Events

:

:

Elektronik | Funk | Software

Der Technik-Blog

  • Social Media

    YouTube

    Werbung:


    Neue Artikel


    Events

    • Keine zukünftigen Events vorhanden

    Der Technik-Blog

    LoRaWAN Javascript Payload Decoder Beispiel programmieren

    LoRaWAN Payload Decoder schreiben

    Alex @ AEQ-WEB

    In der Regel gibt es für LoRaWAN-Sensoren direkt vom Hersteller einen fertigen Javascript-Decoder für die Einbindung bei TTN (The Things Network, The Things Stack), Helium oder einem anderen LoRaWAN-Netzwerk. In seltenen Fällen oder insbesondere bei Sensoren für den Business-Bereich (Wasserzähler, Gaszähler, Energiezähler usw.) gibt der Hersteller meistens keinen fertigen Decoder heraus, sondern eine Dokumentation über die Byteaufteilung der Payload. In diesem Artikel geht es um einen Wasserzähler (Qualcosonic W1 von AXIOMA), wo anhand der Byte-Tabelle ein Javascript Decoder für TTN erstellt wird.

    Aufgabe des Decoders

    LoRaWAN ist eine sehr sparsame Funktechnologie, wo nicht nur auf den Energieverbrauch geachtet wird, sondern auch auf eine möglichst effiziente und kurze Datenübertragungszeit. Übliche Übertragungsformate wie JSON oder Klartext sind deshalb keine Option. Die von einem Sensor erfassten Messdaten werden lokal in eine sehr sparsame Payload encodiert, wo nur so viele Bit und Bytes per Funk übertragen werden, wie unbedingt notwendig. Der serverseitige Payload Decoder wandelt diese Daten zurück und vergibt einen entsprechenden Parametername für die einzelnen Werte, welche wiederum meistens im JSON-Format an eine Applikation weitergegeben werden.

    Das Beispielprojekt

    Als Beispiel für dieses Projekt kommt ein Wasserzähler (Qualcosonic W1 von AXIOMA) zum Einsatz. Dieser wurde zuvor bereits bei TTN registriert und sendet nun alle 24 Stunden den aktuellen Zählerstand mit Zeitstempel sowie einen Statuscode bzw. Fehlercode mit. Vom Hersteller wird anstelle eines fertigen Decoders eine Tabelle geliefert, wo ersichtlich ist, welche Bytes zu einem bestimmten Messwert gehören. Anhand dieser Tabelle wird nun ein entsprechender Decoder erstellt. Die Wertetabelle des Herstellers aus dem Datenblatt sieht wie folgt aus:

    Order Number of bytes Description
    1 4 Current date and time
    2 1 Status code
    3 4 Current volume
    4 4 Log date and time
    5 4 Volume at log date and time


    Werbung:

    Einteilung der Bytes

    Zuerst werden die einzelnen Bytes in die jeweiligen Bereiche eingeteilt. Als Beispiel wird eine Payload vom 20.10.2022 um 7:02:19 (UTC) mit einem aktuellen Zählerstand von 83,902 m3 und den Fehlercode "0" (Kein Fehler) verwendet. Die Hexadezimale Payload für diese Werte sieht wie folgt aus:

    MSB, LSB & Wertberechung

    Eine weitere wichtige Information vom Hersteller ist die Bitwertigkeit. Dabei gibt es MSB (Most Significant Bit) und LSB (Least Significant Bit). Eine bevorzugte Bitwertigkeit gibt es nicht, jedoch muss der Decoder entsprechend auf die Herstellervorgabe programmiert werden, um daraus plausible Werte zu erhalten. In der folgenden Grafik wird der aktuelle Zählerstand (Byte 5-8) aus der Payload genommen und als LSB/MSB dargestellt.

    Wie in der oberen Grafik erkennbar ist, werden zwischen LSB und MSB einfach die Bytes gespiegelt. Das erste Byte (BE) bei LSB ist nun das letzte Byte bei MSB, während das letzte Byte von LSB (00) nun an erster Stelle bei MSB steht. Der Hersteller hat sich bei diesem Sensor auf eine Codierung in MSB festgelegt. Hexadezimal ist übersichtlicher als Binär, jedoch wird für das bessere Verständnis dieser Vorgehensweise die Hexadezimale MSB Payload in eine Binärzahl umgerechnet:

    Werden die vier Bytes vom aktuellen Zählerstand von hexadezimal in binär umgerechnet und aneinandergereiht, so entsteht eine 32-Bit Binärzahl. Wird diese nun in eine Dezimalzahl umgerechnet, so erhält man den aktuellen Zählerstand in Liter. Wird dieser durch 1000 dividiert, so erhält man den aktuellen Zählerstand in Kubikmeter.

    Werbung:

    Payload Decoder programmieren

    Der Payload-Decoder wird in Javascript programmiert. Dabei handelt es sich um eine Funktion, die standardmäßig nach dem Datenempfang auf dem LoRaWAN-Server ausgeführt wird. Übergeben werden dieser Funktion die Bytes der Payload und ein Port.

    Die Variable "vol" besteht nun aus Byte 8-5. In diesem Fall handelt es sich um ein Bit-Shifting nach MSB, weshalb mit Byte[8] (Blau) begonnen wird und dieses um 24 Stellen nach links verschoben wird. Anschließend kommt Byte[7] (Grün) dazu und wird um 16 Stellen nach links geschoben. Byte[6] (Gelb) wird um 8 Stellen nach links geschoben und Byte[5] (Orange) füllt nun die letzten 8 Stellen. Daraus ergibt sich ein 32-Bit Zahlenwert (Integer bzw. Long) der über "return" als "VolumeTotal" zurückgeben wird. Eine Division durch 1000 wandelt Liter in Kubikmeter um. Der Decoder für den aktuellen Zählerstand sieht nun wie folgt aus:

    //More information at https://www.aeq-web
    function Decoder(bytes, port) {
    
      var vol = bytes[8] << 24 | bytes[7] << 16 | bytes[6] << 8 | bytes[5];
    
    		return {
    			VolumeTotal: vol / 1000 //Volume in m³
    		}
    }
    

    Unix-Time in Datum & Uhrzeit umwandeln

    Der Wasserzähler sendet neben den Zählerstand auch seinen aktuellen Zeitstempel (Byte 0-3) mit. Es handelt sich dabei um einen Unix-Timestamp, der ebenfalls aus einem 32-Bit Zahlenwert besteht. Das Bit-Shifting funktioniert daher exakt gleich wie beim Zählerstand, nur das dafür die ersten vier Bytes der Payload anstelle Byte 5-8 verwendet werden müssen. Unixzeit zählt die vergangenen Sekunden seit 01.01.1970 00:00 in UTC. Anhand der vergangenen Sekunden seit diesem Zeitstempel kann nun eine sekundengenaue Uhrzeit berechnet werden. Eine Funktion zur Umrechnung gibt es praktisch bei allen Programmiersprachen, so auch bei Javascript. Folgende Funktion gibt aus Unixzeit "1666249339" den Datum-Zeitstempel "20.10.2022 07:02:19" zurück:

    //More information at https://www.aeq-web.com
    function Decoder(bytes, port) {
    
    		var systime = bytes[3] << 24 | bytes[2] << 16 | bytes[1] << 8 | bytes[0];
    		var systemtime = unixToDateTime(systime);
    
    		return {
    			DateTime: systemtime
    		}
    
    	function unixToDateTime(unixtime) {
    		var date = new Date(unixtime * 1000);
    		var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
    		var hours = date.getHours();
    		var minutes = "0" + date.getMinutes();
    		var seconds = "0" + date.getSeconds();
    		var year = date.getFullYear();
    		var month = months[date.getMonth()];
    		var day = date.getDate();
    		var DateTime = day + '-' + month + '-' + year + ' ' + hours + ':' + minutes.substr(-2) + ':' + seconds.substr(-2);
    		return DateTime;
    	}
    }
    

    Fehlercode

    Neben Verbrauchswerten und Zeitstempeln wird auch ein Fehlercode übertragen. Dieser besteht lediglich aus einem Byte und ist daher sehr einfach zu Decodieren:

    Werbung:

    //More information at https://www.aeq-web
    function Decoder(bytes, port) {
      
    		var sta = bytes[4];
    
    		return {
    			Status: sta
    		}
    }
    

    Der vollständige Code

    Der vollständige Code für den Qualcosonic W1 Payload-Decoder sieht nun wie folgt aus:

    //More information at https://www.aeq-web.com
    function Decoder(bytes, port) {
    
    	if (port == 100) {
    		var systime = bytes[3] << 24 | bytes[2] << 16 | bytes[1] << 8 | bytes[0];
    		var sta = bytes[4];
    		var vol = bytes[8] << 24 | bytes[7] << 16 | bytes[6] << 8 | bytes[5];
    
    		var systemtime = unixToDateTime(systime);
    
    		return {
    			DateTime: systemtime,
    			VolumeTotal: vol / 1000, //Volume in m³
    			Status: sta
    		}
    	}
    
    	function unixToDateTime(unixtime) {
    		var date = new Date(unixtime * 1000);
    		var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
    		var hours = date.getHours();
    		var minutes = "0" + date.getMinutes();
    		var seconds = "0" + date.getSeconds();
    		var year = date.getFullYear();
    		var month = months[date.getMonth()];
    		var day = date.getDate();
    		var DateTime = day + '-' + month + '-' + year + ' ' + hours + ':' + minutes.substr(-2) + ':' + seconds.substr(-2);
    		return DateTime;
    	}
    }
    


    122X122

    Über den Autor

    Alex, der Gründer von AEQ-WEB. Seit über 10 Jahren beschäftigt er sich mit Computern und elektronischen Bauteilen aller Art. Neben den Hardware-Projekten entwickelt er auch Webseiten, Apps und Software für Computer.

    Top Artikel in dieser Kategorie:

    LHT65 Sensor TTN HTTP Integration

    Vom TTN zur eigenen Webseite

    • Video
    • DE/EN

    In diesem Artikel geht es um die Weiterleitung empfangener LoRaWAN Datenpakete von TTN an die eigene Webseite über HTTP

    Weiterlesen
    Heltec LoRa32 LoRaWAN Tutorial

    LoRaWAN mit dem Heltec LoRa32 V3

    • Video

    Einstieg in das LoRaWAN (TTN) mit dem Heltec LoRa32 V3 und Einrichtung vom Board in der Arduino IDE

    Weiterlesen

    Social Media

    YouTube

    Werbung:


    Neue Artikel


    Events

    • Keine zukünftigen Events vorhanden