Skip to content

Instantly share code, notes, and snippets.

@alnjxn
Last active September 5, 2018 18:50
Show Gist options
  • Save alnjxn/34ec8c58acf87f9ae8a9c96a656cbfed to your computer and use it in GitHub Desktop.
Save alnjxn/34ec8c58acf87f9ae8a9c96a656cbfed to your computer and use it in GitHub Desktop.
Elsys Packet Decoder / Encoder for TTN
function Converter(decoded, port) {
// Merge, split or otherwise
// mutate decoded fields.
var converted = decoded;
// if (port === 1 && (converted.led === 0 || converted.led === 1)) {
// converted.led = Boolean(converted.led);
// }
return converted;
}
function Decoder(bytes, port) {
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;
}
var decoded = {};
if (port === 5) {
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
for (i = 0; i < bytes.length; i++) {
switch(bytes[i]) {
case TYPE_TEMP: //Temperature
var temp = (bytes[i+1]<<8) | (bytes[i+2]);
temp = bin16dec(temp);
decoded.temperature = temp / 10;
i += 2;
break;
case TYPE_RH: //Humidity
var rh = (bytes[i+1]);
decoded.humidity = rh;
i += 1;
break;
case TYPE_ACC: //Acceleration
decoded.x = bin8dec(bytes[i+1]);
decoded.y = bin8dec(bytes[i+2]);
decoded.z=bin8dec(bytes[i+3]);
i += 3;
break;
case TYPE_LIGHT: //Light
decoded.light = (bytes[i+1]<<8) | (bytes[i+2]);
i += 2;
break;
case TYPE_MOTION: //Motion sensor(PIR)
decoded.motion = (bytes[i+1]);
i += 1;
break;
case TYPE_CO2: //CO2
decoded.co2 = (bytes[i+1]<<8) | (bytes[i+2]);
i += 2;
break;
case TYPE_VDD: //Battery level
decoded.vdd = (bytes[i+1]<<8) | (bytes[i+2]);
i += 2;
break;
case TYPE_ANALOG1: //Analog input 1
decoded.analog1 = (bytes[i+1]<<8) | (bytes[i+2]);
i += 2;
break;
case TYPE_GPS: //gps
decoded.lat = (bytes[i+1]<<16) | (bytes[i+2]<<8) | (bytes[i+3]);
decoded.long = (bytes[i+4]<<16) | (bytes[i+5]<<8) | (bytes[i+6]);
i += 6;
break;
case TYPE_PULSE1: //Pulse input 1
decoded.pulse1 = (bytes[i+1]<<8) | (bytes[i+2]);
i += 2;
break;
case TYPE_PULSE1_ABS: //Pulse input 1 absolute value
var pulseAbs = (bytes[i+1]<<24) | (bytes[i+2]<<16) | (bytes[i+3]<<8) | (bytes[i+4]);
decoded.pulseAbs=pulseAbs;
i += 4;
break;
case TYPE_EXT_TEMP1: //External temp
var extTemp = (bytes[i+1]<<8) | (bytes[i+2]);
extTemp = bin16dec(extTemp);
decoded.externalTemperature = extTemp / 10;
i += 2;
break;
case TYPE_EXT_DIGITAL: //Digital input
decoded.digital=(bytes[i+1]);
i += 1;
break;
case TYPE_EXT_DISTANCE: //Distance sensor input
decoded.distance=(bytes[i+1]<<8) | (bytes[i+2]);
i += 2;
break;
case TYPE_ACC_MOTION: //Acc motion
decoded.accMotion=(bytes[i+1]);
i += 1;
break;
case TYPE_IR_TEMP: //IR temperature
var iTemp = (bytes[i+1]<<8) | (bytes[i+2]);
iTemp = bin16dec(iTemp);
var eTemp = (bytes[i+3]<<8) | (bytes[i+4]);
eTemp = bin16dec(eTemp);
decoded.irInternalTemperature = iTemp / 10;
decoded.irExternalTemperature = eTemp / 10;
i += 4;
break;
case TYPE_OCCUPANCY: //Body occupancy
decoded.occupancy = (bytes[i+1]);
i += 1;
break;
case TYPE_WATERLEAK: //Water leak
decoded.waterleak = (bytes[i+1]);
i += 1;
break;
case TYPE_GRIDEYE: //Grideye bytes
i += 65;
break
case TYPE_PRESSURE: //External Pressure
var press =(bytes[i+1]<<24) | (bytes[i+2]<<16) | (bytes[i+3]<<8) | (bytes[i+4]);
decoded.pressure = press / 1000;
i += 4;
break;
case TYPE_SOUND: //Sound
decoded.soundPeak = bytes[i+1];
decoded.soundAvg = bytes[i+2];
i += 2;
break;
case TYPE_PULSE2: //Pulse 2
decoded.pulse2=(bytes[i+1]<<8)|(bytes[i+2]);
i += 2;
break;
case TYPE_PULSE2_ABS: //Pulse input 2 absolute value
decoded.pulseAbs2 = (bytes[i+1]<<24) | (bytes[i+2]<<16) | (bytes[i+3]<<8) | (bytes[i+4]);
i += 4;
break;
case TYPE_ANALOG2: //Analog input 2
decoded.analog2 = (bytes[i+1]<<8) | (bytes[i+2]);
i += 2;
break;
case TYPE_EXT_TEMP2: //External temp 2
var extTemp2 = (bytes[i+1]<<8) | (bytes[i+2]);
extTemp2 = bin16dec(extTemp2);
decoded.externalTemperature2 = extTemp2 / 10;
i += 2;
break;
default: //something is wrong with bytes
i = bytes.length;
break;
}
}
}
if (port === 6) {
var TYPE_APPS_KEY = 0x01; //App Session Key 16 byte
var TYPE_NWKS_KEY = 0x02; //Network Session Key 16 byte
var TYPE_DEV_EUI = 0x03; //Device EUI 8 byte
var TYPE_APP_EUI = 0x04; //Application EUI 8 byte
var TYPE_APP_KEY = 0x05; //Application Key 16 byte
var TYPE_DEV_ADDR = 0x06; //Device Address 4 byte
var TYPE_OTA = 0x07; //OTAA 1 byte bool
var TYPE_PORT = 0x08; //Port 1 byte
var TYPE_MODE = 0x09; //Mode 1 byte
var TYPE_ACK = 0x0A; //Acknowledge Messages 1 byte bool
var TYPE_DR_DEF = 0x0B; //Data Rate (Default) 1 byte
var TYPE_DR_MAX = 0x0C; //Data Rate (Maximum) 1 byte
var TYPE_DR_MIN = 0x0D; //Data Rate (Minimum) 1 byte
var TYPE_PAYLOAD = 0x0E; //Payload 1 byte
var TYPE_POWER = 0x0F; //Power 1 byte
var TYPE_EXT_CFG = 0x10; //External Config 1 byte
var TYPE_PIR_CFG = 0x11; //PIR Config 1 byte
var TYPE_CO2_CFG = 0x12; //CO2 Config 1 byte
var TYPE_ACC_CFG = 0x13; //Acceleration Config 4 byte
var TYPE_SPL_PER = 0x14; //Sample Period 4 byte
var TYPE_TEMP_PER = 0x15; //Temperature Period 4 byte
var TYPE_RH_PER = 0x16; //Humidity Period 4 byte
var TYPE_LIGHT_PER = 0x17; //Light Period 4 byte
var TYPE_PIR_PER = 0x18; //PIR Period 4 byte
var TYPE_CO2_PER = 0x19; //CO2 Period 4 byte
var TYPE_EXT_PER = 0x1A; //External Period 4 byte
var TYPE_EXT_PWR_TIME = 0x1B; //External Power Time 4 byte (ms)
var TYPE_TRIG_TIME = 0x1C; //Trigger Time 4 byte (s)
var TYPE_ACC_PER = 0x1D; //Acceleration Period 4 byte
var TYPE_VDD_PER = 0x1E; //VDD Period 4 byte
var TYPE_SEND_PER = 0x1F; //Send Period 4 byte
var TYPE_LOCK = 0x20; //Lock Code 4 byte
var TYPE_LINK_CHK = 0x22; //Link Threshold, Period 4 byte
var TYPE_PRESS_PER = 0x23; //Pressure Period 4 byte
var TYPE_SOUND_PER = 0x24; //Sound Period 4 byte
var TYPE_LED_EXT = 0xFA; //4 bit ext mode, 4 bit LED mode
var TYPE_VERSION = 0xFB; //Version Number 4 byte
var TYPE_SLEEP = 0xFC; //Force Sensor Sleep 4 byte (s)
var TYPE_GENERIC = 0xFD; //1 byte lenith, x byte NFC string
var TYPE_REBOOT = 0xFE; //Reboot 0 bytes
decoded.dataRates = {};
decoded.sensorPeriods = {};
decoded.configurations = {};
for (i = 0; i < bytes.length; i++) {
switch(bytes[i]) {
case TYPE_OTA: //OTA Activation
var ota = (bytes[i+1]);
decoded.ota = ota ? true : false;
i += 1;
break;
case TYPE_PORT: //Port
var port = (bytes[i+1]);
port = bin16dec(port);
decoded.port = port;
i += 1;
break;
case TYPE_MODE: //Mode
var mode = (bytes[i+1]);
mode = bin16dec(mode);
decoded.mode = mode;
i += 1;
break;
case TYPE_ACK: //Acknowledge
var ack = (bytes[i+1]);
decoded.ack = ack ? true : false;
i += 1;
break;
case TYPE_DR_DEF: //Default Data Rate
var ddr = (bytes[i+1]);
ddr = bin16dec(ddr);
decoded.dataRates.default = ddr;
i += 1;
break;
case TYPE_DR_MAX: //Maximum Data Rate
var maxdr = (bytes[i+1]);
maxdr = bin16dec(maxdr);
decoded.dataRates.maximum = maxdr;
i += 1;
break;
case TYPE_DR_MIN: //Minimum Data Rate
var mindr = (bytes[i+1]);
mindr = bin16dec(mindr);
decoded.dataRates.minimum = mindr;
i += 1;
break;
case TYPE_PIR_CFG: //PIR Config
var pircfg = (bytes[i+1]);
pircfg = bin16dec(pircfg);
decoded.configurations.pir = pircfg;
i += 1;
break;
case TYPE_CO2_CFG: //CO2 Config
var co2cfg = (bytes[i+1]);
co2cfg = bin16dec(co2cfg);
decoded.configurations.co2 = co2cfg;
i += 1;
break;
case TYPE_ACC_CFG: //Acceleration Config
var acccfg = (bytes[i+1]<<24) | (bytes[i+2]<<16) | (bytes[i+3]<<8) | (bytes[i+4]);
acccfg = bin16dec(acccfg);
decoded.configurations.acc = acccfg;
i += 4;
break;
case TYPE_SPL_PER: //Sample Period
var splper = (bytes[i+1]<<24) | (bytes[i+2]<<16) | (bytes[i+3]<<8) | (bytes[i+4]);
splper = bin16dec(splper);
decoded.sensorPeriods.sample = splper;
i += 4;
break;
case TYPE_TEMP_PER: //Temperature Period
var tempper = (bytes[i+1]<<24) | (bytes[i+2]<<16) | (bytes[i+3]<<8) | (bytes[i+4]);
tempper = bin16dec(tempper);
decoded.sensorPeriods.temperature = tempper;
i += 4;
break;
case TYPE_RH_PER: //Humidity Period
var rhper =(bytes[i+1]<<24) | (bytes[i+2]<<16) | (bytes[i+3]<<8) | (bytes[i+4]);
rhper = bin16dec(rhper);
decoded.sensorPeriods.humidity = rhper;
i += 4;
break;
case TYPE_LIGHT_PER: //Light Period
var lightper = (bytes[i+1]<<24) | (bytes[i+2]<<16) | (bytes[i+3]<<8) | (bytes[i+4]);
lightper = bin16dec(lightper);
decoded.sensorPeriods.light = lightper;
i += 4;
break;
case TYPE_PIR_PER: //PIR Period
var pirper = (bytes[i+1]<<24) | (bytes[i+2]<<16) | (bytes[i+3]<<8) | (bytes[i+4]);
pirper = bin16dec(pirper);
decoded.sensorPeriods.pir = pirper;
i += 4;
break;
case TYPE_CO2_PER: //CO2 Period
var co2per = (bytes[i+1]<<24) | (bytes[i+2]<<16) | (bytes[i+3]<<8) | (bytes[i+4]);
co2per = bin16dec(co2per);
decoded.sensorPeriods.co2 = co2per;
i += 4;
break;
case TYPE_EXT_PER: //External Period
var extper = (bytes[i+1]<<24) | (bytes[i+2]<<16) | (bytes[i+3]<<8) | (bytes[i+4]);
extper = bin16dec(extper);
decoded.sensorPeriods.external = extper;
i += 4;
break;
case TYPE_EXT_PWR_TIME: //External Power Time (ms)
var extpwr = (bytes[i+1]<<24) | (bytes[i+2]<<16) | (bytes[i+3]<<8) | (bytes[i+4]);
extpwr = bin16dec(extpwr);
decoded.extPwrTime = extpwr;
i += 4;
break;
case TYPE_TRIG_TIME: //Trigger Time (s)
var trigtime = (bytes[i+1]<<24) | (bytes[i+2]<<16) | (bytes[i+3]<<8) | (bytes[i+4]);
trigtime = bin16dec(trigtime);
decoded.triggerTime = trigtime;
i += 4;
break;
case TYPE_ACC_PER: //Acceleration Period
var accper = (bytes[i+1]<<24) | (bytes[i+2]<<16) | (bytes[i+3]<<8) | (bytes[i+4]);
accper = bin16dec(accper);
decoded.sensorPeriods.acc = accper;
i += 4;
break;
case TYPE_VDD_PER: //VDD Period
var vddper = (bytes[i+1]<<24) | (bytes[i+2]<<16) | (bytes[i+3]<<8) | (bytes[i+4]);
vddper = bin16dec(vddper);
decoded.sensorPeriods.vdd = vddper;
i += 4;
break;
case TYPE_SEND_PER: //VDD Period
var sendper = (bytes[i+1]<<24) | (bytes[i+2]<<16) | (bytes[i+3]<<8) | (bytes[i+4]);
sendper = bin16dec(sendper);
decoded.sensorPeriods.transmit = sendper;
i += 4;
break;
case TYPE_LOCK: //Lock Code
var lock = (bytes[i+1]<<24) | (bytes[i+2]<<16) | (bytes[i+3]<<8) | (bytes[i+4]);
lock = bin16dec(lock);
decoded.lock = lock;
i += 4;
break;
case TYPE_LINK_CHK: //Link Threshold
var link = (bytes[i+1]<<24) | (bytes[i+2]<<16) | (bytes[i+3]<<8) | (bytes[i+4]);
link = bin16dec(link);
decoded.linkChk = link;
i += 4;
break;
case TYPE_PRESS_PER: //Pressure Period
var press = (bytes[i+1]<<24) | (bytes[i+2]<<16) | (bytes[i+3]<<8) | (bytes[i+4]);
press = bin16dec(press);
decoded.sensorPeriods.pressure = press;
i += 4;
break;
case TYPE_SOUND_PER: //Sound Period
var sound = (bytes[i+1]<<24) | (bytes[i+2]<<16) | (bytes[i+3]<<8) | (bytes[i+4]);
sound = bin16dec(sound);
decoded.sensorPeriods.sound = sound;
i += 4;
break;
case TYPE_VERSION: //Firmware Version
var v = (bytes[i+1]<<8) | (bytes[i+2]);
v = bin16dec(v).toString();
var version = v.charAt(0) + '.' + v.charAt(1) + '.' + v.charAt(2);
decoded.version = version;
i += 2;
break;
}
}
}
return decoded;
}
function Encoder(object, port) {
var TYPE_ACK = 'ack';
// Encode downlink messages sent as
// object to an array or buffer of bytes.
var bytes = [];
if (port === 6) {
bytes.push(0x3E, 0x00);
for (var key in object) {
switch(key)
{
case TYPE_ACK:
var ackSetting = object[key] ? 1: 0;
bytes.push(0x0A, ackSetting);
bytes[1] = bytes[1] + 2;
break;
default:
break;
}
}
}
return bytes;
}
function Validator(converted, port) {
// Return false if the decoded, converted
// message is invalid and should be dropped.
return true;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment