hi all, i have some problems in getting a payload decoder in js for "agoraopinion feedback buttons"working proper. This device has 3 action keys(red,yellow,green). i took an already existing script and modify it. my solution shows only 2 of the 3 buttons that got triggered. i am totaly new to js. would be fine if you could help me. thanks
Here my solution:
var TYPE_PTYPE = bytes[-2]; //Payload type
var TYPE_YELLOW = bytes[2]; //Leftbutton
var TYPE_GREEN = bytes[4]; //middle button
var TYPE_RED = bytes[0]; //right button
var TYPE_BL = bytes[6]; //Battery Level
var TYPE_DI = bytes[8]; //Device ID
function bin16dec(bin) {
var num=bin&0xFFFF;
if (0x8000 & num)
num = - (0x010000 - num);
return num;
}
function bin8dec(bin) {
var num=bin&0xFF;
if (0x80 & num)
num = - (0x0100 - num);
return num;
}
function hexToBytes(hex) {
for (var bytes = [], c = 0; c < hex.length; c += 3)
bytes.push(parseInt(hex.substr(c, 2), 16));
return bytes;
}
function DecodeSmileybox(bytes){
var obj = new Object();
for(i=0;i<bytes.length;i++){
//console.log(data[i]);
switch(bytes[i]){
case TYPE_PTYPE: //Payloadtype
obj.ptype=(bytes[i+1]);
i+=1;
break
case TYPE_YELLOW: //left button
obj.yellow=(bytes[i+1]);
i+=1;
break
case TYPE_GREEN: //middle button
obj.green=(bytes[i+1]>>4); //obj.green=(bytes[i+1]);
i+=1;
break
case TYPE_RED: //right button
obj.red=(bytes[i+1]);
i+=1;
break
case TYPE_BL: //Battery Level
obj.bl=(bytes[i+1]);
i+=1;
break
case TYPE_DI: //Device ID
//obj.motion=(bytes[i+1]);
obj.di=(bytes[i+1]);
i+=1;
break
default: //somthing is wrong with data
i=bytes.length;
break
}
}
return obj;
}
function Decode(fPort, bytes) {
return DecodeSmileybox(bytes);
}
Okay, this is indeed a literal repost of your Slack post
Let me repeat my remarks/questions too then:
The PDF document shows a text-based message, assuming you indeed get 16 bytes (or 14), not 8 (or 6), for the first message type that’s described in the PDF. That is not only quite bad for LoRaWAN (a big waste of airtime), but also complicates things a lot. Also, it does not at all match the script you’ve got so far: the script seems to expect a specific message whenever a button is pressed, rather than some totals as per the PDF.
So: it would help to see actual payloads as received in your application (TTN Console) along with the values that you think this should decode into.
Good, it’s not text! Even more, it only uses 1.5 bytes for a single count, not wasting anything at all. Many would simply have used 2 bytes per counter.
Then the following might work? Note that it uses a fixed-format decoder; not some loop that iterates over the payload and tries to determine how to interpret the next part by comparing to some known values, like in your attempt:
/**
* Decoder for Agora Opinion feedback button.
*/
function Decoder(bytes, port) {
var result = {};
result.payloadType = bytes[0];
// 1.5 bytes (3 nibbles) per count, plus 0.5 byte for battery,
// encoded in 5 bytes; rr ry yy gg gb
result.redCount = bytes[1]<<4 | bytes[2]>>4;
result.yellowCount = (bytes[2] & 0x0F)<<8 | bytes[3];
result.greenCount = bytes[4]<<4 | bytes[5]>>4;
// Unary-plus operator to cast string result of toFixed to number
result.batteryVoltage =
+((3 * 1.224) / (((bytes[5] & 0x0F) + 20) / 21)).toFixed(1);
return result;
}
To explain the bitwise operators, for the 5 bytes rr ry yy gg gb, all in hexadecimal notation using two 4-bits nibbles for each 8-bits byte:
rr << 4 appends a nibble to the right, so yields rr0 (left shift of 4 bits; actually the result is 32 bits, so 00000rr0)
ry >> 4 shifts the rightmost nibble out of memory, so discards y and yields r (right shift; actually 0000000r)