LANSITEC - Badge Tracker

Sensor

Codec Description

Codec for LANSITEC - Badge-Tracker (v1.0.0).

Codec Preview

function float16(bytes) { console.log(bytes.toString("hex")); const sign = bytes[0] >> 7 === 1? -1 : 1; const bias = 0x0f; const exponent = (bytes[0] & 0x7c) >> 2; const fraction = (bytes[0] & 0x03) << 8 | bytes[1]; if (exponent === 0x00) { return sign * (2 ** (-14)) * (0 + (fraction / 1024)); } else if (exponent === 0xff) { return null; //infinity } else { return sign * (2 ** (exponent - bias) ) * (1 + (fraction / 1024)); } } // 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 Decode(fPort, bytes, variables) { //获取uplink消息类型 var uplink_type = ((bytes[0] >> 4) & 0x0F); switch (uplink_type) { case 0x01: var Register_Msg = Register_proc(bytes); return Register_Msg; break; case 0x02: var Heartbeat_Msg = Heartbeat_proc(bytes); return Heartbeat_Msg; break; case 0x03: var PeriodicalPposition_Msg = PeriodicalPosition_proc(bytes); return PeriodicalPposition_Msg; break; case 0x04: var OnDemandPosition_Msg = OnDemandPosition_proc(bytes); return OnDemandPosition_Msg; break; case 0x05: var HistoryPositon_Msg = HistoryPosition_proc(bytes); return HistoryPositon_Msg; break; case 0x06: var Alarm_Msg = Alarm_proc(bytes); return Alarm_Msg; break; case 0x07: var BleCoordinate_Msg = BleCoordinate_proc(bytes); return BleCoordinate_Msg; break; case 0x08: var Acknowledge_Msg = Acknowledge_proc(bytes); return Acknowledge_Msg; break; default: return null; break; } } //Message type: Register 0x1 function Register_proc(bytes) { var Register_Msg = { "type": 0, "adr": 0, "mode": 0, "smode": 0, "BleTxPower": 0, "dr": 0, "breakpoint": 0, "selfadapt": 0, "oneoff": 0, "alreport": 0, "pos": 0, "hb": 0, "crc": 0 }; //type Register_Msg.type = "Register"; //adr Register_Msg.adr = ((bytes[0] >> 3) & 0x01); switch (Register_Msg.adr) { case 0x00: Register_Msg.adr = "OFF"; break; case 0x01: Register_Msg.adr = "ON"; break; default: break; } //mode Register_Msg.mode = (bytes[0] & 0x07); switch (Register_Msg.mode) { case 0x01: Register_Msg.mode = "AU920"; break; case 0x02: Register_Msg.mode = "CLAA"; break; case 0x03: Register_Msg.mode = "CN470"; break; case 0x04: Register_Msg.mode = "AS923"; break; case 0x05: Register_Msg.mode = "EU433"; break; case 0x06: Register_Msg.mode = "EU868"; break; case 0x07: Register_Msg.mode = "US915"; break; default: break; } //smode Register_Msg.smode = bytes[1]; switch (Register_Msg.smode) { case 0x01: Register_Msg.smode = "AU920"; break; case 0x02: Register_Msg.smode = "CLAA"; break; case 0x04: Register_Msg.smode = "CN470"; break; case 0x08: Register_Msg.smode = "AS923"; break; case 0x10: Register_Msg.smode = "EU433"; break; case 0x20: Register_Msg.smode = "EU868"; break; case 0x40: Register_Msg.smode = "US915"; break; default: break; } //BleTxPower Register_Msg.BleTxPower = { value: ((bytes[2] >> 3) & 0x1F), unit: "dBm" }; //Register_Msg.rfu1 = (bytes[2] & 0x07); if(Register_Msg.mode === "CLAA") { Register_Msg.frequencysweepmode = (bytes[2] & 0x07); if(Register_Msg.frequencysweepmode === 0x01) { Register_Msg.frequencysweepmode = "A mode"; } else if(Register_Msg.frequencysweepmode === 0x02) { Register_Msg.frequencysweepmode = "B mode"; } else if(Register_Msg.frequencysweepmode === 0x03) { Register_Msg.frequencysweepmode = "C mode"; } else if(Register_Msg.frequencysweepmode === 0x04) { Register_Msg.frequencysweepmode = "D mode"; } else if(Register_Msg.frequencysweepmode === 0x05) { Register_Msg.frequencysweepmode = "E mode"; } else if(Register_Msg.frequencysweepmode === 0x06) { Register_Msg.frequencysweepmode = "All frequency sweep"; } } //DR Register_Msg.dr = `DR${((bytes[3] >> 4) & 0x0F)}`; //breakpoint Register_Msg.breakpoint = ((bytes[3] >> 3) & 0x01); switch (Register_Msg.breakpoint) { case 0x00: Register_Msg.breakpoint = "Disable"; break; case 0x01: Register_Msg.breakpoint = "Enable"; break; default: break; } //selfadapt Register_Msg.selfadapt = ((bytes[3] >> 2) & 0x01); switch (Register_Msg.selfadapt) { case 0x00: Register_Msg.selfadapt = "Disable"; break; case 0x01: Register_Msg.selfadapt = "Enable"; break; default: break; } //oneoff Register_Msg.oneoff = ((bytes[3] >> 1) & 0x01); switch (Register_Msg.oneoff) { case 0x00: Register_Msg.oneoff = "Disable"; break; case 0x01: Register_Msg.oneoff = "Enable"; break; default: break; } //alreport Register_Msg.alreport = (bytes[3] & 0x01); switch (Register_Msg.alreport) { case 0x00: Register_Msg.alreport = "Disable"; break; case 0x01: Register_Msg.alreport = "Enable"; break; default: break; } //pos Register_Msg.pos = { value: ((((bytes[4] << 8) & 0xFF00) | (bytes[5] & 0xFF))*5), unit: "sec" }; //HB Register_Msg.hb = { value: (bytes[6]*30), unit: "sec" }; //crc Register_Msg.crc = (((bytes[7] << 8) & 0xFF00) | (bytes[8] &0xFF)); return Register_Msg; } //Message type: Heartbeat 0x2 function Heartbeat_proc(bytes) { var Heartbeat_Msg = { "type":0, "ver":0, "vol":0, "rssi":0, "snr":0, "gpsstate":0, "vibstate":0, "chgstate":0, "crc":0 }; //type Heartbeat_Msg.type = "Heartbeat"; //ver Heartbeat_Msg.ver = (bytes[0] & 0x0F); //vol Heartbeat_Msg.vol = { value: bytes[1], unit: "%" }; //rssi Heartbeat_Msg.rssi = { value: bytes[2] * (-1), unit: "dBm" }; //SNR let snr = (((bytes[3] << 8) & 0xFF00) | (bytes[4] & 0xFF)); snr = snr > 0x7fff ? snr - 0x10000 : snr; Heartbeat_Msg.snr = { value: snr * (0.01),//(((((bytes[3] << 8) & 0xFF00) | (bytes[4] & 0xFF)) & 0xffff )*(0.01)), unit: "dB" }; //GPSSTATE Heartbeat_Msg.gpsstate = ((bytes[5] >> 4) & 0x0F); switch (Heartbeat_Msg.gpsstate) { case 0x00: Heartbeat_Msg.gpsstate = "off"; break; case 0x01: Heartbeat_Msg.gpsstate = "boot GPS"; break; case 0x02: Heartbeat_Msg.gpsstate = "locating"; break; case 0x03: Heartbeat_Msg.gpsstate = "located"; break; case 0x09: Heartbeat_Msg.gpsstate = "no signal"; break; default: break; } //vibstate Heartbeat_Msg.vibstate = { value: (bytes[5] & 0x0F), unit: "level" }; //chgstate Heartbeat_Msg.chgstate = ((bytes[6] >> 4) & 0x0F); switch (Heartbeat_Msg.chgstate) { case 0x00: Heartbeat_Msg.chgstate = "power cable disconnected"; break; case 0x05: Heartbeat_Msg.chgstate = "power cable connected, charging"; break; case 0x06: Heartbeat_Msg.chgstate = "power cable connected, charge complete"; break; default: break; } //crc Heartbeat_Msg.crc = (((bytes[7] << 8) & 0xFF00) | (bytes[8] & 0xFF)); return Heartbeat_Msg; } //Message type: PeriodicalPosition 0x03 function PeriodicalPosition_proc(bytes) { var PeriodicalPposition_Msg = { "type":0, "longitude":0, "latitude":0, "time":0, "location":0, }; //type PeriodicalPposition_Msg.type = "PeriodicalPosition"; //longitude let lng = bytes.readFloatBE(1); //(((bytes[1] << 24) & 0xFF000000) | ((bytes[2] << 16) & 0xFF0000) | ((bytes[3] << 8) & 0xFF00) | (bytes[4] & 0xFF)); // lng = lng > 0x7fffffff ? lng - 0x100000000 : lng; // 0x94B62E00 (-180) to 0x6B49D200 (180) PeriodicalPposition_Msg.longitude = { value: lng,//bytes.readFloatBE(1), unit: "°" }; //latitude let lat = bytes.readFloatBE(5); //(((bytes[5] << 24) & 0xFF000000) | ((bytes[6] << 16) & 0xFF0000) | ((bytes[7] << 8) & 0xFF00) | (bytes[8] & 0xFF)); // lat = lat > 0x7fffffff ? lat - 0x100000000 : lat; // 0xCA5B1700 (-90) to 0x35A4E900 (90) PeriodicalPposition_Msg.latitude = { value: lat, //bytes.readFloatBE(5), //lat / 10000000, unit: "°" }; //time PeriodicalPposition_Msg.time = { value: (((bytes[9] << 24) & 0xFF000000) | ((bytes[10] << 16) & 0xFF0000) | ((bytes[11] << 8) & 0xFF00) | (bytes[12] & 0xFF)), unit: "sec" }; PeriodicalPposition_Msg.location = { value: `${lat},${lng}`, location: { lat: lat, lng: lng, } } return PeriodicalPposition_Msg; } //Message type: OnDemandPosition 0x04 function OnDemandPosition_proc(bytes) { var OnDemandPosition_Msg = { "type":0, "msgid":0, "longitude":0, "latitude":0, "location":0, "time":0, }; //type OnDemandPosition_Msg.type = "OnDemandPosition"; //magid OnDemandPosition_Msg.msgid = bytes[1]; //longitude let lng = bytes.readFloatBE(2); //(((bytes[2] <<24) & 0xFF000000) | ((bytes[3] << 16) & 0xFF0000) | ((bytes[4] << 8) & 0xFF00) | (bytes[5] & 0xFF)); //lng = lng > 0x7fffffff ? lng - 0x100000000 : lng; // 0x94B62E00 (-180) to 0x6B49D200 (180) OnDemandPosition_Msg.longitude = { value: lng, //lng / 10000000, unit: "°", }; //latitude let lat = bytes.readFloatBE(6); //(((bytes[6] <<24) & 0xFF000000) | ((bytes[7] << 16) & 0xFF0000) | ((bytes[8] << 8) & 0xFF00) | (bytes[9] & 0xFF)); //lat = lat > 0x7fffffff ? lat - 0x100000000 : lat; // 0xCA5B1700 (-90) to 0x35A4E900 (90) OnDemandPosition_Msg.latitude = { value: lat, //lat / 10000000, unit: "°", }; //time OnDemandPosition_Msg.time = { value: (((bytes[10] <<24) & 0xFF000000) | ((bytes[11] << 16) & 0xFF0000) | ((bytes[12] << 8) & 0xFF00) | (bytes[13] & 0xFF)), unit: "sec", }; OnDemandPosition_Msg.location = { value: `${lat},${lng}`, location: { lat: lat, lng: lng, } } return OnDemandPosition_Msg; } //Message type: HistoryPosition 0x05 function HistoryPosition_proc(bytes) { var HistoryPositon_Msg = { "type":0, "length":0, "longitude":0, "latitude":0, "location":0, "time":0, // "lonoff":0, // "latoff":0, // "toff":0 }; //type HistoryPositon_Msg.type = "HistoryPosition"; //length HistoryPositon_Msg.length = (bytes[0] & 0x0F); //longitude let lng = bytes.readFloatBE(1); //(((bytes[1] <<24) & 0xFF000000) | ((bytes[2] << 16) & 0xFF0000) | ((bytes[3] << 8) & 0xFF00) | (bytes[4] & 0xFF)); // lng = lng > 0x7fffffff ? lng - 0x100000000 : lng; // 0x94B62E00 (-180) to 0x6B49D200 (180) HistoryPositon_Msg.longitude = { value: lng, // / 10000000, unit: "°" }; //latitude let lat = bytes.readFloatBE(5); //(((bytes[5] <<24) & 0xFF000000) | ((bytes[6] << 16) & 0xFF0000) | ((bytes[7] << 8) & 0xFF00) | (bytes[8] & 0xFF)); //lat = lat > 0x7fffffff ? lat - 0x100000000 : lat; HistoryPositon_Msg.latitude = { value: lat, // / 10000000, unit: "°", }; //location HistoryPositon_Msg.location = { value: `${lat},${lng}`, location: { lat: lat, lng: lng, } } //time HistoryPositon_Msg.time = { value: (((bytes[9] <<24) & 0xFF000000) | ((bytes[10] << 16) & 0xFF0000) | ((bytes[11] << 8) & 0xFF00) | (bytes[12] & 0xFF)), unit: "sec", }; //It's P2P message, need to calcuate the real length. if (HistoryPositon_Msg.length === 0x0F) { return null; } else{ //Maximum 6 groups of history position if (HistoryPositon_Msg.length > 6) { return null; } for (var i = 0; i < HistoryPositon_Msg.length; i++) { var tmp = i+2; //console.log(bytes.slice(15+6*i,17+6*i),bytes.slice(13+6*i,15+6*i)); let lngoff = float16(bytes.slice(13+6*i, 15+6*i)); //float16(((bytes[13+6*i] << 8) & 0xFF00) | (bytes[14+6*i] & 0xFF)); //lngoff = lngoff > 0x7fff ? lngoff - 0x10000 : lngoff; HistoryPositon_Msg["pos"+tmp+"lngoff"] = { value: lngoff, // / 10000000, unit: "°", }; let latoff = float16(bytes.slice(15+6*i, 17+6*i)); //float16(((bytes[15+6*i] << 8) & 0xFF00) | (bytes[16+6*i] & 0xFF)); // latoff = latoff > 0x7fff ? latoff - 0x10000 : latoff; HistoryPositon_Msg["pos"+tmp+"latoff"] = { value: latoff, // / 10000000, unit: "°", }; HistoryPositon_Msg["pos"+tmp+"toff"] = { value: (((bytes[17+6*i] << 8) & 0xFF00) | (bytes[18+6*i] & 0xFF)), unit: "sec", }; } return HistoryPositon_Msg; } } //Message type: Alarm 0x06 function Alarm_proc(bytes) { var Alarm_Msg = { "type":0, "alarm":0, "msgid":0 }; //type Alarm_Msg.type = "Alarm"; //alarm Alarm_Msg.alarm = (bytes[0] & 0x0F); switch (Alarm_Msg.alarm) { case 0x1: Alarm_Msg.alarm = "sos" break; default: break; } //msgid Alarm_Msg.msgid = bytes[1]; return Alarm_Msg; } //Message type: BleCoordinate 0x07 function BleCoordinate_proc(bytes) { var BleCoordinate_Msg = { "type":0, "length":0, "move":0, // "name":0, }; BleCoordinate_Msg.type = "BleCoordinate"; BleCoordinate_Msg.length = (bytes[0] & 0x0F); BleCoordinate_Msg.move = bytes[1]; // BleCoordinate_Msg.rfu = ((bytes[2] << 24) & 0xFF000000) | ((bytes[3] << 16) & 0x00FF0000) | ((bytes[4] << 8) & 0x0000FF00) | (bytes[5] & 0x000000FF); for (var i = 0; i < BleCoordinate_Msg.length; i++) { BleCoordinate_Msg[`dev${i+1}major`] = (((bytes[6+5*i] << 8) & 0xFF00) | (bytes[7+5*i] & 0xFF)); BleCoordinate_Msg[`dev${i+1}minor`] = (((bytes[8+5*i] << 8) & 0xFF00) | (bytes[9+5*i] & 0xFF)); BleCoordinate_Msg[`dev${i+1}rssi`] = { value: bytes[10+5*i] - 256, unit: "dBm" }; } return BleCoordinate_Msg; } //Message type: Acknowledge 0x08 function Acknowledge_proc(bytes) { var Acknowledge_Msg = { "type":0, "result":0, "msgid":0 }; Acknowledge_Msg.type = "Acknowledge"; Acknowledge_Msg.result = (bytes[0] & 0x0F); switch (Acknowledge_Msg.result) { case 0x00: Acknowledge_Msg.result = "success"; break; case 0x01: Acknowledge_Msg.result = "failure"; break; default: break; } Acknowledge_Msg.msgid = bytes[1]; return Acknowledge_Msg; } var ignore_vars = []; function toTagoFormat(object_item, serie, prefix = '') { const result = []; for (const key in object_item) { if (ignore_vars.includes(key)) continue; if (typeof object_item[key] === 'object') { result.push({ variable: object_item[key].variable || `${prefix}${key}`, value: object_item[key].value, serie: object_item[key].serie || serie, metadata: object_item[key].metadata, location: object_item[key].location, unit: object_item[key].unit, }); } else { result.push({ variable: `${prefix}${key}`, value: object_item[key], serie, }); } } return result; } // let payload = [{ variable: "payload", value: "3042ed8a9c41ffce2f60742681" }]; //this is for type 1 // let payload = [{ variable: "payload", value: "1101702f00030a0000" }]; //this is for type 1 //let payload = [{ variable: "payload", value: "215f5ff44810500000" }]; // snr -30 for type 2 //let payload = [{ variable: "payload", value: "215f5f0bb810500000" }]; // snr 30 for type 2 // let payload = [{ variable: "payload", value: "3094b62e0035a4e900605b92a7" }]; // negative lng positive lat for type 3 // let payload = [{ variable: "payload", value: "40016b49d200ca5b1700605b92a7" }]; // positive lng negative lat for type 4 // let payload = [{ variable: "payload", value: "5142ed8a9c41ffce2f605b92a7000103ff000f" }]; // positive lng negative lat for type 5 // let payload = [{ variable: "payload", value: "7100000000000005000348" }]; // type 7 const data = payload.find((x) => x.variable === "payload_raw" || x.variable === "payload" || x.variable === "data"); const port = payload.find((x) => x.variable === "fport" || x.variable === "port"); if (data) { const buffer = Buffer.from(data.value, "hex"); // console.log(buffer); const serie = new Date().getTime(); payload = payload.concat(toTagoFormat(Decode(port, buffer), serie)); //payload = payload.map((x) => ({ ...x, serie })); } // console.log(payload);

This codec is sourced from TagoIO Github. All rights belong to TagoIO Github.

This codec is licensed under the GNU General Public License v3 (GPL v3). Modifications, if any, are clearly marked. You are free to use, modify, and distribute the codec under the terms of GPL v3.

Community Feedback