Wir haben im Artikel Node-RED zur Verarbeitung der TTN Daten unsere Node-RED Umgebung eingerichtet, jetzt werden wir die ersten Schritte gehen um aus dem The Things Network (TTN) die ersten Daten abzuholen.
Grundlegende Funktionsweise
Node-RED arbeitet mit grafischen Ablaufplänen den sogenannten Flows. In diesen Flows werden diverse Nodes eingesetzt die unterschiedliche Funktionen beinhalten. Im folgenden werde ich die verwendeten Nodes vorstellen.
Die verwendeten Nodes in Node-RED

Der TTN Node



Der Node “Nucleon Wetter” ist unsere Verbindung zum TTN, dort wird der Name und die App definiert. Klickt man in den Einstellungen aus den Stift neben App erreicht man die Einstellungen der App. Dort muss die in der TTN Console vergebene App ID hinterlegt werden und der in der TTN Application zu entnehmenden Access Key. Die Discovery adress ist schon vorgegeben und passt auch für TTN. (discovery.thethingsnetwork.org:1900)
Damit ist dieser Node schon konfiguriert und man kann mit einem “Debug Node” prüfen ob die Einstellungen passen.
Der Debug Node

Den grünen Debug Node kann man umstellen so das man entweder nur den msg.payload oder das komplette msg Objekt angezeigt haben möchte. Hier ist das komplette Objekt angegeben und die Ausgabe erfolgt im Debug Fenster von Node-RED

Nach dem wir den Flow mit Deploy aktiviert haben warten wir auf die nächste Datenlieferung der Applikation um uns das msg Objekt anzusehen.
Unter dem TTN Node sollte nun ein connected erscheinen.

Die Übertragung der Daten hat also funktioniert, da wir eine Applikation Nutzen die mehrere Devices beheimatet die oben drein auch noch unterschiedliche Sensoren für das Thema Wetter verwenden können werden die Datenlieferungen auf die Ports der Übertragung aufgeteilt. Eine Übersicht der möglichen Ports und deren verwendeter Sensoren findet ihr im Gitlab zu unseren Nucleon Nodes.
Dieser hier eingefangene Nucleon BaseNode liefert auf Port 1 seine Daten und hat damit einen BME280 Sensor zur Erfassung der Daten eingebaut.
Der Switch Node

Damit wir die unterschiedlichen Rückgaben der Wetter Nodes getrennt bearbeiten können setzen wir einen “Switch Node” ein den wir so bearbeiten das dieser Node bei unterschiedlichen Ports auch unterschiedliche Ausgänge nutzt.

In den Einstellungen des Switch können wir definieren worauf die Verzweigung reagieren soll.

Wir legen den Namen des Nodes fest, hier “Portverzweigung” . Das auszuwertende Datum ist msg.payload.port, vergleiche dazu weiter oben den Ausdruck im Debug Fenster des Debug Node.
Wenn nun der Port = 1 ist wird auch der erste Ausgang genutzt, bei 2 der zweite und si fort. Der letzte Eintrag fängt als Lumpensammler alle anderen Werte ein. mit dem kleinen [+add] kann man weitere Ausgänge erstellen um mehr Ports zu verzweigen.
Der Funktion Node
Nun haben wir die unterschiedlichen Datenströme getrennt und können für jeden Zweig eine Verarbeitung der Daten bauen. In unserem Flow erhält nun jeder Port/Sensor Typ einen eigenen “Funktion Node”. Dadurch und mit der entsprechenden Programmierung ist es nun auch möglich das ein Nucleon BaseNode mehrere unterschiedliche Sensoren bedienen kann, wie diese dann hier im Flow dann entsprechend zerlegen und aufbereiten können.

Ein doppelklick auf den Node öffnet wieder das Config Fenster des Nodes.

Wir geben dem Node einen Namen, hier ist es “BME280 JSON” damit wir später noch wissen um was es sich bei dieser Funktion handelt.
Im Funktion Feld setzen schreiben wie den folgenden Code:
var msg1 = {};
msg1.payload = [
{batt : msg.payload_fields.batt,
pressure : msg.payload_fields.pressure,
temperature : msg.payload_fields.temperature,
humidity : msg.payload_fields.humidity,
geolat : msg.metadata.gateways[0].latitude,
geolon : msg.metadata.gateways[0].longitude,
geoalt : msg.metadata.gateways[0].altitude,
port : msg.payload_fields.port,
trigger : msg.payload_fields.trigger,
name : msg.dev_id
},
{app_id : msg.app_id,
dev_id : msg.dev_id,
hardware_serial : msg.hardware_serial}
];
if (msg.metadata.latitude === undefined) {
msg1.payload[0].geolat = msg.metadata.gateways[0].latitude
} else {
msg1.payload[0].geolat = msg.metadata.latitude
}
if (msg.metadata.longitude === undefined) {
msg1.payload[0].geolon = msg.metadata.gateways[0].longitude
} else {
msg1.payload[0].geolon = msg.metadata.longitude
}
if (msg.metadata.altitude === undefined) {
msg1.payload[0].geoalt = msg.metadata.gateways[0].altitude
} else {
msg1.payload[0].geoalt = msg.metadata.altitude
}
if (msg.payload_fields.trigger === undefined) {
if (msg1.payload[0].batt <= 3.1) {
msg1.payload[0].trigger = true
} else {
msg1.payload[0].trigger = false
}
}
if (msg.payload_fields.trigger_val === undefined) {
if (msg1.payload[0].trigger === false) {
msg1.payload[0].trigger_val = 0
} else {
msg1.payload[0].trigger_val = 1
}
}
return (msg1);
Wir definieren hier am Anfang erst einmal ein neue Variable var msg1 = {};
Diese bauen wir nun als Array auf msg1.payload = []; welches zwei Objekte beinhaltet die jeweils mit geschweiften Klammern begrenzt werden {}
msg1.payload = [{},{}];
Das erste Objekt beinhaltet die Wirk Daten , das zweite Objekt bekommt die Meta Daten des Sensors um diese später in der InfluxDB als Keys auszuwählen.
Wir können im oben abgebildeten Code erkennen das die Wirkdaten nicht alle aus dem Payload des Nodes kommen, sondern auch aus seinen Metadaten wie zum Beispiel die Geo Position des Node. Hier haben wir die Möglichkeit diese Daten entweder vom Node, der ann GPS benötigt, oder aus dem in der Übertragung beteiligten Gateways stammen kann. Das ist hier Zur Zeit noch nicht vollständig umgesetzt aber wird in einer der kommenden Versionen verwirklicht.
Das Zweite Objekt das die Meta Daten des späteren Datensatzes liefert sind die Felder app_id, dev_id und hardware_serial, welche genau einen Node repräsentieren. Diese 3 Felder bilden in der InfluxDB später den Schlüssel um die Daten eines bestimmten Messpunktes zu identifizieren.
Die beiden anderen Funktion Nodes haben entspechenden Inhalt, den ich im folgenden nur als Code hier angebe. Sie unterscheiden sich nur in den Wirk Daten die der Node übermittelt.
# Inhalt des BMP180 Function Node der nur Temperatur und Luftdruck sendet
var msg1 = {};
msg1.payload = [
{batt : msg.payload_fields.batt,
pressure : msg.payload_fields.pressure,
temperature : msg.payload_fields.temperature,
geolat : msg.metadata.gateways[0].latitude,
geolon : msg.metadata.gateways[0].longitude,
geoalt : msg.metadata.gateways[0].altitude,
port : msg.payload_fields.port,
trigger : msg.payload_fields.trigger,
name : msg.dev_id
},
{app_id : msg.app_id,
dev_id : msg.dev_id,
hardware_serial : msg.hardware_serial}
];
if (msg.metadata.latitude === undefined) {
msg1.payload[0].geolat = msg.metadata.gateways[0].latitude
} else {
msg1.payload[0].geolat = msg.metadata.latitude
}
if (msg.metadata.longitude === undefined) {
msg1.payload[0].geolon = msg.metadata.gateways[0].longitude
} else {
msg1.payload[0].geolon = msg.metadata.longitude
}
if (msg.metadata.altitude === undefined) {
msg1.payload[0].geoalt = msg.metadata.gateways[0].altitude
} else {
msg1.payload[0].geoalt = msg.metadata.altitude
}
if (msg.payload_fields.trigger === undefined) {
if (msg1.payload[0].batt <= 3.1) {
msg1.payload[0].trigger = true
} else {
msg1.payload[0].trigger = false
}
}
if (msg.payload_fields.trigger_val === undefined) {
if (msg1.payload[0].trigger === false) {
msg1.payload[0].trigger_val = 0
} else {
msg1.payload[0].trigger_val = 1
}
}
return (msg1);
# Der Batterie Node der nur seine eigene Spannung sendet
var msg1 = {};
msg1.payload = [
{batt : msg.payload_fields.batt,
trigger : msg.payload_fields.trigger,
name : msg.dev_id
},
{app_id : msg.app_id,
dev_id : msg.dev_id,
hardware_serial : msg.hardware_serial}
];
if (msg.payload_fields.trigger === undefined) {
if (msg1.payload[0].batt <= 3.1) {
msg1.payload[0].trigger = true
} else {
msg1.payload[0].trigger = false
}
}
if (msg.payload_fields.trigger_val === undefined) {
if (msg1.payload[0].trigger === false) {
msg1.payload[0].trigger_val = 0
} else {
msg1.payload[0].trigger_val = 1
}
}
return (msg1);
Der InfluxDB Node
Jetzt haben wir die empfangenen Daten so aufbereitet das wir sie in die InfluxDB versenden können. Der Payload ist so aufbereitet das die Felder mit den Wetterdaten und die Felder welche als Key genutzt werden sollten in zwei Objekten übergeben werden.


Die Einstellungen bestehen aus der Auswahl des InfluxDB Servers, dem benennen des Measurement und dem Node Namen.

Hier wird im Server Dialog die URL des Host und der Port eingerichtet, die entsprechende Datenbank gewählt, Username und Passwort eingetragen. Der Server bekommt noch einen eindeutigen Namen und schon ist alles eingerichtet.
Die Influx Datenbank muss zuvor noch definiert werden, das erledigt man auf der Console des Servers mit dem Komandozeilen Clienen:
influx -username '<user>' -password '<pass>
Connected to http://localhost:8086 version 1.7.4
InfluxDB shell version: 1.7.4
Enter an InfluxQL query
>
Hier im Clienten legen wir die Datenbank an:
CREATE DATABASE wetter
Und wir vergeben die Berechtigungen für unsere beiden Benutzer ttn zum schreiben und ttgraf zum lesen der Daten in der neuen Datenbank.
GRANT WRITE ON wetter to ttn
GRANT READ ON wetter to ttngraf
damit ist die InfluxDB für die Wetterdaten erstellt und kann von uns beschrieben werden.
Nun verbinden wie die Nodes noch mit den Routen und drücken die Deploy Taste um den neuen Flow in betrieb zu nehmen.

Das soll dann für heute auch reichen, im nächsten Node-RED Beitrag werden wie diesen Flow noch um die Erfassung von Node Meta Daten erweitern so das wir auch sehen können über welchen Kanal und mit welchem Spread Faktor die Daten übertragen worden sind.
Ich hoffe das es verständlich ist und ihr diese Funktion dann auch für eure Produkte einsetzen könnt.
Scheint ja sehr einfach zu sein – auch für Senioren geeigent ?
Frage bitte, habe noch einen Arduino UNO und Rasperry Pi Zero
WV 1.1 rumliegen , geht damit auch etwas und brauche ich weitere Anschlüsse/Teile ?
Andere preiswerte Empfehlungen ?
Herzlichen Dank im Voraus und schöne Grüße a. d. Westerwald
wowo