IoT-Profile verwalten

Um IoT-Profile zu verwalten, wechseln Sie zunächst zur Geräteverwaltung, indem Sie im Benutzermenü oben rechts auf Geräte klicken. Wechseln Sie anschließend auf die Registerkarte IoT-Profile.

In der Seitenleiste links werden nun alle IoT-Profile aufgelistet, die Sie bereits eingerichtet haben. Um ein neues Profil zu erstellen, klicken Sie oberhalb dieser Seitenleiste auf Profil hinzufügen.

In der Hauptansicht können Sie nun das IoT-Profil konfigurieren.

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

Ein IoT-Profil besteht aus einer Liste von Datenpunktdefinitionen sowie einem Dekodieralgorithmus, der die Daten vom Gerät auf diese Datenpunkte aufschlüsselt.

Bemerkung

Wenn Sie ein IoT-Profil erstellen oder bearbeiten, hat dies zunächst keine Auswirkung auf existierende Geräte. Erst wenn Sie das Profil auf ein Gerät anwenden (siehe IoT-Profile anwenden), werden die Datenpunkte auf dem Gerät angelegt und der Dekodierer registriert.

Profilname

Geben Sie dem IoT-Profil einen aussagekräftigen Namen, beispielsweise den Modellnamen des IoT-Geräts oder dessen Anwendungszweck.

Gerätetyp

Wählen Sie hier den Typ des IoT-Geräts aus, für den dieses Profil bestimmt ist.

Datenpunkte

In dieser Tabelle können Sie die Datenpunkte konfigurieren, die automatisch angelegt werden sollen, wenn das IoT-Profil einem Gerät zugewiesen wird.

Schlüssel

Ein Schlüssel, der in der gesamten Tabelle eindeutig ist, und mit dem der entsprechende Datenpunkt im Dekodierer identifiziert werden kann. Der Schlüssel kann sehr kurz sein, solange er eindeutig ist und den Datenpunkt verständlich identifiziert, beispielsweise “temperatur” oder “zaehler01”.

Bemerkung

Um einen Batterie-Watchdog auf dem Gerät einrichten zu können, der bei niedrigem Batteriestand alarmiert, müssen Sie einen der Datenpunkte mit dem Schlüssel battery kennzeichnen. Dieser Datenpunkt darf nur Werte von 0 bis 100 annehmen. Vergessen Sie nicht, den aktuellen Batteriestand in Ihrem Dekodierer auszulesen und diesem Datenpunkt zuzuweisen. Nachdem Sie das Profil einem Gerät zugewiesen haben, können Sie den Batteriealarm auf der Konfigurationsseite des betreffenden Geräts im Abschnitt Alarmierung einstellen.

Bemerkung

ThermoValve-Geräten kann ein Temperatur­­sensor (z. B. ein Wisely oder ein Mein LoRa-Gerät) zugewiesen werden, der die Raumtemperatur für den Thermostat zur Verfügung stellt. Wenn Sie ein IoT-Profil für ein eigenes LoRa-Gerät erstellen, welches Sie zusammen mit einem ThermoValve-Gerät verwenden möchten, muss der Schlüssel des Temperatur­­datenpunkts im Profil auf temperature gesetzt werden.

Name

Der Name des Datenpunkts, wie er später in der Datenpunktliste, auf Diagrammen oder Anlagebildern angezeigt werden soll.

Systemname

Der Systemname des Datenpunkts, der ihn im System eindeutig identifiziert.

Um sicherzustellen, dass Datenpunkte einen eindeutigen Systemnamen erhalten, selbst wenn Sie das IoT-Profil auf mehrere Geräte anwenden, können Sie einen der folgenden Platzhalter verwenden:

  • %DEVID% wird automatisch mit der Geräte­­identifikation (in der Regel die EUI des Geräts) ersetzt.

  • %DEVNAME% wird automatisch mit dem Gerätenamen ersetzt. Da der Gerätename lokalisierbar ist, der Systemname hingegen nicht, wird das System den Gerätenamen in der Sprache des Benutzers verwenden, der das IoT-Profil dem Datenpunkt zuweist.

Beschreibung

Eine zusätzliche Beschreibung des Datenpunkts, beispielsweise dessen Verwendungszeck oder genaue Standort- oder Bauteil­­bezeichnung.

Typ

Der Datentyp des Datenpunkts.

Einheit

Die Einheit, in der die Messwert­­aufzeichnung auf diesem Datenpunkt erfolgt.

Auf der öffentlichen Web-App verfügbar machen

Wenn diese Option aktiviert ist, wird der Datenpunkt in der öffentlichen Web-App angezeigt, die durch Scannen des QR-Codes auf dem entsprechenden Gerät geöffnet werden kann. Beachten Sie, dass der Datenpunkt und dessen letzte Messwerte in der öffentlichen Web-App ohne Login zugänglich sind. Durch Deaktivieren der Option sind der Datenpunkt und seine Messwerte nur noch auf der normalen Avelon-Benutzeroberfläche über ein gültiges Login zugänglich.

Dekodierer

In diesem Eingabefeld definieren Sie den Dekodieralgorithmus, mit dem der Datenstrom des IoT-Geräts in die Messwerte oder Alarme der einzelnen Datenpunkte umgewandelt wird.

Der Algorithmus muss als JavaScript-Funktion decode geschrieben werden, die die folgenden Parameter entgegennimmt:

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

Der Datenstrom als Bytearray.

port

Die Portnummer, auf der der Datenstrom ü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.

Grundsätzlich muss die Funktion decode ein Array mit Objekten der folgenden Form 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 der Dezimalstellen einer Zahl festlegen

// 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;
}