Setup decoder for a device

Setup decoder for a device


Obtain the decoder source

Go to https://github.com/decentlab/decentlab-decoders and get the respective JavaScript decoder source.

Modify the source for Helium

Helium expects a function with the following signature:

function Decoder(bytes, port) {
... }

First, we remove the main function and its calls, which are for testing purposes.

function main() {
console.log(decentlab_decoder.decode("02..."));
console.log(decentlab_decoder.decode("02...")); }

main();

At the end, add the following snippet. This function presents the expected signature and return values including the error messages.

function Decoder(bytes, port) {
var errors = []; var data = {}; var res = decentlab_decoder.decode(bytes); if ('error' in res) { errors = [res['error']]; } else { data = res; } return { data: data, warnings: [], errors: errors }; }

For DL-DS18, the final source code would look like below:

/* https://www.decentlab.com/products/temperature-sensor-for-lorawan */

var decentlab_decoder = {
  PROTOCOL_VERSION: 2,
  SENSORS: [
    {length: 1,
     values: [{name: 'temperature',
               displayName: 'Temperature',
               convert: function (x) { return (x[0] - 32768) / 16; },
               unit: '°C'}]},
    {length: 1,
     values: [{name: 'battery_voltage',
               displayName: 'Battery voltage',
               convert: function (x) { return x[0] / 1000; },
               unit: 'V'}]}
  ],

  read_int: function (bytes, pos) {
    return (bytes[pos] << 8) + bytes[pos + 1];
  },

  decode: function (msg) {
    var bytes = msg;
    var i, j;
    if (typeof msg === 'string') {
      bytes = [];
      for (i = 0; i < msg.length; i += 2) {
        bytes.push(parseInt(msg.substring(i, i + 2), 16));
      }
    }

    var version = bytes[0];
    if (version != this.PROTOCOL_VERSION) {
      return {error: "protocol version " + version + " doesn't match v2"};
    }

    var deviceId = this.read_int(bytes, 1);
    var flags = this.read_int(bytes, 3);
    var result = {'protocol_version': version, 'device_id': deviceId};
    // decode payload
    var pos = 5;
    for (i = 0; i < this.SENSORS.length; i++, flags >>= 1) {
      if ((flags & 1) !== 1)
        continue;

      var sensor = this.SENSORS[i];
      var x = [];
      // convert data to 16-bit integer array
      for (j = 0; j < sensor.length; j++) {
        x.push(this.read_int(bytes, pos));
        pos += 2;
      }

      // decode sensor values
      for (j = 0; j < sensor.values.length; j++) {
        var value = sensor.values[j];
        if ('convert' in value) {
          result[value.name] = {displayName: value.displayName,
                                value: value.convert.bind(this)(x)};
          if ('unit' in value)
            result[value.name]['unit'] = value.unit;
        }
      }
    }
    return result;
  }
};

function Decoder(bytes, port) {
var errors = [];
var data = {};
var res = decentlab_decoder.decode(bytes);
if ('error' in res) {
errors = [res['error']];
} else {
data = res;
}
return {
data: data,
warnings: [],
errors: errors
}; }

Set the decoder

Go to Functions, and Add New Function. Give it a name (e.g. DL-DS18) and select Decoder for Function Type and Custom Script for Choose Format.

Delete the existing content of the Enter Custom Script editor, insert the modified script from the previous step, and save it by clicking the Save Function button.

You can check the script using Script Validator with the example payloads ( 02...  from the console.log(decentlab_decoder.decode("02...")); ) from the original decoder code.

Finally apply the decoder function to your device in the Flows.