I’m using a Wisblock dev kit to build an environment monitor as per the guide/sketch published here:
It’s working fine, and from the serial monitor I can see the measurements being taken.
I’m passing the data to a Chirpstack server, but I’m having trouble decoding the data, I’m not much of a programmer and I’m struggling to get my head around the code for it.
I’ve been trying to use this code block:
function decodeUplink(fPort, bytes) {
var data = {};
if (fPort === 2) {
// Decode temperature
var temp = bytes[0] << 8 | bytes[1];
data.temperature = temp / 100.0;
// Decode humidity
var hum = bytes[2] << 8 | bytes[3];
data.humidity = hum / 100.0;
// Decode pressure
var pres = bytes[4] << 8 | bytes[5];
data.pressure = pres / 100.0;
// Decode gas resistance
var gas = bytes[6] << 24 | bytes[7] << 16 | bytes[8] << 8 | bytes[9];
data.gasResistance = gas;
}
return data;
}
in Chirpstack I just see an error:
“decodeUplink did not return ‘data’”
It seems the code is returning an empty object maybe? Not sure how to troubleshoot this one.
Hi @Wedgie32
I think there are some minor mistakes in your decoder. The data (temperature first), doesn’t start at bytes[0], because byted[0] is the data type:
Byte 0 ==> Marker for the data type, for environment sensor it is alway 1
Byte 1 - 2 ==> temperature MSB first, 2 bytes length
Byte 3 - 4 ==> humidity MSB first, 2 bytes lenght
Byte 5 - 8 ==> barometric pressure, MSB first, 4 bytes length
Byte 9 - 14 ==> gas resistance, MSB first, 4 bytes length
Try this decoder, that should work on TTN and Chirpstack V3 and V4:
// Decode decodes an array of bytes into an object.
// - fPort contains the LoRaWAN fPort number
// - bytes is an array of bytes, e.g. [225, 230, 255, 0]
// - variables contains the device variables e.g. {"calibration": "3.5"} (both the key / value are of type string)
// The function must return an object, e.g. {"temperature": 22.5}
function DoDecode(fPort, bytes) {
var decoded = {};
switch (bytes[0])
{
case 0x01: // Environment sensor data
decoded.temperature = (bytes[1] << 8 | bytes[2]) / 100;
decoded.humidity = (bytes[3] << 8 | + bytes[4]) / 100;
decoded.pressure = (bytes[8] | (bytes[7] << 8) | (bytes[6] << 16) | (bytes[5] << 24)) / 100;
decoded.gas = bytes[12] | (bytes[11] << 8) | (bytes[10] << 16) | (bytes[9] << 24);
decoded.batt = (bytes[13] << 8 | bytes[14]) / 100;
break;
case 0x02: // Temperature and humidity sensor data
decoded.temperature = (bytes[1] << 8 | bytes[2]) / 100;
decoded.humidity = (bytes[3] << 8 | + bytes[4]) / 100;
decoded.batt = (bytes[5] << 8 | bytes[6]) / 100;
break;
case 0x03: // Ambient light sensor data
decoded.light = (bytes[4] | (bytes[3] << 8) | (bytes[2] << 16) | (bytes[1] << 24)) / 10;
decoded.batt = (bytes[5] << 8 | bytes[6]) / 100;
break;
case 0x04: // No sensor data, just counter
decoded.cnt = bytes[4] | (bytes[3] << 8) | (bytes[2] << 16) | (bytes[1] << 24);
break;
case 0x20: // Solar panel data
decoded.current = (bytes[1] << 8 | bytes[2]);
decoded.today = (bytes[3] << 8 | + bytes[4]);
break;
case 0x30: // Accelerometer sensor
if (bytes[1] == 0) {
decoded.x_move = "no";
} else {
decoded.x_move = "yes";
}
if (bytes[2] == 0) {
decoded.y_move = "no";
} else {
decoded.y_move = "yes";
}
if (bytes[3] == 0) {
decoded.z_move = "no";
} else {
decoded.z_move = "yes";
}
break;
default:
decoded.unknown = "Unknown data format";
break;
}
return decoded;
}
// For TTN
function Decoder(bytes, fPort)
{
return DoDecode(fPort, bytes);
}
// For Chirpstack
function Decode(fPort, bytes, variables)
{
return DoDecode(fPort, bytes);
}
// Chirpstack v3 to v4 compatibility wrapper
function decodeUplink(input) {
return {
data: Decode(input.fPort, input.bytes, input.variables)
};
}