Skip to content

Instantly share code, notes, and snippets.

@DefProc
Last active July 4, 2020 20:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DefProc/139948c9236e16c8608e8aa7bb6cf100 to your computer and use it in GitHub Desktop.
Save DefProc/139948c9236e16c8608e8aa7bb6cf100 to your computer and use it in GitHub Desktop.
TTN decoder for AM100/AM102 sensors
function Decoder(bytes, port) {
// Decode an uplink message from a buffer
// (array) of bytes to an object of fields.
var decoded = {};
// for Ursalink AM100/AM102 Payload Structure
// From: https://resource.ursalink.com/document/am100_series_payload_structure.pdf
for (i = 0; i < bytes.length;) {
// BATTERY (%)
if (bytes[i] == 0x01 && bytes[i+1] == 0x75) {
decoded.battery = bytes[i+2];
i += 3;
continue;
}
// TEMPERATURE (degC)
else if (bytes[i] == 0x03 && bytes[i+1] == 0x67) {
// If there's already a reading, ignore
if (typeof decoded.temperature == 'undefined') {
decoded.temperature = readUInt16LE(bytes.slice(i+2, i+3)) / 10;
}
i += 4;
continue;
}
// HUMIDITY (% abs)
else if (bytes[i] == 0x04 && bytes[i+1] == 0x68) {
// If there's already a reading, ignore
if (typeof decoded.humidity == 'undefined') {
decoded.humidity = bytes[i+2]/2 ;
}
i += 3;
continue;
}
// Light levels (lux)
else if (bytes[i] == 0x06 && bytes[i+1] == 0x65) {
// If there's already a reading, ignore
if (typeof decoded.illumination == 'undefined') {
decoded.illumination = readUInt16LE(bytes.slice(i+2, i+3)) ;
decoded.visible_infrared = readUInt16LE(bytes.slice(i+4, i+5)) ;
decoded.infrared = readUInt16LE(bytes.slice(i+6, i+7)) ;
}
i += 8;
continue;
}
// PIR Activity (number of events)
else if (bytes[i] == 0x05 && bytes[i+1] == 0x6a) {
// If there's already a reading, ignore
if (typeof decoded.activity == 'undefined') {
//decoded.activity = readUInt16LE(bytes.slice(i+2, i+3)) ;
decoded.activity = (bytes[i+3] << 8) + bytes[i+2];
}
i += 4;
continue;
}
// CO2 concentration (ppm)
else if (bytes[i] == 0x07 && bytes[i+1] == 0x7d) {
// If there's already a reading, ignore
if (typeof decoded.co2 == 'undefined') {
//decoded.co2 = readUInt16LE(bytes.slice(i+2, i+3)) ;
decoded.co2 = (bytes[i+3] << 8) + bytes[i+2];
//decoded.co2_hex = toHexString(bytes.slice(i+2, i+3)) ;
}
i += 4;
continue;
}
// TVOC concentration (ppb)
else if (bytes[i] == 0x08 && bytes[i+1] == 0x7d) {
// If there's already a reading, ignore
if (typeof decoded.tvoc == 'undefined') {
decoded.tvoc = (bytes[i+3] << 8) + bytes[i+2];
}
i += 4;
continue;
}
// Barometric Pressure (kPa)
else if (bytes[i] == 0x09 && bytes[i+1] == 0x73) {
// If there's already a reading, ignore
if (typeof decoded.pressure == 'undefined') {
decoded.pressure = ((bytes[i+3] << 8) + bytes[i+2]) / 10;
}
i += 4;
continue;
}
else {
// nothing matched
i++;
}
}
return decoded;
}
/* isEmpty
*/
function isEmpty(obj) {
return Object.getOwnPropertyNames(obj).length === 0;
}
/* toHexString
*/
function toHexString(byteArray) {
var s = '0x';
byteArray.forEach(function(byte) {
s += ('0' + (byte & 0xFF).toString(16)).slice(-2);
});
return s;
}
/* ******************************************
* bytes to number
********************************************/
function readUInt8LE(bytes) {
return (bytes & 0xFF);
}
function readInt8LE(bytes) {
var ref = readUInt8LE(bytes);
return (ref > 0x7F) ? ref - 0x100 : ref;
}
function readUInt16LE(bytes) {
var value = (bytes[1] << 8) + bytes[0];
return (value & 0xFFFF);
}
function readInt16LE(bytes) {
var ref = readUInt16LE(bytes);
return (ref > 0x7FFF) ? ref - 0x10000 : ref;
}
function readUInt32LE(bytes) {
var value = (bytes[3] << 24) + (bytes[2] << 16) + (bytes[1] << 8) + bytes[0];
return (value & 0xFFFFFFFF);
}
function readInt32LE(bytes) {
var ref = readUInt32LE(bytes);
return (ref > 0x7FFFFFFF) ? ref - 0x100000000 : ref;
}
function readFloatLE(bytes) {
// JavaScript bitwise operators yield a 32 bits integer, not a float.
// Assume LSB (least significant byte first).
var bits = bytes[3] << 24 | bytes[2] << 16 | bytes[1] << 8 | bytes[0];
var sign = (bits >>> 31 === 0) ? 1.0 : -1.0;
var e = bits >>> 23 & 0xff;
var m = (e === 0) ? (bits & 0x7fffff) << 1 : (bits & 0x7fffff) | 0x800000;
var f = sign * m * Math.pow(2, e - 150);
return f;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment