From d1d569dadfc06636390cceec1e18d29bc3d2ac58 Mon Sep 17 00:00:00 2001 From: cheetah Date: Sun, 13 Nov 2022 23:59:44 +0000 Subject: [PATCH] added birdy slim payloadformatter --- ttnv3.uplink.birdyslim.js | 125 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 ttnv3.uplink.birdyslim.js diff --git a/ttnv3.uplink.birdyslim.js b/ttnv3.uplink.birdyslim.js new file mode 100644 index 0000000..96b4e2e --- /dev/null +++ b/ttnv3.uplink.birdyslim.js @@ -0,0 +1,125 @@ +function Decoder(bytes, port) { + var data = {} + function bytesToString(a) { + return a.map(function(x){ return String.fromCharCode(x) }).join('') // because very OLD js parser + } + switch (port) { + case 1: // Technical Received Acknowledgment '|5||C|' + // 31 32 33 34 35 20 + data.type = 'ack' + data.ack = 'recv' + data.msgid = bytesToString(bytes.splice(0,5)) + data.rssi = bytes[0] + break; + case 2: // Read and Operational Acknowledgment 'AA|5|' and Operational '33|5|' + // AA 31 32 33 34 35 + // operational ack with Payload "test"(maybe you should use a single byte) + // 33 31 32 33 34 35 54 65 73 74 + data.type = 'ack' + data.ack = bytes.length == 5 ? 'read' : 'operational' + data.msgid = bytesToString(bytes.splice(0,5)) + if (data.ack === 'operational') { + data.operationalData = bytes + } + break; + case 3: // Status & Canned Messages + // Canned Message '01' --- '05', single Hex Number, incrementing + // Status '|Z|' or if no CenterSelection '00' + + if (bytes.length == 1) { + data.type = 'cannedMessage' + data.cannedMessage = bytes[0] * 1 + } else { + data.type = 'status' + data.status = bytes[0] * 1 + data.selection = bytes[1] * 1 + } + break; + case 4: // Battery and Power Notifications + // Startup 'FF' + // Shutdown 'EE' + // Low Battery 'FD' + // ChargingOn '|V|CC' + // ChargingOff'|V|BB' + if (bytes.length == 1) { + data.type = 'power' + if (bytes[0] >= 0xEE) { + data.poweredOn = bytes[0]== 0xFF + } + if (bytes[0] == 0xFD) { + data.type = 'low_battery' + } + if (bytes[0] <= 0xAA) { + data.type = 'battery' + data.battery = bytes[0] * 1 + data.isCharging = false + } + } else { + data.type = 'battery' + data.battery = bytes[0] * 1 + data.isCharging = bytes[1] == 0xCC + } + break; + case 5: // OTAStatus + LoneWorker/SOS Trigger + GPS Tracking Port '|G|' + // GPS Tracking '|G|' + //// 00 1E 33 D7 00 4A 2C 31 10 + // SOS Start 'FF|G|' + //// FF 00 1E 33 D7 00 4A 2C 31 10 + // SOS End 'FE|G|' + //// FE 00 1E 33 D7 00 4A 2C 31 10 + // LoneWorker Lack of movement 'FD|G|' + //// FD 00 1E 33 D7 00 4A 2C 31 10 + // LoneWorker Falldetect 'FC|G|' + //// FC 00 1E 33 D7 00 4A 2C 31 10 + // LoneWorker End 'FB|G|' + //// FB 00 1E 33 D7 00 4A 2C 31 10 + // OTA/PagerStatus 'FA|G||V|' + //// FA 00 1E 33 D7 00 4A 2C 31 10 28 + if (bytes.length !== 9) { // we have more than just the |G| block + if (bytes.length === 10) { + switch(bytes[0]) { + case 0xFF: // SOS Start + data.type = 'sos' + data.sos = true + break; + case 0xFE: // SOS End + data.type = 'sos' + data.sos = false + break; + case 0xFD: // LoneWorker Lack of movement + data.type = 'sos' + data.sos = false + data.loneworker = 'lackofmovement' + break; + case 0xFC: // LoneWorker Falldetect + data.type = 'sos' + data.sos = false + data.loneworker = 'falldetect' + break; + case 0xFB: // LoneWorker End + data.type = 'sos' + data.sos = false + data.loneworker = false + break; + } + bytes.splice(0,1) + } + if (bytes.length === 11) { // OTA PagerStatus + data.type = 'ota' + data.ota = 'status' + data.battery = bytes[10] * 1 + bytes.splice(0,1) + } + } else { // we are having a normal gps block only + data.type = 'gps' + } + var gpsBlock = bytes.splice(0,9) + data.longitude = ((gpsBlock[0]<<24)>>>0) + ((gpsBlock[1]<<16)>>>0) + ((gpsBlock[2]<<8)>>>0) + gpsBlock[3] + data.longitude /= 10e4 + data.latitude = ((gpsBlock[4]<<24)>>>0) + ((gpsBlock[5]<<16)>>>0) + ((gpsBlock[6]<<8)>>>0) + gpsBlock[7] + data.latitude /= 10e4 + data.lastGPSAcquisition = gpsBlock[8] + break; + } + return data; + } \ No newline at end of file