Skip to content

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:

EvrlastUplinkDecoder.js

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:

  1. Ö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 Version Payload Codec)
  2. Wählen Sie als Formatter-Typ Custom Javascript formatter (TTN) bzw. Custom JavaScript codec functions (ChirpStack).
  3. Fügen Sie den Inhalt von EvrlastUplinkDecoder.js vollständig in das Codefeld ein.
  4. 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