Datenformat & Decoder
Datenformat & Decoder¶
Wenn Sie Ihr Evrlast-LoRaWAN-Gerät ohne die Evrlast-Cloud betreiben, empfängt Ihr eigenes LoRaWAN-Netzwerk (LNS) nur die rohen, binär kodierten Nutzdaten (Payload) des Geräts. Damit Sie daraus die eigentlichen Messwerte auslesen können, benötigen Sie einen Decoder (auch Payload Formatter oder Codec genannt), den Sie in Ihrem LNS hinterlegen.
Evrlast stellt dafür einen fertigen JavaScript-Decoder bereit: EvrlastUplinkDecoder.js.
Wird der Decoder benötigt, wenn ich die Evrlast-Cloud nutze?
Nein. Ist Ihr Gerät in der Evrlast-Cloud registriert, übernimmt die Cloud das Dekodieren der Payload automatisch. Der Decoder ist ausschließlich für den Betrieb ohne Evrlast-Cloud relevant.
Decoder herunterladen¶
Sie können den Decoder direkt herunterladen und in Ihr LNS einfügen:
Decoder im LNS hinterlegen¶
Der Decoder ist als Funktion decodeUplink(input) implementiert und folgt damit dem Standard-Interface, das sowohl TTN (The Things Stack) als auch ChirpStack v4 für JavaScript-Payload-Formatter verwenden. Sie können den Code daher unverändert übernehmen:
- Öffnen Sie in Ihrem LNS die Einstellungen der betroffenen Anwendung bzw. des Geräteprofils:
- TTN:
Applications ⇒ Ihre Anwendung ⇒ Payload formatters ⇒ Uplink - ChirpStack:
Applications ⇒ Ihre Anwendung ⇒ Device profiles ⇒ Codec(bzw. je nach VersionPayload Codec)
- TTN:
- Wählen Sie als Formatter-Typ Custom Javascript formatter (TTN) bzw. Custom JavaScript codec functions (ChirpStack).
- Fügen Sie den Inhalt von
EvrlastUplinkDecoder.jsvollständig in das Codefeld ein. - Speichern Sie die Einstellung. Neue Uplinks Ihres Geräts werden ab sofort automatisch dekodiert.
Nutzen Sie eine andere Plattform (z. B. Firefly), übernehmen Sie den Code sinngemäß in die dort vorgesehene Stelle für benutzerdefinierte Payload-Decoder — die Funktionslogik bleibt identisch, lediglich die Einbindung unterscheidet sich je nach Anbieter.
Rückgabeformat¶
Der Decoder liest die binäre Payload aus und gibt für jeden übertragenen Messwert ein Objekt mit folgenden Feldern zurück:
| Feld | Beschreibung |
|---|---|
| identifier | Kennung des Sensortyps (sensorType-ID) — siehe Sensor-Identifier unten. |
| value | Der eigentliche Messwert. |
| port | Nummer des Sensor-Ports, an dem der Messwert erfasst wurde. |
Alle Messwerte eines Uplinks werden gesammelt in data.measurementValues zurückgegeben, zum Beispiel:
{
"data": {
"measurementValues": [
{ "identifier": 1, "value": 1234, "port": 1 },
{ "identifier": 2, "value": 56, "port": 2 }
]
}
}
Sensor-Identifier (sensorType-ID)¶
Jeder Messwert im Feld identifier verweist auf einen festen Sensortyp. Anhand der folgenden Tabelle ordnen Sie die ID dem jeweiligen Sensor zu:
| ID | Sensor | Einheit |
|---|---|---|
| 0 | Temperatur | °C |
| 3 | Batteriespannung | V |
| 4 | Luftfeuchtigkeit | % |
| 5 | Luftdruck | Pa |
| 6 | Platinentemperatur (Gerätetemperatur) | °C |
| 7 | Solarspannung | V |
| 10 | Schallpegel | dB |
| 11 | Bodenfeuchtigkeit | % |
| 17 | Externe Temperatur | °C |
| 18 | pH-Wert | pH |
| 23 | Schalter | On/Off |
| 25 | Feinstaub PM100 | µg/m³ |
| 26 | Feinstaub PM10 | µg/m³ |
| 27 | Feinstaub PM2,5 | µg/m³ |
| 30 | Flexibler Sensor (generisch, mehrere Ports) | – |
| 32 | Ladezustand | – |
| 35 | Temperatur 2 (zweiter Temperatursensor) | °C |
| 36 | Luftdruck 2 (zweiter Drucksensor) | Pa |
| 38 | Betriebsstatus (Power Good) | – |
| 39 | Ozon (O₃) | ppm |
| 40 | Abstand (Radar) | mm |
| 41 | Stickstoffdioxid (NO₂) | ppm |
| 42 | Kohlenmonoxid (CO) | ppm |
| 43 | Sauerstoff (O₂) | %VOL |
| 44 | Ammoniak (NH₃) | ppm |
| 45 | Schwefelwasserstoff (H₂S) | ppm |
| 46 | Chlorwasserstoff (HCl) | ppm |
| 47 | Wasserstoff (H₂) | ppm |
| 48 | Phosphin (PH₃) | ppm |
| 49 | Schwefeldioxid (SO₂) | ppm |
| 50 | Chlor (Cl₂) | ppm |
| 51 | Fluorwasserstoff (HF) | ppm |
Quellcode¶
function decodeUplink(input) {
var data = input.bytes;
var pos = 0;
function readVarint() {
var result = 0, shift = 0;
while (pos < data.length) {
var byte = data[pos++];
result |= (byte & 0x7F) << shift;
if ((byte & 0x80) === 0) break;
shift += 7;
}
return result;
}
function readBytes() {
var len = readVarint();
var bytes = data.slice(pos, pos + len);
pos += len;
return bytes;
}
var msgBytes = readBytes();
var msgPos = 0;
function msgReadVarint() {
var result = 0, shift = 0;
while (msgPos < msgBytes.length) {
var byte = msgBytes[msgPos++];
result |= (byte & 0x7F) << shift;
if ((byte & 0x80) === 0) break;
shift += 7;
}
return result;
}
function msgReadBytes() {
var len = msgReadVarint();
var bytes = msgBytes.slice(msgPos, msgPos + len);
msgPos += len;
return bytes;
}
var sensors = [];
while (msgPos < msgBytes.length) {
var tag = msgReadVarint();
var fieldNum = tag >> 3, wireType = tag & 7;
if (fieldNum === 1 && wireType === 2) {
var valueBytes = msgReadBytes();
var vPos = 0;
function vReadVarint() {
var result = 0, shift = 0;
while (vPos < valueBytes.length) {
var byte = valueBytes[vPos++];
result |= (byte & 0x7F) << shift;
if ((byte & 0x80) === 0) break;
shift += 7;
}
return result;
}
var value = {};
while (vPos < valueBytes.length) {
var vTag = vReadVarint();
var vFieldNum = vTag >> 3;
if (vFieldNum === 1) value.identifier = vReadVarint();
else if (vFieldNum === 2) value.value = vReadVarint();
else if (vFieldNum === 3) value.port = vReadVarint();
}
sensors.push(value);
}
}
return {
data: {
measurementValues: sensors
}
};
}
Siehe auch¶
- Config Generator — zum Einstellen der Geräteparameter
- Web Flasher — zum Auslesen der Firmware-Version Ihres Geräts