TheThingsNetwork Gateway Status und Node-Red Worldmap

Node-Red entwickelt sich immer mehr zu einem meiner Lieblingstools. Die Umwandlung und Restrukturierung  von Daten gestaltet sich damit so einfach, dass man viele Herausforderungen mit nur wenigen „Programmier“-schritten lösen kann.

Nachdem ich vor ein paar Tagen zum ersten Mal die Worldmap in Node-Red ausprobiert habe, entstanden darüber einige Ideen, die ich verwirklichen möchte.

Inspiriert von Bjoerns Techblog und Refues Traffic Dashboard wollte ich den Status der TTN Gateways unserer Community in Node-Reds Worldmap darstellen.

Bjoern stellt die API zur Abfrage des Gateway Status in seinem Blog ausführlich vor, darauf kann ich an dieser Stelle verzichten. Zur Abfrage der API nutze ich den http request Node. Für die Abfrage der Community Gateways verwende ich die selben GPS Koordinaten und den Radius, wie auf der Community Seite definiert.

Screenshot_20190210_154725

Die vollständige url lautet damit: https://www.thethingsnetwork.org/gateway-data/location?latitude=50.962010&longitude=6.970313&distance=16200

Im http request Node kann man bereits die Ausgabe als „json formatted“ auswählen.
In nachfolgenden function Node wird die Ausgabe so umgeformt, dass für jedes Gateway der Liste sein online Status als Farbe und natürlich seine Geoposition auf der Karte abgebildet wird. Als Trigger für die Abfrage dient die Worldmap selber. Beim Laden oder Refresh der Seite wird der http request Node neu getriggert. Ein Gateway wird grün dargestellt, wenn es in den letzten 15 Minuten „gesehen“ (last_seen) wurde. Wenn es jedoch länger als 15 Minuten nicht gesehen wurde orange und wenn es länger als 60 Minuten stumm war in rot dargestellt. Wenn man ein Gateway auf der Worldmap anklickt, werden weitere Information wie Description und Owner angezeigt.

Der function Node, der den http request triggert ist simple

if (msg.payload.action === "connected") 
return msg;

Ein wenig umfangreicher ist hier der function Node, der die Daten für den worlmap Node aufbereitet

var NumOfGW = Object.keys(msg.payload).length; 
var gwArr=[];
var mapArr=[];
var timeDiff15 = new Date((new Date()) -15*1000*60);
var timeDiff60 = new Date((new Date()) -60*1000*60);
for (var i = 0; i< NumOfGW; i++){
    gwArr.push(Object.keys(msg.payload)[i]); 
}
for (var i = 0; i< NumOfGW; i++){
if (typeof(msg.payload[gwArr[i]].location)!== "undefined"){
    message = {
    lat: msg.payload[gwArr[i]].location.latitude,
    lon: msg.payload[gwArr[i]].location.longitude,
    name: msg.payload[gwArr[i]].id,
    };
    if (new Date(msg.payload[gwArr[i]].last_seen) === "undefined"){
        message.iconColor="green";
    }
    else if (new Date(msg.payload[gwArr[i]].last_seen)<timeDiff60){
        message.iconColor="red";
    }
    else if (new Date(msg.payload[gwArr[i]].last_seen)<timeDiff15){
        message.iconColor="orange";
    }
    else {
        message.iconColor="green";
    }
    message.Description = msg.payload[gwArr[i]].description;
    message.Owner = msg.payload[gwArr[i]].owner;
    message.lastSeen = msg.payload[gwArr[i]].last_seen;
    mapArr.push(message);
   }
}
msg.payload=mapArr;
return msg;

Auch der worldmap Node wird mit den Geodaten der Community konfiguriert. Dadurch wird die Karte im Zentrum von Köln zentriert und mit einem angenehmen Zoomfaktor angezeigt.

Screenshot_20190210_155440

Wer die komplette Funktion auf seinem Node-Red nachbauen möchte muss nur die worldmap Nodes nachinstallieren. Dazu auf die 3 waagerechten Striche oben rechts, dann Manage Palette, install und nach worldmap suchen. Es wird dann node-red-contrib-web-worldmap gefunden, dass muss installiert werden.

Hier zum direkten Einbinden die Node-Red Daten

[{"id":"54aa39db.4c074","type":"worldmap in","z":"142c7153.7b2197","name":"","path":"/worldmap","x":194.88333129882812,"y":258.1000061035156,"wires":[["c8d2dfcd.98075"]]},{"id":"de77cedf.98a7f","type":"http request","z":"142c7153.7b2197","name":"GW Status","method":"GET","ret":"obj","url":"https://www.thethingsnetwork.org/gateway-data/location?latitude=50.962010&amp;amp;amp;amp;amp;longitude=6.970313&amp;amp;amp;amp;amp;distance=16200","tls":"","x":424.949951171875,"y":160.1666259765625,"wires":[["4b276cf0.dc2bf4","633070e6.4339a"]]},{"id":"b9bebb3c.1ba67","type":"inject","z":"142c7153.7b2197","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":183.50003051757812,"y":159.1666259765625,"wires":[["de77cedf.98a7f"]]},{"id":"88ce05cb.6685a8","type":"debug","z":"142c7153.7b2197","name":"","active":true,"console":"false","complete":"false","x":881.9500732421875,"y":223.7332763671875,"wires":[]},{"id":"4b276cf0.dc2bf4","type":"function","z":"142c7153.7b2197","name":"extract Geo&amp;amp;amp;amp;Status","func":"var NumOfGW = Object.keys(msg.payload).length; \nvar gwArr=[];\nvar mapArr=[];\nvar timeDiff15 = new Date((new Date()) -15*1000*60);\nvar timeDiff60 = new Date((new Date()) -60*1000*60);\nfor (var i = 0; i&amp;amp;amp;lt; NumOfGW; i++){\n gwArr.push(Object.keys(msg.payload)[i]); \n}\nfor (var i = 0; i&amp;amp;amp;lt; NumOfGW; i++){\n message = {\n lat: msg.payload[gwArr[i]].location.latitude,\n lon: msg.payload[gwArr[i]].location.longitude,\n name: msg.payload[gwArr[i]].id,\n };\n if (new Date(msg.payload[gwArr[i]].last_seen)=== undefined){\n message.iconColor=\"green\";\n }\n else if (new Date(msg.payload[gwArr[i]].last_seen)&amp;amp;amp;lt;timeDiff60){\n message.iconColor=\"red\";\n }\n else if (new Date(msg.payload[gwArr[i]].last_seen)&amp;amp;amp;lt;timeDiff15){\n message.iconColor=\"orange\";\n }\n else {\n message.iconColor=\"green\";\n }\n message.Description = msg.payload[gwArr[i]].description;\n message.Owner = msg.payload[gwArr[i]].owner;\n message.lastSeen = msg.payload[gwArr[i]].last_seen;\n mapArr.push(message);\n }\nmsg.payload=mapArr;\nreturn msg;\n","outputs":1,"noerr":0,"x":705.9500732421875,"y":142,"wires":[["88ce05cb.6685a8","a02be639.d80688"]]},{"id":"633070e6.4339a","type":"debug","z":"142c7153.7b2197","name":"","active":false,"console":"false","complete":"false","x":644.9500732421875,"y":217.45001220703125,"wires":[]},{"id":"a02be639.d80688","type":"worldmap","z":"142c7153.7b2197","name":"","lat":"50.962010","lon":"6.970313","zoom":"13","layer":"OSM","cluster":"","maxage":"","usermenu":"show","layers":"show","panit":"false","panlock":"false","zoomlock":"false","path":"/worldmap","x":921.5,"y":143.66665649414062,"wires":[]},{"id":"c8d2dfcd.98075","type":"function","z":"142c7153.7b2197","name":"retrigger from map","func":"if (msg.payload.action === \"connected\")\nreturn msg;","outputs":1,"noerr":0,"x":420.9500427246094,"y":258.4833068847656,"wires":[["de77cedf.98a7f"]]}]

Beeindruckend ist auch, wenn man im http request die url für den Abruf aller Gateways in Deutschland nutzt: https://www.thethingsnetwork.org/gateway-data/country/de

Der zweite Screenshot entstand nach der Änderung des Parameters „cluster if zoom level is less than“


Veröffentlicht am 10. Februar 2019, in node-red, TheThingsNetwork, Uncategorized. Setze ein Lesezeichen auf den Permalink. 2 Kommentare.

  1. Hall Reinhard,

    schön gemacht, gefällt mir gut. Musste ich gleich mal testen.
    Leider hat sich dein Code umformatiert und aus < wurde &amp;lt; .

    Grüße,
    Björn

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden /  Ändern )

Google Foto

Du kommentierst mit Deinem Google-Konto. Abmelden /  Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden /  Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden /  Ändern )

Verbinde mit %s

%d Bloggern gefällt das: