UNPKG

@kaaiot/node-red-contrib-kaa

Version:
645 lines (543 loc) 21.5 kB
// https://wiki.teltonika-gps.com/view/Codec#Codec_8_Extended function Processor() { var self = this; this.process = function(data) { if (data.length == 0) { throw new Error("Empty data"); } var parsedMsg = new Parser(data).parse(); console.log("Parsed message: " + JSON.stringify(parsedMsg)); var messages = []; for (var i = 0; i < parsedMsg.avl.length; i++) { var message = new AVLIODataParser().parse(parsedMsg.avl[i]); console.log("AVL message: " + JSON.stringify(message)); messages.push(message); } return { messages: messages, parsedMsg: parsedMsg }; }; this.format = function(msg) { var result = {}; // Coolant Temperature if (msg.obdCoolantTemperature !== undefined) { result.obdCoolantTemperature = msg.obdCoolantTemperature; result.obdCoolantTemperatureValid = 1; } else { result.obdCoolantTemperature = 0; result.obdCoolantTemperatureValid = 0; } // GSM signal result.gsmSignal = msg.gsmSignal; // battery if (msg.externalVoltage !== undefined) { result.externalVoltage = msg.externalVoltage / 1000; result.externalVoltageValid = 1; } else { result.externalVoltage = 0; result.externalVoltageValid = 0; } // GPS coordinates if (msg.location !== undefined) { result.lat = msg.location.lat; result.lon = msg.location.lon; result.locationValid = 1; } else { result.locationValid = 0; } return result; } }; class Parser { constructor(data) { this.inputMsg = data; this.inputDataPtr = 0; } parse() { return this.parseAVLfull(); } //********************************************************************************************** // parseAVLfull //********************************************************************************************** parseAVLfull() { var parsedMsg = {}; parsedMsg.avl = []; // get packet length parsedMsg.fullPacketLength = this.getNextInt16(); // get packet ID parsedMsg.packetId = this.getNextInt16(); // unused byte this.getNextInt8(); // get AVL packet ID, IMEI, codec ID parsedMsg.avlPacketId = this.getNextInt8(); // IMEI length & IMEI var imeiLength = this.getNextInt16(); if (imeiLength != 15) { throw new Error("Wrong imei length: " + imeiLength); } parsedMsg.moduleIMEI = this.toImeiString(this.getNextSubArray(imeiLength)); // AVL Data array // AVL codec ID parsedMsg.codecId = this.getNextInt8(); if (parsedMsg.codecId != 0x8E) { throw new Error("Wrong codecId: " + parsedMsg.codecId); } // AVL number of data parsedMsg.numberOfData = this.getNextInt8(); // payload start for (var i = 0; i < parsedMsg.numberOfData; i++) { var avl = this.parseAVLpacketDataArrayElement(parsedMsg); parsedMsg.avl.push(avl); } // read AVL packets parsedMsg.numberOfRecords = this.getNextInt8(); return parsedMsg; } //********************************************************************************************** // toImeiString //********************************************************************************************** toImeiString(IMEIarray) { var result = ""; for (var i = 0; i < IMEIarray.length; i++) { result += String.fromCharCode(IMEIarray[i]); } return result; } //********************************************************************************************** // parseAVLpacketDataArrayElement //********************************************************************************************** parseAVLpacketDataArrayElement(parsedMsg) { var avl = {}; avl.timestamp = this.getTimestamp(); avl.priority = this.getNextInt8(); avl.GPS = this.parseGPSelement(); this.parseIOelement(parsedMsg, avl); return avl; } //********************************************************************************************** // parseAVLpacket //********************************************************************************************** getTimestamp() { var timestampArray = this.getNextSubArray(8); var value = 0; for (var i = 0; i < timestampArray.length; i++) { value = (value * 256) + timestampArray[i]; } return value; } //********************************************************************************************** // parseGPSelement //********************************************************************************************** parseGPSelement() { var GPS = {}; GPS.longitude = this.getCoordinate(this.getNextSubArray(4)); GPS.latitude = this.getCoordinate(this.getNextSubArray(4)); GPS.altitude = this.getNextInt16(); GPS.angle = this.getNextInt16(); GPS.satellites = this.getNextInt8(); GPS.speed = this.getNextInt16(); return GPS; } //********************************************************************************************** // getCoordinate //********************************************************************************************** getCoordinate(array) { var value = 0; if (array[0] > 127) { //negative value = (array[0] << 24) + (array[1] << 16) + (array[2] << 8) + array[3]; value -= parseInt("ffffffff", 16); } else { //positive value = (array[0] << 24) + (array[1] << 16) + (array[2] << 8) + array[3]; } return value / 10000000; } //********************************************************************************************** // parseIOelement //********************************************************************************************** parseIOelement(parsedMsg, avl) { avl.eventIoID = this.getNextInt16(); //if (avl.eventIoID == 385) { // parseBeacon(); // getNextInt8(); //} else { this.parseUsualIOelements(parsedMsg, avl); this.decodeUsualIOelements(avl); //} } //********************************************************************************************** // parseBeacon //********************************************************************************************** parseBeacon(array) { const BEACON_LENGTH = 20; const EDDY_LENGTH = 16; var avl = {}; avl.beaconLength = array.length; var ptr = 0; // dataPart avl.dataPart = array[ptr++]; avl.beaconRecordsCount = avl.dataPart & 0x0F; avl.recordNumber = (avl.dataPart & 0xF0) >> 4; if (avl.beaconLength < EDDY_LENGTH) { return avl; } // flags avl.flag = array[ptr++]; avl.sygnalStrenghAvailable = ((avl.flag & 0x01) > 0) ? 1 : 0; avl.beaconDataSent = ((avl.flag & 0x20) > 0) ? 1 : 0; // beacons if (avl.beaconDataSent != 0) { // beacon data avl.beaconId = array.slice(ptr, ptr + BEACON_LENGTH); ptr += BEACON_LENGTH; if (avl.sygnalStrenghAvailable != 0) { avl.BeaconRssi = array[ptr++]; } } return avl; } //********************************************************************************************** // parseUsualIOelements //********************************************************************************************** parseUsualIOelements(parsedMsg, avl) { avl.nTotalIo = this.getNextInt16(); avl.n1Io = this.getNextInt16(); avl.ioData = new Map(); var i = 0; for (i = 0; i < avl.n1Io; i++) { var n1IoId = this.getNextInt16(); var n1IoValue = this.getNextInt8(); if (n1IoValue >= 128) { n1IoValue = n1IoValue - 256; } avl.ioData.set(n1IoId, n1IoValue); } if (this.inputDataPtr >= parsedMsg.fullPacketLength) { return [null, null]; } avl.n2Io = this.getNextInt16(); for (i = 0; i < avl.n2Io; i++) { var n2IoId = this.getNextInt16(); var n2IoValue = this.getNextInt16(); if (n2IoValue >= 0x8000) { n2IoValue = n2IoValue - 0x8000; } avl.ioData.set(n2IoId, n2IoValue); } if (this.inputDataPtr >= parsedMsg.fullPacketLength) { return [null, null]; } avl.n4Io = this.getNextInt16(); for (i = 0; i < avl.n4Io; i++) { var n4IoId = this.getNextInt16(); var n4IoValue = this.getNextInt32(); if (n4IoValue >= 0x80000000) { n4IoValue = n4IoValue - 0x80000000; } avl.ioData.set(n4IoId, n4IoValue); } if (this.inputDataPtr >= parsedMsg.fullPacketLength) { return [null, null]; } avl.n8Io = this.getNextInt16(); for (i = 0; i < avl.n8Io; i++) { var n8IoId = this.getNextInt16(); //var n8IoSubArray = getNextSubArray(8); var n8IoValue = this.getNextInt64(); if (n8IoValue >= 0x8000000000000000) { n8IoValue = n8IoValue - 0x8000000000000000; } //node.warn(n8IoValue); avl.ioData.set(n8IoId, n8IoValue); } avl.nxIo = this.getNextInt16(); for (i = 0; i < avl.nxIo; i++) { var nxIoId = this.getNextInt16(); var nxIoLength = this.getNextInt16(); if (nxIoId == 385) { avl.ioData.set(nxIoId, this.parseBeacon(getNextSubArray(nxIoLength))); } else { avl.ioData.set(nxIoId, this.getNextSubArray(nxIoLength)); } } } //********************************************************************************************** // decodeUsualIOelements //********************************************************************************************** decodeUsualIOelements(avl) { avl.axis = {}; avl.axis.x = avl.ioData.get(17); avl.axis.y = avl.ioData.get(18); avl.axis.z = avl.ioData.get(19); } //********************************************************************************************** // getCharArray //********************************************************************************************** getCharArray(array) { const result = []; for (var i = 0; i < array.length; i++) { result.push(String.fromCharCode(array[i])); } return result; } //********************************************************************************************** // getNextSubArray //********************************************************************************************** getNextSubArray(length) { var subarray = this.inputMsg.slice(this.inputDataPtr, this.inputDataPtr + length); this.inputDataPtr += length; return subarray; } //********************************************************************************************** // getNextInt8 //********************************************************************************************** getNextInt8() { return this.inputMsg[this.inputDataPtr++]; } //********************************************************************************************** // getNextInt16 //********************************************************************************************** getNextInt16() { var value = this.inputMsg[this.inputDataPtr++]; value = (value << 8) + this.inputMsg[this.inputDataPtr++]; return value; } //********************************************************************************************** // getNextInt32 //********************************************************************************************** getNextInt32() { var value = this.inputMsg[this.inputDataPtr++]; value = (value << 8) + this.inputMsg[this.inputDataPtr++]; value = (value << 8) + this.inputMsg[this.inputDataPtr++]; value = (value << 8) + this.inputMsg[this.inputDataPtr++]; return value; } //********************************************************************************************** // getNextInt64 //********************************************************************************************** getNextInt64() { var value = this.inputMsg[this.inputDataPtr++]; value = (value << 8) + this.inputMsg[this.inputDataPtr++]; value = (value << 8) + this.inputMsg[this.inputDataPtr++]; value = (value << 8) + this.inputMsg[this.inputDataPtr++]; value = (value << 8) + this.inputMsg[this.inputDataPtr++]; value = (value << 8) + this.inputMsg[this.inputDataPtr++]; value = (value << 8) + this.inputMsg[this.inputDataPtr++]; value = (value << 8) + this.inputMsg[this.inputDataPtr++]; return value; } //********************************************************************************************** // Calculates the buffers CRC-16/IBM. //********************************************************************************************** crc16(buffer, startPtr, length) { var crc = 0; var odd; for (var i = 0; i < length; i++) { crc = crc ^ buffer[i + startPtr]; var numBit = 0; do { odd = crc & 0x0001; crc = crc >> 1; if (odd == 1) { crc = crc ^ 0xA001; } numBit++; } while (numBit < 8); } return crc; }; }; class AVLIODataParser { parse(avl) { //********************************************************************************************** // getIoData // Get IO data with specified AVL ID //********************************************************************************************** var getIoData = function(id) { if (avl.ioData.get(id) != null) { return avl.ioData.get(id); } else { return avl.ioData.get(id.toString()); } } var payload = {}; payload.timestamp = avl.timestamp; payload.altitude = avl.GPS.altitude; payload.angle = avl.GPS.angle; payload.satellites = avl.GPS.satellites; payload.latitude = avl.GPS.latitude; payload.longitude = avl.GPS.longitude; if (avl.axis != undefined) { payload.axis_x = avl.axis.x; payload.axis_y = avl.axis.y; payload.axis_z = avl.axis.z; } // fuel Used GPS var fuelUsedGps = getIoData(12); if (fuelUsedGps != null) { payload.fuelUsedGps = fuelUsedGps; } // fuel Rate GPS var fuelRateGps = getIoData(13); if (fuelRateGps != null) { payload.fuelRateGps = fuelRateGps; } // total odometer var totalOdometer = getIoData(16); if (totalOdometer != null) { payload.totalOdometer = totalOdometer / 1000; } // gsmSignal var gsmSignal = getIoData(21); if (gsmSignal != null) { payload.gsmSignal = gsmSignal; } // speed var speed = getIoData(24); if (speed != null) { payload.speed = speed; } // obdDtcNumber var obdDtcNumber = getIoData(30); if (obdDtcNumber != null) { payload.obdDtcNumber = obdDtcNumber; } // obdEngineLoad var obdEngineLoad = getIoData(31); if (obdEngineLoad != null) { payload.obdEngineLoad = obdEngineLoad; } // obdCoolantTemperature var obdCoolantTemperature = getIoData(32); if (obdCoolantTemperature != null) { payload.obdCoolantTemperature = obdCoolantTemperature; } // obdShortFuelTrim var obdShortFuelTrim = getIoData(33); if (obdShortFuelTrim != null) { payload.obdShortFuelTrim = obdShortFuelTrim; } // obdFuelPressure var obdFuelPressure = getIoData(34); if (obdFuelPressure != null) { payload.obdFuelPressure = obdFuelPressure; } // obdIntakeMAP var obdIntakeMAP = getIoData(35); if (obdIntakeMAP != null) { payload.obdIntakeMAP = obdIntakeMAP; } // obdEngineRPM var obdEngineRPM = getIoData(36); if (obdEngineRPM != null) { payload.obdEngineRPM = obdEngineRPM; } // obdVehicleSpeed var obdVehicleSpeed = getIoData(37); if (obdVehicleSpeed != null) { payload.obdVehicleSpeed = obdVehicleSpeed; } // obdTimingAdvance var obdTimingAdvance = getIoData(38); if (obdTimingAdvance != null) { payload.obdTimingAdvance = obdTimingAdvance; } // obdIntakeAirTemperature var obdIntakeAirTemperature = getIoData(39); if (obdIntakeAirTemperature != null) { payload.obdIntakeAirTemperature = obdIntakeAirTemperature; } // obdThrottlePosition var obdThrottlePosition = getIoData(41); if (obdThrottlePosition != null) { payload.obdThrottlePosition = obdThrottlePosition; } // obdDistanceTraveledMILon var obdDistanceTraveledMILon = getIoData(43); if (obdDistanceTraveledMILon != null) { payload.obdDistanceTraveledMILon = obdDistanceTraveledMILon; } // obdFuelLevel var obdFuelLevel = getIoData(48); if (obdFuelLevel != null) { payload.obdFuelLevel = obdFuelLevel; } else { payload.obdFuelLevel = 50; } // engineOilTemperature var engineOilTemperature = getIoData(58); if (engineOilTemperature != null) { payload.engineOilTemperature = engineOilTemperature; } // fuelRate var fuelRate = getIoData(60); if (fuelRate != null) { payload.fuelRate = fuelRate; } // externalVoltage var externalVoltage = getIoData(66); if (externalVoltage != null) { payload.externalVoltage = externalVoltage; } // batteryVoltage var batteryVoltage = getIoData(67); if (batteryVoltage != null) { payload.batteryVoltage = batteryVoltage; } // batteryCurrent var batteryCurrent = getIoData(68); if (batteryCurrent != null) { payload.batteryCurrent = batteryCurrent; } // gnssStatus var gnssStatus = getIoData(69); if (gnssStatus != null) { payload.gnssStatus = gnssStatus; } // batteryLevel var batteryLevel = getIoData(113); if (batteryLevel != null) { payload.batteryLevel = batteryLevel; } // tripOdometer var tripOdometer = getIoData(199); if (tripOdometer != null) { payload.tripOdometer = tripOdometer; } // gsmCellId var gsmCellId = getIoData(205); if (gsmCellId != null) { payload.gsmCellId = gsmCellId; } // gsmAreaCode var gsmAreaCode = getIoData(206); if (gsmAreaCode != null) { payload.gsmAreaCode = gsmAreaCode; } // ignition var ignition = getIoData(239); if (ignition != null) { payload.ignition = ignition; } // movement var movement = getIoData(240); if (movement != null) { payload.movement = movement; } // btStatus var btStatus = getIoData(263); if (btStatus != null) { payload.btStatus = btStatus; } // instantMovement var instantMovement = getIoData(303); if (instantMovement != null) { payload.instantMovement = instantMovement; } // obdOemTotalMileage var obdOemTotalMileage = getIoData(389); if (obdOemTotalMileage != null) { payload.obdOemTotalMileage = obdOemTotalMileage; } // obdOemFuelLevel var obdOemFuelLevel = getIoData(390); if (obdOemFuelLevel != null) { payload.obdOemFuelLevel = obdOemFuelLevel / 10; } else { payload.obdOemFuelLevel = 50; } return payload; } } module.exports.Processor = Processor;