Dekodierer für LoRa-Geräteprofile

Bei LoRa-Geräteprofilen akzeptiert die Funktion decode die folgenden Parameter:

function decode(bytes, port, date) {
  var decoded = [];
  // Place your code here and push the results to 'decoded'.
  return decoded;
}
bytes

Die Nachricht als Bytearray.

port

Die Portnummer, auf der die Meldung übertragen wird. Dieser kann bei einigen Geräten beispielsweise zur Identifikation des Meldungstyps verwendet werden.

date

Ein Datumsobjekt des Zeitpunkts, an dem die Meldung vom IoT-Gerät versandt wurde. Falls diese Information nicht zur Verfügung steht, wird stattdessen das Empfangsdatum der Meldung übergeben.

Die Funktion decode muss ein Array von Objekten mit dem folgenden Aufbau zurückgeben:

Messwerte

{
  type: 'measurement',
  key: 'data_point_key_xyz',
  datetime: 1539093694, // milliseconds since Jan 1, 1970 or Date.prototype.toISOString()
  value: 23.5
}
type

Muss bei normalen Messwerten auf 'measurement' gesetzt werden.

key

Der Schlüssel des entsprechenden Datenpunkts, wie er oben in der Tabelle Datenpunkte in der Spalte Schlüssel definiert wurde.

../../../_images/edit-iot-profiles-keys.de.png
datetime

Datum und Uhrzeit des Messwertes. Kann beispielsweise auf Date.now() gesetzt oder aus dem Funktionsparameter date abgeleitet werden. Gültige Werte sind entweder die Anzahl Millisekunden seit 1. Januar 1970 (Date.prototype.getTime()) oder eine Zeichenfolge gemäss ISO 8601 (Date.prototype.toISOString()).

value

Der effektiv aufgezeichnete Messwert als Ganzzahl, Fließkommazahl oder Wahrheitswert.

Alarme

{
  type: 'alarm',
  key: 'data_point_key_xyz',
  datetime: 1539093694, // milliseconds since Jan 1, 1970 or Date.prototype.toISOString()
  value: 23.5,
  toState: 'offNormal', // or 'normal' if alarm is gone
  message: 'The alarm message'
}
type

Muss bei Alarmen auf 'alarm' gesetzt werden.

key

Der Schlüssel des entsprechenden Datenpunkts, wie er oben in der Tabelle Datenpunkte in der Spalte Schlüssel definiert wurde.

../../../_images/edit-iot-profiles-keys.de.png
datetime

Datum und Uhrzeit des Alarms. Kann beispielsweise auf Date.now() gesetzt oder aus dem Funktionsparameter date abgeleitet werden. Gültige Werte sind entweder die Anzahl Millisekunden seit 1. Januar 1970 (Date.prototype.getTime()) oder eine Zeichenfolge gemäss ISO 8601 (Date.prototype.toISOString()).

value

Der anstehende Alarmwert.

toState

'offNormal' im Alarmfall oder 'normal' im Fall einer Gutmeldung. Falls der Alarm sich nicht auf den aktuellen Messwert, sondern auf ein anderes Problem bezieht (z. B. dass der Wert nicht richtig ausgelesen werden konnte), können Sie auch den Status 'fault' verwenden.

message

Der Alarmtext, wie er in einem Alarmticket und in eventuellen Benachrichtigungen angezeigt werden soll.

Hilfsfunktionen

In diesem Abschnitt finden Sie einige Hilfsfunktionen, die die Manipulation von Bytearrays und das Erstellen der Ausgabeobjekte vereinfachen können.

Ausgabeobjekt für Messwerte erstellen

// Helper function to generate a measurement object.
function createMeasurement(key, datetime, value) {
  return {
    type: 'measurement',
    key: key,
    datetime: datetime,
    value: value
  };
}

Messwertobjekt erstellen:

decoded.push(createMeasurement('data_point_key_xyz', 1539093694, 24.5));

Ausgabeobjekt für Alarme erstellen

// Helper function to generate an alarm object.
function createAlarm(key, datetime, value, isGone, message) {
  return {
    type: 'alarm',
    key: key,
    datetime: datetime,
    value: value,
    toState: isGone ? 'normal' : 'offNormal',
    message: message
  };
}

Alarmobjekt erstellen:

decoded.push(createAlarm('data_point_key_xyz', 1539093694, 24.5, false, 'Alarm'));

Float32 parsen

// Helper function to generate a float32 from an array of bytes at the given offset.
function getFloat32(bytes, offset, littleEndian) {
  var buffer = new ArrayBuffer(4);
  var view = new DataView(buffer);
  for (var i = 0; i < 4; i++) {
    view.setUint8(i, bytes[offset + i]);
  }
  return Number(view.getFloat32(0, littleEndian));
}

Int16 parsen

// Helper function to generate an int16 from an array of bytes at the given offset.
function getInt16(bytes, offset, littleEndian) {
  var buffer = new ArrayBuffer(2);
  var view = new DataView(buffer);
  for (var i = 0; i < 2; i++) {
    view.setUint8(i, bytes[offset + i]);
  }
  return Number(view.getInt16(0, littleEndian));
}

Uint16 parsen

// Helper function to generate a uint16 from an array of bytes at the given offset.
function getUint16(bytes, offset, littleEndian) {
  var buffer = new ArrayBuffer(2);
  var view = new DataView(buffer);
  for (var i = 0; i < 2; i++) {
    view.setUint8(i, bytes[offset + i]);
    }
  return Number(view.getUint16(0, littleEndian));
}

Uint8 parsen

// Helper function to generate a uint8 from an array of bytes at the given offset.
function getUint8(bytes, offset, littleEndian) {
  var buffer = new ArrayBuffer(1);
  var view = new DataView(buffer);
  view.setUint8(0, bytes[offset]);
  return Number(view.getUint8(0));
}

Einzelnes Bit parsen

// Helper function to extract a single bit from a byte in an array of bytes.
// Bit index 0 is the least significant bit, 7 is the most significant bit.
function getBit(bytes, offset, bitIndex) {
  return (bytes[offset] & (1 << bitIndex)) >> bitIndex;
}

Anzahl Dezimalstellen einer Zahl definieren

// Helper function to set the number of decimals of a number.
function getFixed(number, decimals) {
  return Number(number.toFixed(decimals));
}

Payload testen

Um den Dekodieralgorithmus zu testen, geben Sie im Feld Payload bitte die erwartete Nutzlast im Hexadezimalformat ein (z. B. 007B42F600003039) und klicken Sie anschließend auf die Schaltfläche Test.

Falls keine Fehler aufgetreten sind, erscheint das dekodierte Ausgabeobjekt im Feld Resultat. Im Fehlerfall erscheinen Toast-Benachrichtigungen mit einem kurzen Beschrieb des Problems und allenfalls der fehlerhaften Zeile im Quellcode.

Vollständiges Beispiel

function decode(bytes, port, date) {
  // Decode an uplink message from a buffer (array) of bytes to an object.

  // Helper function to generate a measurement object.
  function createMeasurement(key, datetime, value) {
    return {
      type: 'measurement',
      key: key,
      datetime: datetime,
      value: value
    };
  }

  // Helper function to generate an alarm object.
  function createAlarm(key, datetime, value, isGone, message) {
    return {
      type: 'alarm',
      key: key,
      datetime: datetime,
      value: value,
      toState: isGone ? 'normal' : 'offNormal',
      message: message
    };
  }

  // Helper function to generate a float32 from an array of bytes at the given offset.
  function getFloat32(bytes, offset, littleEndian) {
    var buffer = new ArrayBuffer(4);
    var view = new DataView(buffer);
    for (var i = 0; i < 4; i++) {
      view.setUint8(i, bytes[offset + i]);
    }
    return Number(view.getFloat32(0, littleEndian));
  }

  // Helper function to generate an int16 from an array of bytes at the given offset.
  function getInt16(bytes, offset, littleEndian) {
    var buffer = new ArrayBuffer(2);
    var view = new DataView(buffer);
    for (var i = 0; i < 2; i++) {
      view.setUint8(i, bytes[offset + i]);
    }
    return Number(view.getInt16(0, littleEndian));
  }

  // Helper function to generate a uint16 from an array of bytes at the given offset.
  function getUint16(bytes, offset, littleEndian) {
    var buffer = new ArrayBuffer(2);
    var view = new DataView(buffer);
    for (var i = 0; i < 2; i++) {
      view.setUint8(i, bytes[offset + i]);
    }
    return Number(view.getUint16(0, littleEndian));
  }

  // Helper function to generate a uint8 from an array of bytes at the given offset.
  function getUint8(bytes, offset) {
    var buffer = new ArrayBuffer(1);
    var view = new DataView(buffer);
    view.setUint8(0, bytes[offset]);
    return Number(view.getUint8(0));
  }

  // Helper function to extract a single bit from a byte in an array of bytes.
  // Bit index 0 is the least significant bit, 7 is the most significant bit.
  function getBit(bytes, offset, bitIndex) {
    return (bytes[offset] & (1 << bitIndex)) >> bitIndex;
  }

  // Helper function to set the number of decimals of a number.
  function getFixed(number, decimals) {
    return Number(number.toFixed(decimals));
  }

  var decoded = [];
  var now = Date.now();

  // Add the decoded values to an array.
  // Example:

  // Decode byte 1 (at index 0) as a battery capacity with a value between 0 and 100.
  decoded.push(createMeasurement('battery', now, getFixed(getUint8(bytes, 0) * 100 / 255, 2)));

  // Decode bytes 2 to 3 (starting at index 1) as an unsigned 16-bit integer
  // for the data point with key 'key_1'.
  decoded.push(createMeasurement('key_1', now, getUint16(bytes, 1)));

  // Decode bytes 4 to 7 (starting at index 3) as a 32-bit float
  // for the data point with key 'key_2'.
  decoded.push(createMeasurement('key_2', now, getFloat32(bytes, 3)));

  // Decode bytes 8 to 9 (starting at index 7) as a signed 16-bit integer
  // for the data point with key 'key_3'.
  decoded.push(createMeasurement('key_3', now, getInt16(bytes, 7)));

  // Decode the least significant bit in byte 10 as a binary value (0 or 1).
  // for the data point with key 'key_4'.
  decoded.push(createMeasurement('key_4', now, getBit(bytes, 9, 0)));

  // Decode byte 11 (at index 10) as a binary alarm value (0 or 1)
  // for the data point with key 'key_1' and provide a specific alarm message.
  decoded.push(createAlarm('key_1', now, getBit(bytes, 10, 0), false, 'Add alarm text here'));

  return decoded;
}