cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
Showing results for 
Search instead for 
Did you mean: 

Community Tip - You can subscribe to a forum, label or individual post and receive email notifications when someone posts a new topic or reply. Learn more! X

Adeunis devices (LoRAWAN / SIGFOX) payload Decoding

No ratings

This small tutorial enables you to manage payload decoding for Adeunis Devices within ThingWorx Composer in less than 10 minutes. 

Adeunis Devices communicates on LPWAN networks (LoRaWAN / Sigfox) covering sectors such as smart building, smart industry and smart city.

The encoding is also possible but it will be covered in another article.

 

1. Get Adeunis Codec

Adeunis is providing a codec enabling payload encoding and decoding. 

Download here the resource file containing the codec. 

Unzip the file and edit "script.txt" with your favorite text editor.

Copy all text contained in the file.

 

2.  Create AdeunisCodec Thing

Create a Thing called "AdeunisCodec" based on the GenericThing Template.

 

3. Create a service called "Decode"

Create a Decode Service with the following setup:

  • Inputs: type (String), payload (String)
  • Output as JSON

Past the previously copied "script.txt" content

Save

 

4. Correct a couple of Warnings

Remove all "var codec;" occurences except first one at line 1191. 

Remove semi columns at lines 985,1088, 1096 and 1172

 

5. Remove the following section

The codec relies on implementing functions on JavaScript prototypes which is not supported by ThingWorx Rhino JavaScript Engine. See the following documentation section, here

 

Remove from line 1109 to 1157.

 

The following classes overrides will be removed:

  • Uint8Array.prototype.readUInt16BE
  • Uint8Array.prototype.readInt16BE
  • Uint8Array.prototype.readUInt8
  • Uint8Array.prototype.readUInt32BE
  • Uint8Array.prototype.writeUInt16BE
  • Uint8Array.prototype.writeUInt8
  • Uint8Array.prototype.writeUInt32BE

6. Add new implementations of the removed functions

The functions are adapted from a JavaScript framework which contains resources that helps dealing with binary data, here.

Insert the  following section at the top of the "Decode" script.    

 

 

function readInt16BE (payload,offset) {
  checkOffset(offset, 2, payload.length);
  var val = payload[offset + 1] | (payload[offset] << 8);
  return (val & 0x8000) ? val | 0xFFFF0000 : val;
}

function readUInt32BE (payload,offset) {
  checkOffset(offset, 4, payload.length);
  return (payload[offset] * 0x1000000) +
      ((payload[offset + 1] << 16) |
      (payload[offset + 2] <<  |
      payload[offset + 3]);
}

function readUInt16BE (payload,offset) {
  checkOffset(offset, 2, payload.length);
  return (payload[offset] <<  | payload[offset + 1];
}

function readUInt8 (payload,offset) {
  checkOffset(offset, 1, payload.length);
  return payload[offset];
}

function writeUInt16BE (payload,value, offset) {
  value = +value;
  offset = offset >>> 0;
  checkInt(payload, value, offset, 2, 0xffff, 0);
  if (Buffer.TYPED_ARRAY_SUPPORT) {
    this[offset] = (value >>> 8);
    payload[offset + 1] = value;
  } else objectWriteUInt16(payload, value, offset, false);
  return offset + 2;
}

function writeUInt8 (payload,value, offset) {
  value = +value;
  offset = offset >>> 0;
  checkInt(payload, value, offset, 1, 0xff, 0);
  if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value);
  payload[offset] = value;
  return offset + 1;
}

function writeUInt32BE (payload,value, offset) {
  value = +value;
  offset = offset >>> 0;
  checkInt(payload, value, offset, 4, 0xffffffff, 0);
  if (Buffer.TYPED_ARRAY_SUPPORT) {
    payload[offset] = (value >>> 24);
    payload[offset + 1] = (value >>> 16);
    payload[offset + 2] = (value >>> 8);
    payload[offset + 3] = value;
  } else objectWriteUInt32(payload, value, offset, false);
  return offset + 4;
}

function objectWriteUInt16 (buf, value, offset, littleEndian) {
  if (value < 0) value = 0xffff + value + 1;
  for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; i++) {
    buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>> (littleEndian ? i : 1 - i) * 8;
  }
}

function objectWriteUInt32 (buf, value, offset, littleEndian) {
  if (value < 0) value = 0xffffffff + value + 1;
  for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; i++) {
    buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) *  & 0xff;
  }
}

 

 

7. Add the following function to support previous inserted functions

 

 

function checkOffset (offset, ext, length) {
  if ((offset % 1) !== 0 || offset < 0) throw new Error ('offset is not uint');
  if (offset + ext > length) throw new Error ('Trying to access beyond buffer length');
}

 

 

8. Add the following function for casting String to Bytes

 

 

function splitInBytes(data) {
    var bytes = [];
    var bytesAsString = '';
    for (var i = 0, j = 0;
         i < data.length;
         i += 2,
         j++) {
        bytes[j] = parseInt(data.substr(i, 2), 16);
        bytesAsString += bytes[j] + ' ';
    }
    return bytes;
}

 

 

9. Remap function calls to newly inserted functions

Use the built-in script editor replace feature for the following, see below:

image

 

Within the service script perform a Replace for each of the following lines.

Search Replace by
payload.readInt16BE( readInt16BE(payload,
payload.readUInt32BE( readUInt32BE(payload,
payload.readUInt16BE( readUInt16BE(payload,
payload.readUInt8( readUInt8(payload,
payload.writeUInt16BE( writeUInt16BE(payload,
payload.writeUInt8( writeUInt8(payload,
payload.writeUInt32BE( writeUInt32BE(payload,

 

10. At the Bottom update the following

Replace : decoder.setDeviceType("temp");

By : decoder.setDeviceType(type);

 

11. Insert the following at the bottom

var result = Decoder(splitInBytes(payload), 0);

 

12. Save Service and Thing

 

13. Create a test Service for Adeunis Temp Device

Within "AdeunisCodec" Thing

Create a new service called "test_decode_temp" with Output as String

Insert the following code: 

 

 

// result: STRING
var result = me.Decode({type: "temp" /* STRING */,payload: "43400100F40200F1" /* STRING */});

 

 

Save & Execute 

The expected result is:

 

 

{"temperatures":[{"unit":"°C","name":"probe 1","id":0,"value":24.4},{"unit":"°C","name":"probe 2","id":0,"value":24.1}],"type":"0x43 Temperature data","status":{"frameCounter":2,"lowBattery":false,"hardwareError":false,"probe1Alarm":false,"configurationDone":false,"probe2Alarm":false}}

 

 

 

Please visit the Decoder test section of Adeunis website to see the reference for the Temp device test case, here.

 

Spoiler
The resources has been tested on ThingWorx 8.5 and with the latest and greatest ThingWorx 9...  
If you are more interested in the result than in the implementation process then import the attached "Things_AdeunisCodec.xml" 😉 

 

Version history
Last update:
‎Jul 06, 2020 11:56 AM
Updated by:
Labels (2)
Attachments