Decoding Jeelib binary packets

#1

Using a jeelabs HAT on a Raspberry Pi to receive RF data from remote sensors, which can then be picked up by a 'serial in node' from /dev/ttyAMA0.

The payload received by the serial node takes the following format;
OK 10 22 1 0 0 0 0 237 94 188 4 (-61) where OK is the acknowledgement, 10 is the respective device node, and (-61) is the RSSI of the device.

The remaining 10 bytes are data pairs, which then need decoding into 5 device sensor readings as follows;

x= ([1st byte] + ([2nd byte] * 2^8));
      if (x > 2^15) {
            x = (x - (2^16)); 
            }
     return x

Each device follows the same format but may have a different number of byte pairs, for example a temperature node may have 3 byte pairs - temperature, humidity & battery.

The goal would be to get the data into a usable format, something like??
byte

I've looked through existing nodes in the library, and can't see anything specifically for jeelib, but there a node-red-contrib-binary although it doesn't seem to handle this format.

I really don't know where to start with this, so any help would be appreciated.

0 Likes

#2

If it’s all space separated I would check it starts with OK then split on space to create an array. Then shift off the ok and the first (node) value, pop the Rossi from the other end. Then iterate over the remaining length/2 times to create the values using the formula.

0 Likes

#3

I've got this far, but no idea how to "Then iterate over the remaining length/2 times to create the values using the formula"

This is what I have so far;

if (msg.payload.startsWith("OK")) {
  var x = msg.payload.split(" ");
  var ack = x.shift();
  var node = x.shift();
  var rssi = (x.pop().slice(1,-1));
    msg.ack = ack;
    msg.node = node;
    msg.rssi = rssi;
    msg.payload = x;
    return msg;
  } else {
    return null;
    }

...or my example flow -

[{"id":"a7703a1f.7323e8","type":"debug","z":"c53060.842a0fa","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":380,"y":910,"wires":[]},{"id":"7799b6ac.121f08","type":"inject","z":"c53060.842a0fa","name":"","topic":"","payload":"OK 10 22 1 0 0 0 0 237 94 188 4 (-61)","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":120,"y":910,"wires":[["bb91aa6e.1e7dd8"]]},{"id":"bb91aa6e.1e7dd8","type":"function","z":"c53060.842a0fa","name":"","func":"if (msg.payload.startsWith(\"OK\")) {\nvar x = msg.payload.split(\" \");\nvar ack = x.shift();\nvar node = x.shift();\nvar rssi = (x.pop().slice(1,-1));\n  msg.ack = ack;\n  msg.node = node;\n  msg.rssi = rssi;\n  msg.payload = x;\n  return msg;\n  } else {\n    return null;\n    }","outputs":1,"noerr":0,"x":250,"y":910,"wires":[["a7703a1f.7323e8"]]}]

...and again - the formula is;

x= ([1st byte] + ([2nd byte] * 2^8));
      if (x > 2^15) {
            x = (x - (2^16)); 
            }
     return x
0 Likes

#4

try this

if (msg.payload.startsWith("OK")) {
  var x = msg.payload.split(" ");
  msg.ack = x.shift();
  msg.node = x.shift();
  msg.rssi = parseInt(x.pop().slice(1,-1));
  
  for (var i=0; i < x.length; i++) {
      msg[i/2] = parseInt(x[i]) + parseInt(x[i+1]) * 256;
      if (msg[i/2] > 32768) { msg[i/2] = msg[i/2] - 65536; }
      i++;
  }
  delete msg.payload;
  return msg;
} 
return null;
0 Likes

#5

Thank you, almost there!
Using live data, I'm seeing 6 values in the array, instead of 5. The 6th is NaN.

The test data (which was obtained via the debug panel)

1

..which works OK, however,
using 'live' data, I'm getting

2

...which has added the additional NaN to the array, and the payload is defined differently...

0 Likes

#6

maybe some extra hidden chars at the end of the line or something ?

maybe var x = msg.payload.trim().split(" ");

0 Likes

#7

Yep! that has sorted it.
Thanks for your help Dave, I've learnt a lot through this....
never done 'shift' or 'pop' before......

0 Likes

#8

learning is what it's all about :tada:

1 Like