Skip to content

Instantly share code, notes, and snippets.

@Safrone
Created June 24, 2021 21:49
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Safrone/d3894caf03985cf9d3395c52405525f7 to your computer and use it in GitHub Desktop.
Save Safrone/d3894caf03985cf9d3395c52405525f7 to your computer and use it in GitHub Desktop.
Elsys Chirpstack Decoder
// 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]
// The function must return an object, e.g. {"temperature": 22.5}
/*
@reference https://elsys.se/public/documents/Sensor_payload.pdf
Sensors Name Designation
------------------------------------------------------------
Sound Sensor ERS Sound
*/
function Decode(fPort, bytes, variables) {
return DecodeElsysPayload(bytes);
/*
if ((bytes[0] === 1) && (bytes.length >= 16)) {
var temperature = (bytes[1] << 8) + bytes[2]
if ((bytes[1] & (1 << 7)) !== 0) {
temperature = -1 * (0xFFFF - temperature + 1)
}
else {
temperature = (bytes[1] << 8) + bytes[2]
}
return {
"temperature": {1: temperature},
"humidity": {2: bytes[4]},
"illuminance": {4: (bytes[6] << 8) + bytes[7]},
"motion_counts": {5: bytes[9]},
"battery": {7: (bytes[11] << 8) + bytes[12]},
"sound_peak": {21: bytes[14]},
"sound_avg": {21: bytes[15]}
}
}
else {
return {"raw_message": {0: bytes}}
}*/
}
/*
______ _ _______ _______
| ____| | / ____\ \ / / ____|
| |__ | | | (___ \ \_/ / (___
| __| | | \___ \ \ / \___ \
| |____| |____ ____) | | | ____) |
|______|______|_____/ |_| |_____/
ELSYS simple payload decoder.
Use it as it is or remove the bugs :)
www.elsys.se
peter@elsys.se
*/
var TYPE_TEMP = 0x01; //temp 2 bytes -3276.8°C -->3276.7°C
var TYPE_RH = 0x02; //Humidity 1 byte 0-100%
var TYPE_ACC = 0x03; //acceleration 3 bytes X,Y,Z -128 --> 127 +/-63=1G
var TYPE_LIGHT = 0x04; //Light 2 bytes 0-->65535 Lux
var TYPE_MOTION = 0x05; //No of motion 1 byte 0-255
var TYPE_CO2 = 0x06; //Co2 2 bytes 0-65535 ppm
var TYPE_VDD = 0x07; //VDD 2byte 0-65535mV
var TYPE_ANALOG1 = 0x08; //VDD 2byte 0-65535mV
var TYPE_GPS = 0x09; //3bytes lat 3bytes long binary
var TYPE_PULSE1 = 0x0A; //2bytes relative pulse count
var TYPE_PULSE1_ABS = 0x0B; //4bytes no 0->0xFFFFFFFF
var TYPE_EXT_TEMP1 = 0x0C; //2bytes -3276.5C-->3276.5C
var TYPE_EXT_DIGITAL = 0x0D; //1bytes value 1 or 0
var TYPE_EXT_DISTANCE = 0x0E; //2bytes distance in mm
var TYPE_ACC_MOTION = 0x0F; //1byte number of vibration/motion
var TYPE_IR_TEMP = 0x10; //2bytes internal temp 2bytes external temp -3276.5C-->3276.5C
var TYPE_OCCUPANCY = 0x11; //1byte data
var TYPE_WATERLEAK = 0x12; //1byte data 0-255
var TYPE_GRIDEYE = 0x13; //65byte temperature data 1byte ref+64byte external temp
var TYPE_PRESSURE = 0x14; //4byte pressure data (hPa)
var TYPE_SOUND = 0x15; //2byte sound data (peak/avg)
var TYPE_PULSE2 = 0x16; //2bytes 0-->0xFFFF
var TYPE_PULSE2_ABS = 0x17; //4bytes no 0->0xFFFFFFFF
var TYPE_ANALOG2 = 0x18; //2bytes voltage in mV
var TYPE_EXT_TEMP2 = 0x19; //2bytes -3276.5C-->3276.5C
var TYPE_EXT_DIGITAL2 = 0x1A; // 1bytes value 1 or 0
var TYPE_EXT_ANALOG_UV= 0x1B; // 4 bytes signed int (uV)
var TYPE_DEBUG = 0x3D; // 4bytes debug
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 += 2)
bytes.push(parseInt(hex.substr(c, 2), 16));
return bytes;
}
function DecodeElsysPayload(data){
var obj = {};
for(i=0;i<data.length;i++){
//console.log(data[i]);
switch(data[i]){
case TYPE_TEMP: //Temperature
var temp=(data[i+1]<<8)|(data[i+2]);
temp=bin16dec(temp);
obj.temperature = {1: temp/10};
i+=2;
break
case TYPE_RH: //Humidity
var rh=(data[i+1]);
obj.humidity = {2: rh};
i+=1;
break
case TYPE_ACC: //Acceleration
obj.acceleration_x = {3: bin8dec(data[i+1])};
obj.acceleration_y = {3: bin8dec(data[i+2])};
obj.acceleration_z = {3: bin8dec(data[i+3])};
i+=3;
break
case TYPE_LIGHT: //Light
obj.illuminance = {4: (data[i+1]<<8)|(data[i+2])};
i+=2;
break
case TYPE_MOTION: //Motion sensor(PIR)
obj.motion_counts = {5: (data[i+1])};
i+=1;
break
case TYPE_CO2: //CO2
obj.co2 = {6: (data[i+1]<<8)|(data[i+2])};
i+=2;
break
case TYPE_VDD: //Battery level
obj.battery = {7: (data[i+1]<<8)|(data[i+2])};
i+=2;
break
case TYPE_ANALOG1: //Analog input 1
obj.analog1 = {8: (data[i+1]<<8)|(data[i+2])};
i+=2;
break
case TYPE_GPS: //gps
obj.latitude = {9: (data[i+1]<<16)|(data[i+2]<<8)|(data[i+3])};
obj.longitude = {9: (data[i+4]<<16)|(data[i+5]<<8)|(data[i+6])};
i+=6;
break
case TYPE_PULSE1: //Pulse input 1
obj.pulse1 = {10: (data[i+1]<<8)|(data[i+2])};
i+=2;
break
case TYPE_PULSE1_ABS: //Pulse input 1 absolute value
var pulseAbs=(data[i+1]<<24)|(data[i+2]<<16)|(data[i+3]<<8)|(data[i+4]);
obj.pulse_abs = {11: pulseAbs};
i+=4;
break
case TYPE_EXT_TEMP1: //External temp
var temp=(data[i+1]<<8)|(data[i+2]);
temp=bin16dec(temp);
obj.external_temperature = {12: temp/10};
i+=2;
break
case TYPE_EXT_DIGITAL: //Digital input
obj.digital = {13: (data[i+1])};
i+=1;
break
case TYPE_EXT_DISTANCE: //Distance sensor input
obj.distance = {14: (data[i+1]<<8)|(data[i+2])};
i+=2;
break
case TYPE_ACC_MOTION: //Acc motion
obj.acc_motion = {15: (data[i+1])};
i+=1;
break
case TYPE_IR_TEMP: //IR temperature
var iTemp=(data[i+1]<<8)|(data[i+2]);
iTemp=bin16dec(iTemp);
var eTemp=(data[i+3]<<8)|(data[i+4]);
eTemp=bin16dec(eTemp);
obj.ir_internal_temperature = {16: iTemp/10};
obj.ir_external_temperature = {16: eTemp/10};
i+=4;
break
case TYPE_OCCUPANCY: //Body occupancy
obj.occupancy = {17: (data[i+1])};
i+=1;
break
case TYPE_WATERLEAK: //Water leak
obj.water_leak = {18: (data[i+1])};
i+=1;
break
case TYPE_GRIDEYE: //Grideye data
var ref = data[i+1];
i++;
obj.grideye = {19: []};
for(var j = 0; j < 64; j++) {
obj.grideye[TYPE_GRIDEYE][j] = ref + (data[1+i+j] / 10.0);
}
i += 64;
break
case TYPE_PRESSURE: //External Pressure
var temp=(data[i+1]<<24)|(data[i+2]<<16)|(data[i+3]<<8)|(data[i+4]);
obj.pressure = {20: temp/1000};
i+=4;
break
case TYPE_SOUND: //Sound
obj.sound_peak = {21: data[i+1]};
obj.sound_avg = {21: data[i+2]};
i+=2;
break
case TYPE_PULSE2: //Pulse 2
obj.pulse2 = {22: (data[i+1]<<8)|(data[i+2])};
i+=2;
break
case TYPE_PULSE2_ABS: //Pulse input 2 absolute value
obj.pulse_abs2 = {23: (data[i+1]<<24)|(data[i+2]<<16)|(data[i+3]<<8)|(data[i+4])};
i+=4;
break
case TYPE_ANALOG2: //Analog input 2
obj.analog2 = {24: (data[i+1]<<8)|(data[i+2])};
i+=2;
break
case TYPE_EXT_TEMP2: //External temp 2
var temp=(data[i+1]<<8)|(data[i+2]);
temp=bin16dec(temp);
if(typeof obj.external_temperature2 === "number") {
obj.external_temperature2 = {25: obj.external_temperature2};
}
if(typeof obj.externalTemperature2 === "object") {
obj.externalTemperature2 = {25: (temp / 10)};
} else {
obj.externalTemperature2 = {25: temp / 10};
}
i+=2;
break
case TYPE_EXT_DIGITAL2: //Digital input 2
obj.digital2 = {26: (data[i+1])};
i+=1;
break
case TYPE_EXT_ANALOG_UV: //Load cell analog uV
obj.analog_uv = {27: (data[i + 1] << 24) | (data[i + 2] << 16) | (data[i + 3] << 8) | (data[i + 4])};
i += 4;
break
default: //something is wrong with data
i=data.length;
break
}
}
return obj;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment