From 44d8d13ad76a3b7b7615c08b2c83e9cf72bbfef5 Mon Sep 17 00:00:00 2001 From: Pavlo Anikeichyk <91755619+PavelAnikeichyk@users.noreply.github.com> Date: Thu, 8 May 2025 20:59:42 +0300 Subject: [PATCH 1/2] Fixed node-red-teltonika-tcp-flow.json --- .../code/node-red-teltonika-tcp-flow.json | 1136 ++++++++--------- 1 file changed, 568 insertions(+), 568 deletions(-) diff --git a/doc/Tutorials/device-integration/hardware-guides/connect-teltonika-to-kaa-platform/attach/code/node-red-teltonika-tcp-flow.json b/doc/Tutorials/device-integration/hardware-guides/connect-teltonika-to-kaa-platform/attach/code/node-red-teltonika-tcp-flow.json index f28f50eca7..4a6182c3f1 100644 --- a/doc/Tutorials/device-integration/hardware-guides/connect-teltonika-to-kaa-platform/attach/code/node-red-teltonika-tcp-flow.json +++ b/doc/Tutorials/device-integration/hardware-guides/connect-teltonika-to-kaa-platform/attach/code/node-red-teltonika-tcp-flow.json @@ -1,569 +1,569 @@ [ - { - "id": "bde2c7d9084e1fa9", - "type": "tab", - "label": "Teltonika_codec8ext TCP", - "disabled": false, - "info": "", - "env": [] - }, - { - "id": "f476063bdbda1a15", - "type": "debug", - "z": "bde2c7d9084e1fa9", - "name": "RAW data", - "active": false, - "tosidebar": true, - "console": false, - "tostatus": false, - "complete": "true", - "targetType": "full", - "statusVal": "", - "statusType": "auto", - "x": 420, - "y": 340, - "wires": [] - }, - { - "id": "fd727ce0c3c8ed4f", - "type": "function", - "z": "bde2c7d9084e1fa9", - "name": "Filter PING packet", - "func": "if (msg.payload.length == 1) {\n msg.payload = \"PING. \" + msg.ip + \":\" + msg.port;\n return [null, msg];\n}\n\nreturn [msg, null];", - "outputs": 2, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 210, - "y": 360, - "wires": [ - [ - "f476063bdbda1a15", - "d2b0d4148e870f54" - ], - [ - "0a4531912ab49b84" - ] - ] - }, - { - "id": "0a4531912ab49b84", - "type": "debug", - "z": "bde2c7d9084e1fa9", - "name": "PING packets", - "active": false, - "tosidebar": true, - "console": false, - "tostatus": false, - "complete": "payload", - "targetType": "msg", - "statusVal": "", - "statusType": "auto", - "x": 440, - "y": 380, - "wires": [] - }, - { - "id": "d2b0d4148e870f54", - "type": "function", - "z": "bde2c7d9084e1fa9", - "name": "PARSE codec8_ext TCP", - "func": "var inputMsg = msg.payload;\n\nvar inputDataPtr = 0;\nvar fullPacketLength = 0;\n\nvar parsedMsg = {};\nparsedMsg.avl = [];\nvar avl = {};\n\nparseAVLfull();\n\n// create TCP response\nvar tcpResponse = createTcpResponse(parsedMsg.numberOfData, msg._session);\n\nmsg.payload = parsedMsg;\n\nreturn [msg, tcpResponse]; // response\n\n//**********************************************************************************************\n// createTcpResponse\n//**********************************************************************************************\nfunction createTcpResponse(receivedDataCount, session) {\n var countHex = dec2Hex32(receivedDataCount);\n var tcpResponse = {};\n tcpResponse._session = session;\n tcpResponse.payload = new Buffer([Number(countHex.substring(6, 8)), Number(countHex.substring(4, 6)),\n Number(countHex.substring(2, 4)), Number(countHex.substring(0, 2))]);\n\n return tcpResponse;\n}\n\n//**********************************************************************************************\n// dec2Hex32\n//**********************************************************************************************\nfunction dec2Hex32(dec) {\n return Math.abs(dec).toString(32);\n}\n\n//**********************************************************************************************\n// parseAVLfull\n//**********************************************************************************************\nfunction parseAVLfull() {\n //preamble\n var preamble = getNextInt32();\n if (preamble != 0x00000000) {\n node.warn(\"Wrong preamble\");\n return [null, null];\n }\n\n // get packet length\n parsedMsg.fullPacketLength = getNextInt32();\n\n var calculatedCrc16 = crc16(inputMsg, inputDataPtr, (inputMsg.length - inputDataPtr - 4));\n\n // AVL codec ID\n parsedMsg.codecId = getNextInt8();\n if (parsedMsg.codecId != 0x8E) {\n node.warn(\"Wrong codecId: \" + parsedMsg.codecId);\n return [null, null];\n }\n\n // AVL number of data\n parsedMsg.numberOfData = getNextInt8();\n\n // AVL Data array \n\n for (var i = 0; i < parsedMsg.numberOfData; i++) {\n parseAVLpacketDataArrayElement();\n }\n\n parsedMsg.numberOfRecords = getNextInt8();\n\n if (parsedMsg.numberOfData != parsedMsg.numberOfRecords) {\n node.warn(\"numberOfData1 not equals numberOfData2\");\n return [null, null];\n }\n\n parsedMsg.crc16 = getNextInt32();\n if (calculatedCrc16 != parsedMsg.crc16) {\n node.warn(\"Wrong crc16.\");\n return [null, null];\n }\n}\n\n//**********************************************************************************************\n// parseAVLpacketDataArrayElement\n//**********************************************************************************************\nfunction parseAVLpacketDataArrayElement() {\n avl = {};\n avl.timestamp = getTimestamp();\n avl.priority = getNextInt8();\n avl.GPS = parseGPSelement();\n parseIOelement();\n parsedMsg.avl.push(avl);\n}\n\n//**********************************************************************************************\n// parseAVLpacket\n//**********************************************************************************************\nfunction getTimestamp() {\n var timestampArray = getNextSubArray(8);\n var value = 0;\n for (var i = 0; i < timestampArray.length; i++) {\n value = (value * 256) + timestampArray[i];\n }\n return value;\n}\n\n//**********************************************************************************************\n// parseGPSelement\n//**********************************************************************************************\nfunction parseGPSelement() {\n var GPS = {};\n GPS.longitude = getCoordinate(getNextSubArray(4));\n GPS.latitude = getCoordinate(getNextSubArray(4));\n GPS.altitude = getNextInt16();\n GPS.angle = getNextInt16();\n GPS.satellites = getNextInt8();\n GPS.speed = getNextInt16();\n\n return GPS;\n}\n\n//**********************************************************************************************\n// getCoordinate\n//**********************************************************************************************\nfunction getCoordinate(array) {\n var value = 0;\n if (array[0] > 127) { //negative\n value = (array[0] << 24) + (array[1] << 16) + (array[2] << 8) + array[3];\n value -= parseInt(\"ffffffff\", 16);\n } else { //positive\n value = (array[0] << 24) + (array[1] << 16) + (array[2] << 8) + array[3];\n }\n return value / 10000000;\n}\n\n//**********************************************************************************************\n// parseIOelement\n//**********************************************************************************************\nfunction parseIOelement() {\n avl.eventIoID = getNextInt16();\n\n //if (avl.eventIoID == 385) {\n // parseBeacon();\n // getNextInt8();\n //} else {\n parseUsualIOelements();\n decodeUsualIOelements();\n //}\n}\n\n//**********************************************************************************************\n// parseBeacon\n//**********************************************************************************************\nfunction parseBeacon(array) {\n const BEACON_LENGTH = 20;\n const EDDY_LENGTH = 16;\n\n var avl = {};\n\n avl.beaconLength = array.length;\n\n var ptr = 0;\n\n // dataPart\n avl.dataPart = array[ptr++];\n avl.beaconRecordsCount = avl.dataPart & 0x0F;\n avl.recordNumber = (avl.dataPart & 0xF0) >> 4;\n\n if (avl.beaconLength < EDDY_LENGTH) {\n return avl;\n }\n\n // flags\n avl.flag = array[ptr++];\n avl.sygnalStrenghAvailable = ((avl.flag & 0x01) > 0) ? 1 : 0;\n avl.beaconDataSent = ((avl.flag & 0x20) > 0) ? 1 : 0;\n\n // beacons\n if (avl.beaconDataSent != 0) {\n // beacon data\n avl.beaconId = array.slice(ptr, ptr + BEACON_LENGTH);\n ptr += BEACON_LENGTH;\n if (avl.sygnalStrenghAvailable != 0) {\n avl.BeaconRssi = array[ptr++];\n }\n }\n\n return avl;\n}\n\n//**********************************************************************************************\n// parseUsualIOelements\n//**********************************************************************************************\nfunction parseUsualIOelements() {\n avl.nTotalIo = getNextInt16();\n avl.n1Io = getNextInt16();\n avl.ioData = new Map();\n var i = 0;\n for (i = 0; i < avl.n1Io; i++) {\n var n1IoId = getNextInt16();\n var n1IoValue = getNextInt8();\n if (n1IoValue >= 128) {\n n1IoValue = n1IoValue - 256;\n }\n avl.ioData.set(n1IoId, n1IoValue);\n }\n\n if (inputDataPtr >= parsedMsg.fullPacketLength) { return [null, null]; }\n avl.n2Io = getNextInt16();\n for (i = 0; i < avl.n2Io; i++) {\n var n2IoId = getNextInt16();\n var n2IoValue = getNextInt16();\n if (n2IoValue >= 0x8000) {\n n2IoValue = n2IoValue - 0x8000;\n }\n avl.ioData.set(n2IoId, n2IoValue);\n }\n\n if (inputDataPtr >= parsedMsg.fullPacketLength) { return [null, null]; }\n avl.n4Io = getNextInt16();\n for (i = 0; i < avl.n4Io; i++) {\n var n4IoId = getNextInt16();\n var n4IoValue = getNextInt32();\n if (n4IoValue >= 0x80000000) {\n n4IoValue = n4IoValue - 0x80000000;\n }\n avl.ioData.set(n4IoId, n4IoValue);\n }\n\n if (inputDataPtr >= parsedMsg.fullPacketLength) { return [null, null]; }\n avl.n8Io = getNextInt16();\n for (i = 0; i < avl.n8Io; i++) {\n var n8IoId = getNextInt16();\n //var n8IoSubArray = getNextSubArray(8);\n var n8IoValue = getNextInt64();\n if (n8IoValue >= 0x8000000000000000) {\n n8IoValue = n8IoValue - 0x8000000000000000;\n }\n //node.warn(n8IoValue);\n avl.ioData.set(n8IoId, n8IoValue);\n }\n avl.nxIo = getNextInt16();\n for (i = 0; i < avl.nxIo; i++) {\n var nxIoId = getNextInt16();\n var nxIoLength = getNextInt16();\n if (nxIoId == 385) {\n avl.ioData.set(nxIoId, parseBeacon(getNextSubArray(nxIoLength)));\n } else {\n avl.ioData.set(nxIoId, getNextSubArray(nxIoLength));\n }\n }\n}\n\n//**********************************************************************************************\n// decodeUsualIOelements\n//**********************************************************************************************\nfunction decodeUsualIOelements() {\n avl.axis = {};\n avl.axis.x = avl.ioData.get(17);\n avl.axis.y = avl.ioData.get(18);\n avl.axis.z = avl.ioData.get(19);\n}\n\n//**********************************************************************************************\n// getCharArray\n//**********************************************************************************************\nfunction getCharArray(array) {\n const result = [];\n for (var i = 0; i < array.length; i++) {\n result.push(String.fromCharCode(array[i]));\n }\n return result;\n}\n\n//**********************************************************************************************\n// getNextSubArray\n//**********************************************************************************************\nfunction getNextSubArray(length) {\n var subarray = inputMsg.slice(inputDataPtr, inputDataPtr + length);\n inputDataPtr += length;\n return subarray;\n}\n\n//**********************************************************************************************\n// getNextInt8\n//**********************************************************************************************\nfunction getNextInt8() {\n return inputMsg[inputDataPtr++];\n}\n\n//**********************************************************************************************\n// getNextInt16\n//**********************************************************************************************\nfunction getNextInt16() {\n var value = inputMsg[inputDataPtr++];\n value = (value << 8) + inputMsg[inputDataPtr++];\n return value;\n}\n\n//**********************************************************************************************\n// getNextInt32\n//**********************************************************************************************\nfunction getNextInt32() {\n var value = inputMsg[inputDataPtr++];\n value = (value << 8) + inputMsg[inputDataPtr++];\n value = (value << 8) + inputMsg[inputDataPtr++];\n value = (value << 8) + inputMsg[inputDataPtr++];\n return value;\n}\n\n//**********************************************************************************************\n// getNextInt64\n//**********************************************************************************************\nfunction getNextInt64() {\n var value = inputMsg[inputDataPtr++];\n value = (value << 8) + inputMsg[inputDataPtr++];\n value = (value << 8) + inputMsg[inputDataPtr++];\n value = (value << 8) + inputMsg[inputDataPtr++];\n value = (value << 8) + inputMsg[inputDataPtr++];\n value = (value << 8) + inputMsg[inputDataPtr++];\n value = (value << 8) + inputMsg[inputDataPtr++];\n value = (value << 8) + inputMsg[inputDataPtr++];\n return value;\n}\n\n//**********************************************************************************************\n// Calculates the buffers CRC-16/IBM.\n//**********************************************************************************************\nfunction crc16(buffer, startPtr, length) {\n var crc = 0;\n var odd;\n\n for (var i = 0; i < length; i++) {\n crc = crc ^ buffer[i + startPtr];\n\n var numBit = 0;\n do {\n odd = crc & 0x0001;\n crc = crc >> 1;\n if (odd == 1) {\n crc = crc ^ 0xA001;\n }\n numBit++;\n } while (numBit < 8);\n }\n\n return crc;\n};", - "outputs": 2, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 290, - "y": 260, - "wires": [ - [ - "0e7ef225e445c758", - "18b3dfde097451d1" - ], - [ - "63b71825da12406c", - "3d65e2931542de30" - ] - ] - }, - { - "id": "0e7ef225e445c758", - "type": "debug", - "z": "bde2c7d9084e1fa9", - "name": "PARSED data", - "active": true, - "tosidebar": true, - "console": false, - "tostatus": false, - "complete": "true", - "targetType": "full", - "statusVal": "", - "statusType": "auto", - "x": 520, - "y": 240, - "wires": [] - }, - { - "id": "e54797cf40844cf2", - "type": "inject", - "z": "bde2c7d9084e1fa9", - "name": "Trigger", - "props": [ - { - "p": "payload" - }, - { - "p": "topic", - "vt": "str" - } - ], - "repeat": "", - "crontab": "", - "once": true, - "onceDelay": "", - "topic": "", - "payload": "", - "payloadType": "date", - "x": 140, - "y": 100, - "wires": [ - [ - "ed4c731ecb5921bf" - ] - ] - }, - { - "id": "cb562ce75e8f1d6a", - "type": "function", - "z": "bde2c7d9084e1fa9", - "name": "USER config", - "func": "/*\n Fill before using:\n - application version\n*/\n\nconst TRACKER_APP_VERSION = \"chfq5afsj3ic738hqpd0-v1\";\nflow.set(\"TRACKER_APP_VERSION\", TRACKER_APP_VERSION);\n\nreturn msg;", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 530, - "y": 100, - "wires": [ - [] - ] - }, - { - "id": "ed4c731ecb5921bf", - "type": "function", - "z": "bde2c7d9084e1fa9", - "name": "INIT flow context", - "func": "const tcpSessions = new Map();\nflow.set(\"TCP_SESSIONS\", tcpSessions);\n\nreturn msg;", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 330, - "y": 100, - "wires": [ - [ - "cb562ce75e8f1d6a" - ] - ] - }, - { - "id": "fabe947dd3edbd38", - "type": "comment", - "z": "bde2c7d9084e1fa9", - "name": "Please, fill USER config before using!!!", - "info": "", - "x": 610, - "y": 60, - "wires": [] - }, - { - "id": "18b3dfde097451d1", - "type": "function", - "z": "bde2c7d9084e1fa9", - "name": "FIND IMEI by sessionID", - "func": "var IMEI = lookForImeiBySession(msg._session);\n\nif (IMEI != null) {\n var moduleIMEI = toImeiString(Buffer.from(IMEI, 'utf8'));\n\n msg.token = moduleIMEI;\n msg.applicationVersion = flow.get(\"TRACKER_APP_VERSION\");\n\n return msg;\n}\n\nnode.warn(\"Session with ID: \" + msg._session.id + \" not found\");\nreturn null;\n\n//****************************************************************************************\n// functions\n//****************************************************************************************\nfunction lookForImeiBySession(session) {\n var tempIMEI = null;\n const TCP_SESSIONS = flow.get(\"TCP_SESSIONS\");\n TCP_SESSIONS.forEach(function (value, key, map) {\n if(value.id === session.id) {\n tempIMEI = key;\n }\n });\n return tempIMEI;\n}\n\nfunction toImeiString(IMEIarray) {\n var result = \"\";\n for (var i = 0; i < IMEIarray.length; i++) {\n result += String.fromCharCode(IMEIarray[i]);\n }\n return result;\n}", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 550, - "y": 200, - "wires": [ - [ - "4bb019c7b06b724c" - ] - ] - }, - { - "id": "30c07c74d031f354", - "type": "function", - "z": "bde2c7d9084e1fa9", - "name": "SAVE IMEI and send TCP reply", - "func": "var inputDataPtr = 0;\n\nvar inputMsg = msg.payload;\n\n// IMEI length & IMEI\nvar imeiLength = getNextInt16();\nif (imeiLength != 15) {\n node.error(\"Wrong imei length: \" + imeiLength);\n return null;\n}\nvar moduleIMEI = toImeiString(getNextSubArray(imeiLength));\n\nif (msg._session.type !== \"tcp\") {\n node.warn(\"Wrong session type: \" + msg.session.type);\n return;\n}\n\nconst TCP_SESSIONS = flow.get(\"TCP_SESSIONS\");\nif (TCP_SESSIONS.get(moduleIMEI)) {\n node.debug(\"Update session for the IMEI: \" + moduleIMEI);\n TCP_SESSIONS.set(moduleIMEI, msg._session);\n} else {\n node.debug(\"Create session for the IMEI: \" + moduleIMEI);\n TCP_SESSIONS.set(moduleIMEI, msg._session);\n}\nflow.set(\"TCP_SESSIONS\", TCP_SESSIONS);\n\nmsg.payload = Buffer.from(\"\\x01\");\n\nreturn msg;\n\n\n//**********************************************************************************************\n// toImeiString\n//**********************************************************************************************\nfunction toImeiString(IMEIarray) {\n var result = \"\";\n for (var i = 0; i < IMEIarray.length; i++) {\n result += String.fromCharCode(IMEIarray[i]);\n }\n return result;\n}\n\n//**********************************************************************************************\n// getNextSubArray\n//**********************************************************************************************\nfunction getNextSubArray(length) {\n var subarray = inputMsg.slice(inputDataPtr, inputDataPtr + length);\n inputDataPtr += length;\n return subarray;\n}\n\n//**********************************************************************************************\n// getNextInt16\n//**********************************************************************************************\nfunction getNextInt16() {\n var value = inputMsg[inputDataPtr++];\n value = value * 256 + inputMsg[inputDataPtr++];\n return value;\n}", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 490, - "y": 540, - "wires": [ - [ - "63b71825da12406c" - ] - ] - }, - { - "id": "507b354d815858fa", - "type": "function", - "z": "bde2c7d9084e1fa9", - "name": "SEND msg to EPMX", - "func": "var requestId = Math.floor(Math.random()*100);\n\n// creates message to send\nmsg.topic = \"kp1/\" + msg.applicationVersion + \"/epmx/\" + msg.token + \"/update/keys/\" + requestId;\n\nreturn msg;", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 1260, - "y": 280, - "wires": [ - [ - "2ee0531dc3f57930", - "9a4cb5651b35323f" - ] - ] - }, - { - "id": "2ee0531dc3f57930", - "type": "debug", - "z": "bde2c7d9084e1fa9", - "name": "", - "active": false, - "tosidebar": true, - "console": false, - "tostatus": false, - "complete": "true", - "targetType": "full", - "statusVal": "", - "statusType": "auto", - "x": 1450, - "y": 260, - "wires": [] - }, - { - "id": "8cc6f5051471b6e0", - "type": "function", - "z": "bde2c7d9084e1fa9", - "name": "SEND msg to DCX", - "func": "msg.topic = \"kp1/\" + msg.applicationVersion + \"/dcx/\" + msg.token + \"/json\";\n\nreturn msg;", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 1270, - "y": 360, - "wires": [ - [ - "207c92efc66d09e7", - "9a4cb5651b35323f" - ] - ] - }, - { - "id": "207c92efc66d09e7", - "type": "debug", - "z": "bde2c7d9084e1fa9", - "name": "", - "active": true, - "tosidebar": true, - "console": false, - "tostatus": false, - "complete": "true", - "targetType": "full", - "statusVal": "", - "statusType": "auto", - "x": 1450, - "y": 380, - "wires": [] - }, - { - "id": "6bb92953f4c7c05a", - "type": "function", - "z": "bde2c7d9084e1fa9", - "name": "PARSE AVL IO data", - "func": "var avl = msg.avl;\n\nvar payload = {};\npayload.timestamp = avl.timestamp;\npayload.altitude = avl.GPS.altitude;\npayload.angle = avl.GPS.angle;\npayload.satellites = avl.GPS.satellites;\npayload.latitude = avl.GPS.latitude;\npayload.longitude = avl.GPS.longitude;\n\nif (avl.axis != undefined) {\n payload.axis_x = avl.axis.x;\n payload.axis_y = avl.axis.y;\n payload.axis_z = avl.axis.z;\n}\n\n// fuel Used GPS\nvar fuelUsedGps = getIoData(12);\nif (fuelUsedGps != null) {\n payload.fuelUsedGps = fuelUsedGps;\n}\n\n// fuel Rate GPS\nvar fuelRateGps = getIoData(13);\nif (fuelRateGps != null) {\n payload.fuelRateGps = fuelRateGps;\n}\n\n// total odometer\nvar totalOdometer = getIoData(16);\nif (totalOdometer != null) {\n payload.totalOdometer = totalOdometer / 1000;\n}\n\n// gsmSignal\nvar gsmSignal = getIoData(21);\nif (gsmSignal != null) {\n payload.gsmSignal = gsmSignal;\n}\n\n// speed\nvar speed = getIoData(24);\nif (speed != null) {\n payload.speed = speed;\n}\n\n// obdDtcNumber\nvar obdDtcNumber = getIoData(30);\nif (obdDtcNumber != null) {\n payload.obdDtcNumber = obdDtcNumber;\n}\n\n// obdEngineLoad\nvar obdEngineLoad = getIoData(31);\nif (obdEngineLoad != null) {\n payload.obdEngineLoad = obdEngineLoad;\n}\n\n// obdCoolantTemperature\nvar obdCoolantTemperature = getIoData(32);\nif (obdCoolantTemperature != null) {\n payload.obdCoolantTemperature = obdCoolantTemperature;\n}\n\n// obdShortFuelTrim\nvar obdShortFuelTrim = getIoData(33);\nif (obdShortFuelTrim != null) {\n payload.obdShortFuelTrim = obdShortFuelTrim;\n}\n\n// obdFuelPressure\nvar obdFuelPressure = getIoData(34);\nif (obdFuelPressure != null) {\n payload.obdFuelPressure = obdFuelPressure;\n}\n\n// obdIntakeMAP\nvar obdIntakeMAP = getIoData(35);\nif (obdIntakeMAP != null) {\n payload.obdIntakeMAP = obdIntakeMAP;\n}\n\n// obdEngineRPM\nvar obdEngineRPM = getIoData(36);\nif (obdEngineRPM != null) {\n payload.obdEngineRPM = obdEngineRPM;\n}\n\n// obdVehicleSpeed\nvar obdVehicleSpeed = getIoData(37);\nif (obdVehicleSpeed != null) {\n payload.obdVehicleSpeed = obdVehicleSpeed;\n}\n\n// obdTimingAdvance\nvar obdTimingAdvance = getIoData(38);\nif (obdTimingAdvance != null) {\n payload.obdTimingAdvance = obdTimingAdvance;\n}\n\n// obdIntakeAirTemperature\nvar obdIntakeAirTemperature = getIoData(39);\nif (obdIntakeAirTemperature != null) {\n payload.obdIntakeAirTemperature = obdIntakeAirTemperature;\n}\n\n// obdThrottlePosition\nvar obdThrottlePosition = getIoData(41);\nif (obdThrottlePosition != null) {\n payload.obdThrottlePosition = obdThrottlePosition;\n}\n\n// obdDistanceTraveledMILon\nvar obdDistanceTraveledMILon = getIoData(43);\nif (obdDistanceTraveledMILon != null) {\n payload.obdDistanceTraveledMILon = obdDistanceTraveledMILon;\n}\n\n// obdFuelLevel\nvar obdFuelLevel = getIoData(48);\nif (obdFuelLevel != null) {\n payload.obdFuelLevel = obdFuelLevel;\n} else {\n payload.obdFuelLevel = 50;\n}\n\n// engineOilTemperature\nvar engineOilTemperature = getIoData(58);\nif (engineOilTemperature != null) {\n payload.engineOilTemperature = engineOilTemperature;\n}\n\n// fuelRate\nvar fuelRate = getIoData(60);\nif (fuelRate != null) {\n payload.fuelRate = fuelRate;\n}\n\n// externalVoltage\nvar externalVoltage = getIoData(66);\nif (externalVoltage != null) {\n payload.externalVoltage = externalVoltage;\n}\n\n// batteryVoltage\nvar batteryVoltage = getIoData(67);\nif (batteryVoltage != null) {\n payload.batteryVoltage = batteryVoltage;\n}\n\n// batteryCurrent\nvar batteryCurrent = getIoData(68);\nif (batteryCurrent != null) {\n payload.batteryCurrent = batteryCurrent;\n}\n\n// gnssStatus\nvar gnssStatus = getIoData(69);\nif (gnssStatus != null) {\n payload.gnssStatus = gnssStatus;\n}\n\n// batteryLevel\nvar batteryLevel = getIoData(113);\nif (batteryLevel != null) {\n payload.batteryLevel = batteryLevel;\n}\n\n// tripOdometer\nvar tripOdometer = getIoData(199);\nif (tripOdometer != null) {\n payload.tripOdometer = tripOdometer;\n}\n\n// gsmCellId\nvar gsmCellId = getIoData(205);\nif (gsmCellId != null) {\n payload.gsmCellId = gsmCellId;\n}\n\n// gsmAreaCode\nvar gsmAreaCode = getIoData(206);\nif (gsmAreaCode != null) {\n payload.gsmAreaCode = gsmAreaCode;\n}\n\n// ignition\nvar ignition = getIoData(239);\nif (ignition != null) {\n payload.ignition = ignition;\n}\n\n// movement\nvar movement = getIoData(240);\nif (movement != null) {\n payload.movement = movement;\n}\n\n// btStatus\nvar btStatus = getIoData(263);\nif (btStatus != null) {\n payload.btStatus = btStatus;\n}\n\n// instantMovement\nvar instantMovement = getIoData(303);\nif (instantMovement != null) {\n payload.instantMovement = instantMovement;\n}\n\n// obdOemTotalMileage\nvar obdOemTotalMileage = getIoData(389);\nif (obdOemTotalMileage != null) {\n payload.obdOemTotalMileage = obdOemTotalMileage;\n}\n\n// obdOemFuelLevel\nvar obdOemFuelLevel = getIoData(390);\nif (obdOemFuelLevel != null) {\n payload.obdOemFuelLevel = obdOemFuelLevel / 10;\n} else {\n payload.obdOemFuelLevel = 50;\n}\n\n// creates message to send\nvar result = {};\nresult.payload = payload;\nresult.token = msg.token;\nresult.applicationVersion = msg.applicationVersion;\n\nreturn result;\n\n//**********************************************************************************************\n// getIoData\n// Get IO data with specified AVL ID\n//**********************************************************************************************\nfunction getIoData(id) {\n if (avl.ioData.get(id) != null) {\n return avl.ioData.get(id);\n } else {\n return avl.ioData.get(id.toString());\n }\n}", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 960, - "y": 200, - "wires": [ - [ - "a7b4e83044812b5a" - ] - ] - }, - { - "id": "4bb019c7b06b724c", - "type": "function", - "z": "bde2c7d9084e1fa9", - "name": "TO msgs", - "func": "var avl = msg.payload.avl[msg.numberOfData - 1];\n\nvar messages = [];\nfor (var i=0; i 0x7FFFFFFF) {\n value -= 0x100000000;\n }\n return value / 10000000;\n}\n\n//**********************************************************************************************\n// parseIOelement\n//**********************************************************************************************\nfunction parseIOelement() {\n avl.eventIoID = getNextInt16();\n\n //if (avl.eventIoID == 385) {\n // parseBeacon();\n // getNextInt8();\n //} else {\n parseUsualIOelements();\n decodeUsualIOelements();\n //}\n}\n\n//**********************************************************************************************\n// parseBeacon\n//**********************************************************************************************\nfunction parseBeacon(array) {\n const BEACON_LENGTH = 20;\n const EDDY_LENGTH = 16;\n\n var avl = {};\n\n avl.beaconLength = array.length;\n\n var ptr = 0;\n\n // dataPart\n avl.dataPart = array[ptr++];\n avl.beaconRecordsCount = avl.dataPart & 0x0F;\n avl.recordNumber = (avl.dataPart & 0xF0) >> 4;\n\n if (avl.beaconLength < EDDY_LENGTH) {\n return avl;\n }\n\n // flags\n avl.flag = array[ptr++];\n avl.sygnalStrenghAvailable = ((avl.flag & 0x01) > 0) ? 1 : 0;\n avl.beaconDataSent = ((avl.flag & 0x20) > 0) ? 1 : 0;\n\n // beacons\n if (avl.beaconDataSent != 0) {\n // beacon data\n avl.beaconId = array.slice(ptr, ptr + BEACON_LENGTH);\n ptr += BEACON_LENGTH;\n if (avl.sygnalStrenghAvailable != 0) {\n avl.BeaconRssi = array[ptr++];\n }\n }\n\n return avl;\n}\n\n//**********************************************************************************************\n// parseUsualIOelements\n//**********************************************************************************************\nfunction parseUsualIOelements() {\n avl.nTotalIo = getNextInt16();\n avl.n1Io = getNextInt16();\n avl.ioData = new Map();\n var i = 0;\n for (i = 0; i < avl.n1Io; i++) {\n var n1IoId = getNextInt16();\n var n1IoValue = getNextInt8();\n if (n1IoValue >= 128) {\n n1IoValue = n1IoValue - 256;\n }\n avl.ioData.set(n1IoId, n1IoValue);\n }\n\n if (inputDataPtr >= parsedMsg.fullPacketLength) { return [null, null]; }\n avl.n2Io = getNextInt16();\n for (i = 0; i < avl.n2Io; i++) {\n var n2IoId = getNextInt16();\n var n2IoValue = getNextInt16();\n if (n2IoValue >= 0x8000) {\n n2IoValue = n2IoValue - 0x8000;\n }\n avl.ioData.set(n2IoId, n2IoValue);\n }\n\n if (inputDataPtr >= parsedMsg.fullPacketLength) { return [null, null]; }\n avl.n4Io = getNextInt16();\n for (i = 0; i < avl.n4Io; i++) {\n var n4IoId = getNextInt16();\n var n4IoValue = getNextInt32();\n if (n4IoValue >= 0x80000000) {\n n4IoValue = n4IoValue - 0x80000000;\n }\n avl.ioData.set(n4IoId, n4IoValue);\n }\n\n if (inputDataPtr >= parsedMsg.fullPacketLength) { return [null, null]; }\n avl.n8Io = getNextInt16();\n for (i = 0; i < avl.n8Io; i++) {\n var n8IoId = getNextInt16();\n //var n8IoSubArray = getNextSubArray(8);\n var n8IoValue = getNextInt64();\n if (n8IoValue >= 0x8000000000000000) {\n n8IoValue = n8IoValue - 0x8000000000000000;\n }\n //node.warn(n8IoValue);\n avl.ioData.set(n8IoId, n8IoValue);\n }\n avl.nxIo = getNextInt16();\n for (i = 0; i < avl.nxIo; i++) {\n var nxIoId = getNextInt16();\n var nxIoLength = getNextInt16();\n if (nxIoId == 385) {\n avl.ioData.set(nxIoId, parseBeacon(getNextSubArray(nxIoLength)));\n } else {\n avl.ioData.set(nxIoId, getNextSubArray(nxIoLength));\n }\n }\n}\n\n//**********************************************************************************************\n// decodeUsualIOelements\n//**********************************************************************************************\nfunction decodeUsualIOelements() {\n avl.axis = {};\n avl.axis.x = avl.ioData.get(17);\n avl.axis.y = avl.ioData.get(18);\n avl.axis.z = avl.ioData.get(19);\n}\n\n//**********************************************************************************************\n// getCharArray\n//**********************************************************************************************\nfunction getCharArray(array) {\n const result = [];\n for (var i = 0; i < array.length; i++) {\n result.push(String.fromCharCode(array[i]));\n }\n return result;\n}\n\n//**********************************************************************************************\n// getNextSubArray\n//**********************************************************************************************\nfunction getNextSubArray(length) {\n var subarray = inputMsg.slice(inputDataPtr, inputDataPtr + length);\n inputDataPtr += length;\n return subarray;\n}\n\n//**********************************************************************************************\n// getNextInt8\n//**********************************************************************************************\nfunction getNextInt8() {\n return inputMsg[inputDataPtr++];\n}\n\n//**********************************************************************************************\n// getNextInt16\n//**********************************************************************************************\nfunction getNextInt16() {\n var value = inputMsg[inputDataPtr++];\n value = (value << 8) + inputMsg[inputDataPtr++];\n return value;\n}\n\n//**********************************************************************************************\n// getNextInt32\n//**********************************************************************************************\nfunction getNextInt32() {\n var value = inputMsg[inputDataPtr++];\n value = (value << 8) + inputMsg[inputDataPtr++];\n value = (value << 8) + inputMsg[inputDataPtr++];\n value = (value << 8) + inputMsg[inputDataPtr++];\n return value;\n}\n\n//**********************************************************************************************\n// getNextInt64\n//**********************************************************************************************\nfunction getNextInt64() {\n var value = inputMsg[inputDataPtr++];\n value = (value << 8) + inputMsg[inputDataPtr++];\n value = (value << 8) + inputMsg[inputDataPtr++];\n value = (value << 8) + inputMsg[inputDataPtr++];\n value = (value << 8) + inputMsg[inputDataPtr++];\n value = (value << 8) + inputMsg[inputDataPtr++];\n value = (value << 8) + inputMsg[inputDataPtr++];\n value = (value << 8) + inputMsg[inputDataPtr++];\n return value;\n}\n\n//**********************************************************************************************\n// Calculates the buffers CRC-16/IBM.\n//**********************************************************************************************\nfunction crc16(buffer, startPtr, length) {\n var crc = 0;\n var odd;\n\n for (var i = 0; i < length; i++) {\n crc = crc ^ buffer[i + startPtr];\n\n var numBit = 0;\n do {\n odd = crc & 0x0001;\n crc = crc >> 1;\n if (odd == 1) {\n crc = crc ^ 0xA001;\n }\n numBit++;\n } while (numBit < 8);\n }\n\n return crc;\n};", + "outputs": 2, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 260, + "wires": [ + [ + "0e7ef225e445c758", + "18b3dfde097451d1" + ], + [ + "63b71825da12406c", + "3d65e2931542de30" + ] + ] + }, + { + "id": "0e7ef225e445c758", + "type": "debug", + "z": "bde2c7d9084e1fa9", + "name": "PARSED data", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "true", + "targetType": "full", + "statusVal": "", + "statusType": "auto", + "x": 520, + "y": 240, + "wires": [] + }, + { + "id": "e54797cf40844cf2", + "type": "inject", + "z": "bde2c7d9084e1fa9", + "name": "Trigger", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": true, + "onceDelay": "", + "topic": "", + "payload": "", + "payloadType": "date", + "x": 140, + "y": 100, + "wires": [ + [ + "ed4c731ecb5921bf" + ] + ] + }, + { + "id": "cb562ce75e8f1d6a", + "type": "function", + "z": "bde2c7d9084e1fa9", + "name": "USER config", + "func": "/*\n Fill before using:\n - application version\n*/\n\nconst TRACKER_APP_VERSION = \"chfq5afsj3ic738hqpd0-v1\";\nflow.set(\"TRACKER_APP_VERSION\", TRACKER_APP_VERSION);\n\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 530, + "y": 100, + "wires": [ + [] + ] + }, + { + "id": "ed4c731ecb5921bf", + "type": "function", + "z": "bde2c7d9084e1fa9", + "name": "INIT flow context", + "func": "const tcpSessions = new Map();\nflow.set(\"TCP_SESSIONS\", tcpSessions);\n\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 330, + "y": 100, + "wires": [ + [ + "cb562ce75e8f1d6a" + ] + ] + }, + { + "id": "fabe947dd3edbd38", + "type": "comment", + "z": "bde2c7d9084e1fa9", + "name": "Please, fill USER config before using!!!", + "info": "", + "x": 610, + "y": 60, + "wires": [] + }, + { + "id": "18b3dfde097451d1", + "type": "function", + "z": "bde2c7d9084e1fa9", + "name": "FIND IMEI by sessionID", + "func": "var IMEI = lookForImeiBySession(msg._session);\n\nif (IMEI != null) {\n var moduleIMEI = toImeiString(Buffer.from(IMEI, 'utf8'));\n\n msg.token = moduleIMEI;\n msg.applicationVersion = flow.get(\"TRACKER_APP_VERSION\");\n\n return msg;\n}\n\nnode.warn(\"Session with ID: \" + msg._session.id + \" not found\");\nreturn null;\n\n//****************************************************************************************\n// functions\n//****************************************************************************************\nfunction lookForImeiBySession(session) {\n var tempIMEI = null;\n const TCP_SESSIONS = flow.get(\"TCP_SESSIONS\");\n TCP_SESSIONS.forEach(function (value, key, map) {\n if(value.id === session.id) {\n tempIMEI = key;\n }\n });\n return tempIMEI;\n}\n\nfunction toImeiString(IMEIarray) {\n var result = \"\";\n for (var i = 0; i < IMEIarray.length; i++) {\n result += String.fromCharCode(IMEIarray[i]);\n }\n return result;\n}", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 550, + "y": 200, + "wires": [ + [ + "4bb019c7b06b724c" + ] + ] + }, + { + "id": "30c07c74d031f354", + "type": "function", + "z": "bde2c7d9084e1fa9", + "name": "SAVE IMEI and send TCP reply", + "func": "var inputDataPtr = 0;\n\nvar inputMsg = msg.payload;\n\n// IMEI length & IMEI\nvar imeiLength = getNextInt16();\nif (imeiLength != 15) {\n node.error(\"Wrong imei length: \" + imeiLength);\n return null;\n}\nvar moduleIMEI = toImeiString(getNextSubArray(imeiLength));\n\nif (msg._session.type !== \"tcp\") {\n node.warn(\"Wrong session type: \" + msg.session.type);\n return;\n}\n\nconst TCP_SESSIONS = flow.get(\"TCP_SESSIONS\");\nif (TCP_SESSIONS.get(moduleIMEI)) {\n node.debug(\"Update session for the IMEI: \" + moduleIMEI);\n TCP_SESSIONS.set(moduleIMEI, msg._session);\n} else {\n node.debug(\"Create session for the IMEI: \" + moduleIMEI);\n TCP_SESSIONS.set(moduleIMEI, msg._session);\n}\nflow.set(\"TCP_SESSIONS\", TCP_SESSIONS);\n\nmsg.payload = Buffer.from(\"\\x01\");\n\nreturn msg;\n\n\n//**********************************************************************************************\n// toImeiString\n//**********************************************************************************************\nfunction toImeiString(IMEIarray) {\n var result = \"\";\n for (var i = 0; i < IMEIarray.length; i++) {\n result += String.fromCharCode(IMEIarray[i]);\n }\n return result;\n}\n\n//**********************************************************************************************\n// getNextSubArray\n//**********************************************************************************************\nfunction getNextSubArray(length) {\n var subarray = inputMsg.slice(inputDataPtr, inputDataPtr + length);\n inputDataPtr += length;\n return subarray;\n}\n\n//**********************************************************************************************\n// getNextInt16\n//**********************************************************************************************\nfunction getNextInt16() {\n var value = inputMsg[inputDataPtr++];\n value = value * 256 + inputMsg[inputDataPtr++];\n return value;\n}", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 490, + "y": 540, + "wires": [ + [ + "63b71825da12406c" + ] + ] + }, + { + "id": "507b354d815858fa", + "type": "function", + "z": "bde2c7d9084e1fa9", + "name": "SEND msg to EPMX", + "func": "var requestId = Math.floor(Math.random()*100);\n\n// creates message to send\nmsg.topic = \"kp1/\" + msg.applicationVersion + \"/epmx/\" + msg.token + \"/update/keys/\" + requestId;\n\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 1260, + "y": 280, + "wires": [ + [ + "2ee0531dc3f57930", + "9a4cb5651b35323f" + ] + ] + }, + { + "id": "2ee0531dc3f57930", + "type": "debug", + "z": "bde2c7d9084e1fa9", + "name": "", + "active": false, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "true", + "targetType": "full", + "statusVal": "", + "statusType": "auto", + "x": 1450, + "y": 260, + "wires": [] + }, + { + "id": "8cc6f5051471b6e0", + "type": "function", + "z": "bde2c7d9084e1fa9", + "name": "SEND msg to DCX", + "func": "msg.topic = \"kp1/\" + msg.applicationVersion + \"/dcx/\" + msg.token + \"/json\";\n\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 1270, + "y": 360, + "wires": [ + [ + "207c92efc66d09e7", + "9a4cb5651b35323f" + ] + ] + }, + { + "id": "207c92efc66d09e7", + "type": "debug", + "z": "bde2c7d9084e1fa9", + "name": "", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "true", + "targetType": "full", + "statusVal": "", + "statusType": "auto", + "x": 1450, + "y": 380, + "wires": [] + }, + { + "id": "6bb92953f4c7c05a", + "type": "function", + "z": "bde2c7d9084e1fa9", + "name": "PARSE AVL IO data", + "func": "var avl = msg.avl;\n\nvar payload = {};\npayload.timestamp = avl.timestamp;\npayload.altitude = avl.GPS.altitude;\npayload.angle = avl.GPS.angle;\npayload.satellites = avl.GPS.satellites;\npayload.latitude = avl.GPS.latitude;\npayload.longitude = avl.GPS.longitude;\n\nif (avl.axis != undefined) {\n payload.axis_x = avl.axis.x;\n payload.axis_y = avl.axis.y;\n payload.axis_z = avl.axis.z;\n}\n\n// fuel Used GPS\nvar fuelUsedGps = getIoData(12);\nif (fuelUsedGps != null) {\n payload.fuelUsedGps = fuelUsedGps;\n}\n\n// fuel Rate GPS\nvar fuelRateGps = getIoData(13);\nif (fuelRateGps != null) {\n payload.fuelRateGps = fuelRateGps;\n}\n\n// total odometer\nvar totalOdometer = getIoData(16);\nif (totalOdometer != null) {\n payload.totalOdometer = totalOdometer / 1000;\n}\n\n// gsmSignal\nvar gsmSignal = getIoData(21);\nif (gsmSignal != null) {\n payload.gsmSignal = gsmSignal;\n}\n\n// speed\nvar speed = getIoData(24);\nif (speed != null) {\n payload.speed = speed;\n}\n\n// obdDtcNumber\nvar obdDtcNumber = getIoData(30);\nif (obdDtcNumber != null) {\n payload.obdDtcNumber = obdDtcNumber;\n}\n\n// obdEngineLoad\nvar obdEngineLoad = getIoData(31);\nif (obdEngineLoad != null) {\n payload.obdEngineLoad = obdEngineLoad;\n}\n\n// obdCoolantTemperature\nvar obdCoolantTemperature = getIoData(32);\nif (obdCoolantTemperature != null) {\n payload.obdCoolantTemperature = obdCoolantTemperature;\n}\n\n// obdShortFuelTrim\nvar obdShortFuelTrim = getIoData(33);\nif (obdShortFuelTrim != null) {\n payload.obdShortFuelTrim = obdShortFuelTrim;\n}\n\n// obdFuelPressure\nvar obdFuelPressure = getIoData(34);\nif (obdFuelPressure != null) {\n payload.obdFuelPressure = obdFuelPressure;\n}\n\n// obdIntakeMAP\nvar obdIntakeMAP = getIoData(35);\nif (obdIntakeMAP != null) {\n payload.obdIntakeMAP = obdIntakeMAP;\n}\n\n// obdEngineRPM\nvar obdEngineRPM = getIoData(36);\nif (obdEngineRPM != null) {\n payload.obdEngineRPM = obdEngineRPM;\n}\n\n// obdVehicleSpeed\nvar obdVehicleSpeed = getIoData(37);\nif (obdVehicleSpeed != null) {\n payload.obdVehicleSpeed = obdVehicleSpeed;\n}\n\n// obdTimingAdvance\nvar obdTimingAdvance = getIoData(38);\nif (obdTimingAdvance != null) {\n payload.obdTimingAdvance = obdTimingAdvance;\n}\n\n// obdIntakeAirTemperature\nvar obdIntakeAirTemperature = getIoData(39);\nif (obdIntakeAirTemperature != null) {\n payload.obdIntakeAirTemperature = obdIntakeAirTemperature;\n}\n\n// obdThrottlePosition\nvar obdThrottlePosition = getIoData(41);\nif (obdThrottlePosition != null) {\n payload.obdThrottlePosition = obdThrottlePosition;\n}\n\n// obdDistanceTraveledMILon\nvar obdDistanceTraveledMILon = getIoData(43);\nif (obdDistanceTraveledMILon != null) {\n payload.obdDistanceTraveledMILon = obdDistanceTraveledMILon;\n}\n\n// obdFuelLevel\nvar obdFuelLevel = getIoData(48);\nif (obdFuelLevel != null) {\n payload.obdFuelLevel = obdFuelLevel;\n} else {\n payload.obdFuelLevel = 50;\n}\n\n// engineOilTemperature\nvar engineOilTemperature = getIoData(58);\nif (engineOilTemperature != null) {\n payload.engineOilTemperature = engineOilTemperature;\n}\n\n// fuelRate\nvar fuelRate = getIoData(60);\nif (fuelRate != null) {\n payload.fuelRate = fuelRate;\n}\n\n// externalVoltage\nvar externalVoltage = getIoData(66);\nif (externalVoltage != null) {\n payload.externalVoltage = externalVoltage;\n}\n\n// batteryVoltage\nvar batteryVoltage = getIoData(67);\nif (batteryVoltage != null) {\n payload.batteryVoltage = batteryVoltage;\n}\n\n// batteryCurrent\nvar batteryCurrent = getIoData(68);\nif (batteryCurrent != null) {\n payload.batteryCurrent = batteryCurrent;\n}\n\n// gnssStatus\nvar gnssStatus = getIoData(69);\nif (gnssStatus != null) {\n payload.gnssStatus = gnssStatus;\n}\n\n// batteryLevel\nvar batteryLevel = getIoData(113);\nif (batteryLevel != null) {\n payload.batteryLevel = batteryLevel;\n}\n\n// tripOdometer\nvar tripOdometer = getIoData(199);\nif (tripOdometer != null) {\n payload.tripOdometer = tripOdometer;\n}\n\n// gsmCellId\nvar gsmCellId = getIoData(205);\nif (gsmCellId != null) {\n payload.gsmCellId = gsmCellId;\n}\n\n// gsmAreaCode\nvar gsmAreaCode = getIoData(206);\nif (gsmAreaCode != null) {\n payload.gsmAreaCode = gsmAreaCode;\n}\n\n// ignition\nvar ignition = getIoData(239);\nif (ignition != null) {\n payload.ignition = ignition;\n}\n\n// movement\nvar movement = getIoData(240);\nif (movement != null) {\n payload.movement = movement;\n}\n\n// btStatus\nvar btStatus = getIoData(263);\nif (btStatus != null) {\n payload.btStatus = btStatus;\n}\n\n// instantMovement\nvar instantMovement = getIoData(303);\nif (instantMovement != null) {\n payload.instantMovement = instantMovement;\n}\n\n// obdOemTotalMileage\nvar obdOemTotalMileage = getIoData(389);\nif (obdOemTotalMileage != null) {\n payload.obdOemTotalMileage = obdOemTotalMileage;\n}\n\n// obdOemFuelLevel\nvar obdOemFuelLevel = getIoData(390);\nif (obdOemFuelLevel != null) {\n payload.obdOemFuelLevel = obdOemFuelLevel / 10;\n} else {\n payload.obdOemFuelLevel = 50;\n}\n\n// creates message to send\nvar result = {};\nresult.payload = payload;\nresult.token = msg.token;\nresult.applicationVersion = msg.applicationVersion;\n\nreturn result;\n\n//**********************************************************************************************\n// getIoData\n// Get IO data with specified AVL ID\n//**********************************************************************************************\nfunction getIoData(id) {\n if (avl.ioData.get(id) != null) {\n return avl.ioData.get(id);\n } else {\n return avl.ioData.get(id.toString());\n }\n}", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 960, + "y": 200, + "wires": [ + [ + "a7b4e83044812b5a" + ] + ] + }, + { + "id": "4bb019c7b06b724c", + "type": "function", + "z": "bde2c7d9084e1fa9", + "name": "TO msgs", + "func": "var avl = msg.payload.avl[msg.numberOfData - 1];\n\nvar messages = [];\nfor (var i=0; i Date: Thu, 8 May 2025 21:08:38 +0300 Subject: [PATCH 2/2] refactoring --- .../code/node-red-teltonika-tcp-flow.json | 1134 ++++++++--------- 1 file changed, 567 insertions(+), 567 deletions(-) diff --git a/doc/Tutorials/device-integration/hardware-guides/connect-teltonika-to-kaa-platform/attach/code/node-red-teltonika-tcp-flow.json b/doc/Tutorials/device-integration/hardware-guides/connect-teltonika-to-kaa-platform/attach/code/node-red-teltonika-tcp-flow.json index 4a6182c3f1..ced758f080 100644 --- a/doc/Tutorials/device-integration/hardware-guides/connect-teltonika-to-kaa-platform/attach/code/node-red-teltonika-tcp-flow.json +++ b/doc/Tutorials/device-integration/hardware-guides/connect-teltonika-to-kaa-platform/attach/code/node-red-teltonika-tcp-flow.json @@ -1,569 +1,569 @@ [ - { - "id": "bde2c7d9084e1fa9", - "type": "tab", - "label": "Teltonika_codec8ext TCP", - "disabled": false, - "info": "", - "env": [] - }, - { - "id": "f476063bdbda1a15", - "type": "debug", - "z": "bde2c7d9084e1fa9", - "name": "RAW data", - "active": false, - "tosidebar": true, - "console": false, - "tostatus": false, - "complete": "true", - "targetType": "full", - "statusVal": "", - "statusType": "auto", - "x": 420, - "y": 340, - "wires": [] - }, - { - "id": "fd727ce0c3c8ed4f", - "type": "function", - "z": "bde2c7d9084e1fa9", - "name": "Filter PING packet", - "func": "if (msg.payload.length == 1) {\n msg.payload = \"PING. \" + msg.ip + \":\" + msg.port;\n return [null, msg];\n}\n\nreturn [msg, null];", - "outputs": 2, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 210, - "y": 360, - "wires": [ - [ - "f476063bdbda1a15", - "d2b0d4148e870f54" - ], - [ - "0a4531912ab49b84" - ] - ] - }, - { - "id": "0a4531912ab49b84", - "type": "debug", - "z": "bde2c7d9084e1fa9", - "name": "PING packets", - "active": false, - "tosidebar": true, - "console": false, - "tostatus": false, - "complete": "payload", - "targetType": "msg", - "statusVal": "", - "statusType": "auto", - "x": 440, - "y": 380, - "wires": [] - }, - { - "id": "d2b0d4148e870f54", - "type": "function", - "z": "bde2c7d9084e1fa9", - "name": "PARSE codec8_ext TCP", - "func": "var inputMsg = msg.payload;\n\nvar inputDataPtr = 0;\nvar fullPacketLength = 0;\n\nvar parsedMsg = {};\nparsedMsg.avl = [];\nvar avl = {};\n\nparseAVLfull();\n\n// create TCP response\nvar tcpResponse = createTcpResponse(parsedMsg.numberOfData, msg._session);\n\nmsg.payload = parsedMsg;\n\nreturn [msg, tcpResponse]; // response\n\n//**********************************************************************************************\n// createTcpResponse\n//**********************************************************************************************\nfunction createTcpResponse(receivedDataCount, session) {\n var countHex = dec2Hex32(receivedDataCount);\n var tcpResponse = {};\n tcpResponse._session = session;\n tcpResponse.payload = new Buffer([Number(countHex.substring(6, 8)), Number(countHex.substring(4, 6)),\n Number(countHex.substring(2, 4)), Number(countHex.substring(0, 2))]);\n\n return tcpResponse;\n}\n\n//**********************************************************************************************\n// dec2Hex32\n//**********************************************************************************************\nfunction dec2Hex32(dec) {\n return Math.abs(dec).toString(32);\n}\n\n//**********************************************************************************************\n// parseAVLfull\n//**********************************************************************************************\nfunction parseAVLfull() {\n //preamble\n var preamble = getNextInt32();\n if (preamble != 0x00000000) {\n node.warn(\"Wrong preamble\");\n return [null, null];\n }\n\n // get packet length\n parsedMsg.fullPacketLength = getNextInt32();\n\n var calculatedCrc16 = crc16(inputMsg, inputDataPtr, (inputMsg.length - inputDataPtr - 4));\n\n // AVL codec ID\n parsedMsg.codecId = getNextInt8();\n if (parsedMsg.codecId != 0x8E) {\n node.warn(\"Wrong codecId: \" + parsedMsg.codecId);\n return [null, null];\n }\n\n // AVL number of data\n parsedMsg.numberOfData = getNextInt8();\n\n // AVL Data array \n\n for (var i = 0; i < parsedMsg.numberOfData; i++) {\n parseAVLpacketDataArrayElement();\n }\n\n parsedMsg.numberOfRecords = getNextInt8();\n\n if (parsedMsg.numberOfData != parsedMsg.numberOfRecords) {\n node.warn(\"numberOfData1 not equals numberOfData2\");\n return [null, null];\n }\n\n parsedMsg.crc16 = getNextInt32();\n if (calculatedCrc16 != parsedMsg.crc16) {\n node.warn(\"Wrong crc16.\");\n return [null, null];\n }\n}\n\n//**********************************************************************************************\n// parseAVLpacketDataArrayElement\n//**********************************************************************************************\nfunction parseAVLpacketDataArrayElement() {\n avl = {};\n avl.timestamp = getTimestamp();\n avl.priority = getNextInt8();\n avl.GPS = parseGPSelement();\n parseIOelement();\n parsedMsg.avl.push(avl);\n}\n\n//**********************************************************************************************\n// parseAVLpacket\n//**********************************************************************************************\nfunction getTimestamp() {\n var timestampArray = getNextSubArray(8);\n var value = 0;\n for (var i = 0; i < timestampArray.length; i++) {\n value = (value * 256) + timestampArray[i];\n }\n return value;\n}\n\n//**********************************************************************************************\n// parseGPSelement\n//**********************************************************************************************\nfunction parseGPSelement() {\n var GPS = {};\n GPS.longitude = getCoordinate(getNextSubArray(4));\n GPS.latitude = getCoordinate(getNextSubArray(4));\n GPS.altitude = getNextInt16();\n GPS.angle = getNextInt16();\n GPS.satellites = getNextInt8();\n GPS.speed = getNextInt16();\n\n return GPS;\n}\n\n//**********************************************************************************************\n// getCoordinate\n//**********************************************************************************************\nfunction getCoordinate(array) {\n // Combine the 4 bytes into a single 32-bit signed integer\n var value = (array[0] << 24) | (array[1] << 16) | (array[2] << 8) | (array[3]);\n // Adjust for JavaScript's bitwise signed 32-bit range\n if (value > 0x7FFFFFFF) {\n value -= 0x100000000;\n }\n return value / 10000000;\n}\n\n//**********************************************************************************************\n// parseIOelement\n//**********************************************************************************************\nfunction parseIOelement() {\n avl.eventIoID = getNextInt16();\n\n //if (avl.eventIoID == 385) {\n // parseBeacon();\n // getNextInt8();\n //} else {\n parseUsualIOelements();\n decodeUsualIOelements();\n //}\n}\n\n//**********************************************************************************************\n// parseBeacon\n//**********************************************************************************************\nfunction parseBeacon(array) {\n const BEACON_LENGTH = 20;\n const EDDY_LENGTH = 16;\n\n var avl = {};\n\n avl.beaconLength = array.length;\n\n var ptr = 0;\n\n // dataPart\n avl.dataPart = array[ptr++];\n avl.beaconRecordsCount = avl.dataPart & 0x0F;\n avl.recordNumber = (avl.dataPart & 0xF0) >> 4;\n\n if (avl.beaconLength < EDDY_LENGTH) {\n return avl;\n }\n\n // flags\n avl.flag = array[ptr++];\n avl.sygnalStrenghAvailable = ((avl.flag & 0x01) > 0) ? 1 : 0;\n avl.beaconDataSent = ((avl.flag & 0x20) > 0) ? 1 : 0;\n\n // beacons\n if (avl.beaconDataSent != 0) {\n // beacon data\n avl.beaconId = array.slice(ptr, ptr + BEACON_LENGTH);\n ptr += BEACON_LENGTH;\n if (avl.sygnalStrenghAvailable != 0) {\n avl.BeaconRssi = array[ptr++];\n }\n }\n\n return avl;\n}\n\n//**********************************************************************************************\n// parseUsualIOelements\n//**********************************************************************************************\nfunction parseUsualIOelements() {\n avl.nTotalIo = getNextInt16();\n avl.n1Io = getNextInt16();\n avl.ioData = new Map();\n var i = 0;\n for (i = 0; i < avl.n1Io; i++) {\n var n1IoId = getNextInt16();\n var n1IoValue = getNextInt8();\n if (n1IoValue >= 128) {\n n1IoValue = n1IoValue - 256;\n }\n avl.ioData.set(n1IoId, n1IoValue);\n }\n\n if (inputDataPtr >= parsedMsg.fullPacketLength) { return [null, null]; }\n avl.n2Io = getNextInt16();\n for (i = 0; i < avl.n2Io; i++) {\n var n2IoId = getNextInt16();\n var n2IoValue = getNextInt16();\n if (n2IoValue >= 0x8000) {\n n2IoValue = n2IoValue - 0x8000;\n }\n avl.ioData.set(n2IoId, n2IoValue);\n }\n\n if (inputDataPtr >= parsedMsg.fullPacketLength) { return [null, null]; }\n avl.n4Io = getNextInt16();\n for (i = 0; i < avl.n4Io; i++) {\n var n4IoId = getNextInt16();\n var n4IoValue = getNextInt32();\n if (n4IoValue >= 0x80000000) {\n n4IoValue = n4IoValue - 0x80000000;\n }\n avl.ioData.set(n4IoId, n4IoValue);\n }\n\n if (inputDataPtr >= parsedMsg.fullPacketLength) { return [null, null]; }\n avl.n8Io = getNextInt16();\n for (i = 0; i < avl.n8Io; i++) {\n var n8IoId = getNextInt16();\n //var n8IoSubArray = getNextSubArray(8);\n var n8IoValue = getNextInt64();\n if (n8IoValue >= 0x8000000000000000) {\n n8IoValue = n8IoValue - 0x8000000000000000;\n }\n //node.warn(n8IoValue);\n avl.ioData.set(n8IoId, n8IoValue);\n }\n avl.nxIo = getNextInt16();\n for (i = 0; i < avl.nxIo; i++) {\n var nxIoId = getNextInt16();\n var nxIoLength = getNextInt16();\n if (nxIoId == 385) {\n avl.ioData.set(nxIoId, parseBeacon(getNextSubArray(nxIoLength)));\n } else {\n avl.ioData.set(nxIoId, getNextSubArray(nxIoLength));\n }\n }\n}\n\n//**********************************************************************************************\n// decodeUsualIOelements\n//**********************************************************************************************\nfunction decodeUsualIOelements() {\n avl.axis = {};\n avl.axis.x = avl.ioData.get(17);\n avl.axis.y = avl.ioData.get(18);\n avl.axis.z = avl.ioData.get(19);\n}\n\n//**********************************************************************************************\n// getCharArray\n//**********************************************************************************************\nfunction getCharArray(array) {\n const result = [];\n for (var i = 0; i < array.length; i++) {\n result.push(String.fromCharCode(array[i]));\n }\n return result;\n}\n\n//**********************************************************************************************\n// getNextSubArray\n//**********************************************************************************************\nfunction getNextSubArray(length) {\n var subarray = inputMsg.slice(inputDataPtr, inputDataPtr + length);\n inputDataPtr += length;\n return subarray;\n}\n\n//**********************************************************************************************\n// getNextInt8\n//**********************************************************************************************\nfunction getNextInt8() {\n return inputMsg[inputDataPtr++];\n}\n\n//**********************************************************************************************\n// getNextInt16\n//**********************************************************************************************\nfunction getNextInt16() {\n var value = inputMsg[inputDataPtr++];\n value = (value << 8) + inputMsg[inputDataPtr++];\n return value;\n}\n\n//**********************************************************************************************\n// getNextInt32\n//**********************************************************************************************\nfunction getNextInt32() {\n var value = inputMsg[inputDataPtr++];\n value = (value << 8) + inputMsg[inputDataPtr++];\n value = (value << 8) + inputMsg[inputDataPtr++];\n value = (value << 8) + inputMsg[inputDataPtr++];\n return value;\n}\n\n//**********************************************************************************************\n// getNextInt64\n//**********************************************************************************************\nfunction getNextInt64() {\n var value = inputMsg[inputDataPtr++];\n value = (value << 8) + inputMsg[inputDataPtr++];\n value = (value << 8) + inputMsg[inputDataPtr++];\n value = (value << 8) + inputMsg[inputDataPtr++];\n value = (value << 8) + inputMsg[inputDataPtr++];\n value = (value << 8) + inputMsg[inputDataPtr++];\n value = (value << 8) + inputMsg[inputDataPtr++];\n value = (value << 8) + inputMsg[inputDataPtr++];\n return value;\n}\n\n//**********************************************************************************************\n// Calculates the buffers CRC-16/IBM.\n//**********************************************************************************************\nfunction crc16(buffer, startPtr, length) {\n var crc = 0;\n var odd;\n\n for (var i = 0; i < length; i++) {\n crc = crc ^ buffer[i + startPtr];\n\n var numBit = 0;\n do {\n odd = crc & 0x0001;\n crc = crc >> 1;\n if (odd == 1) {\n crc = crc ^ 0xA001;\n }\n numBit++;\n } while (numBit < 8);\n }\n\n return crc;\n};", - "outputs": 2, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 290, - "y": 260, - "wires": [ - [ - "0e7ef225e445c758", - "18b3dfde097451d1" - ], - [ - "63b71825da12406c", - "3d65e2931542de30" - ] - ] - }, - { - "id": "0e7ef225e445c758", - "type": "debug", - "z": "bde2c7d9084e1fa9", - "name": "PARSED data", - "active": true, - "tosidebar": true, - "console": false, - "tostatus": false, - "complete": "true", - "targetType": "full", - "statusVal": "", - "statusType": "auto", - "x": 520, - "y": 240, - "wires": [] - }, - { - "id": "e54797cf40844cf2", - "type": "inject", - "z": "bde2c7d9084e1fa9", - "name": "Trigger", - "props": [ - { - "p": "payload" - }, - { - "p": "topic", - "vt": "str" - } - ], - "repeat": "", - "crontab": "", - "once": true, - "onceDelay": "", - "topic": "", - "payload": "", - "payloadType": "date", - "x": 140, - "y": 100, - "wires": [ - [ - "ed4c731ecb5921bf" - ] - ] - }, - { - "id": "cb562ce75e8f1d6a", - "type": "function", - "z": "bde2c7d9084e1fa9", - "name": "USER config", - "func": "/*\n Fill before using:\n - application version\n*/\n\nconst TRACKER_APP_VERSION = \"chfq5afsj3ic738hqpd0-v1\";\nflow.set(\"TRACKER_APP_VERSION\", TRACKER_APP_VERSION);\n\nreturn msg;", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 530, - "y": 100, - "wires": [ - [] - ] - }, - { - "id": "ed4c731ecb5921bf", - "type": "function", - "z": "bde2c7d9084e1fa9", - "name": "INIT flow context", - "func": "const tcpSessions = new Map();\nflow.set(\"TCP_SESSIONS\", tcpSessions);\n\nreturn msg;", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 330, - "y": 100, - "wires": [ - [ - "cb562ce75e8f1d6a" - ] - ] - }, - { - "id": "fabe947dd3edbd38", - "type": "comment", - "z": "bde2c7d9084e1fa9", - "name": "Please, fill USER config before using!!!", - "info": "", - "x": 610, - "y": 60, - "wires": [] - }, - { - "id": "18b3dfde097451d1", - "type": "function", - "z": "bde2c7d9084e1fa9", - "name": "FIND IMEI by sessionID", - "func": "var IMEI = lookForImeiBySession(msg._session);\n\nif (IMEI != null) {\n var moduleIMEI = toImeiString(Buffer.from(IMEI, 'utf8'));\n\n msg.token = moduleIMEI;\n msg.applicationVersion = flow.get(\"TRACKER_APP_VERSION\");\n\n return msg;\n}\n\nnode.warn(\"Session with ID: \" + msg._session.id + \" not found\");\nreturn null;\n\n//****************************************************************************************\n// functions\n//****************************************************************************************\nfunction lookForImeiBySession(session) {\n var tempIMEI = null;\n const TCP_SESSIONS = flow.get(\"TCP_SESSIONS\");\n TCP_SESSIONS.forEach(function (value, key, map) {\n if(value.id === session.id) {\n tempIMEI = key;\n }\n });\n return tempIMEI;\n}\n\nfunction toImeiString(IMEIarray) {\n var result = \"\";\n for (var i = 0; i < IMEIarray.length; i++) {\n result += String.fromCharCode(IMEIarray[i]);\n }\n return result;\n}", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 550, - "y": 200, - "wires": [ - [ - "4bb019c7b06b724c" - ] - ] - }, - { - "id": "30c07c74d031f354", - "type": "function", - "z": "bde2c7d9084e1fa9", - "name": "SAVE IMEI and send TCP reply", - "func": "var inputDataPtr = 0;\n\nvar inputMsg = msg.payload;\n\n// IMEI length & IMEI\nvar imeiLength = getNextInt16();\nif (imeiLength != 15) {\n node.error(\"Wrong imei length: \" + imeiLength);\n return null;\n}\nvar moduleIMEI = toImeiString(getNextSubArray(imeiLength));\n\nif (msg._session.type !== \"tcp\") {\n node.warn(\"Wrong session type: \" + msg.session.type);\n return;\n}\n\nconst TCP_SESSIONS = flow.get(\"TCP_SESSIONS\");\nif (TCP_SESSIONS.get(moduleIMEI)) {\n node.debug(\"Update session for the IMEI: \" + moduleIMEI);\n TCP_SESSIONS.set(moduleIMEI, msg._session);\n} else {\n node.debug(\"Create session for the IMEI: \" + moduleIMEI);\n TCP_SESSIONS.set(moduleIMEI, msg._session);\n}\nflow.set(\"TCP_SESSIONS\", TCP_SESSIONS);\n\nmsg.payload = Buffer.from(\"\\x01\");\n\nreturn msg;\n\n\n//**********************************************************************************************\n// toImeiString\n//**********************************************************************************************\nfunction toImeiString(IMEIarray) {\n var result = \"\";\n for (var i = 0; i < IMEIarray.length; i++) {\n result += String.fromCharCode(IMEIarray[i]);\n }\n return result;\n}\n\n//**********************************************************************************************\n// getNextSubArray\n//**********************************************************************************************\nfunction getNextSubArray(length) {\n var subarray = inputMsg.slice(inputDataPtr, inputDataPtr + length);\n inputDataPtr += length;\n return subarray;\n}\n\n//**********************************************************************************************\n// getNextInt16\n//**********************************************************************************************\nfunction getNextInt16() {\n var value = inputMsg[inputDataPtr++];\n value = value * 256 + inputMsg[inputDataPtr++];\n return value;\n}", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 490, - "y": 540, - "wires": [ - [ - "63b71825da12406c" - ] - ] - }, - { - "id": "507b354d815858fa", - "type": "function", - "z": "bde2c7d9084e1fa9", - "name": "SEND msg to EPMX", - "func": "var requestId = Math.floor(Math.random()*100);\n\n// creates message to send\nmsg.topic = \"kp1/\" + msg.applicationVersion + \"/epmx/\" + msg.token + \"/update/keys/\" + requestId;\n\nreturn msg;", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 1260, - "y": 280, - "wires": [ - [ - "2ee0531dc3f57930", - "9a4cb5651b35323f" - ] - ] - }, - { - "id": "2ee0531dc3f57930", - "type": "debug", - "z": "bde2c7d9084e1fa9", - "name": "", - "active": false, - "tosidebar": true, - "console": false, - "tostatus": false, - "complete": "true", - "targetType": "full", - "statusVal": "", - "statusType": "auto", - "x": 1450, - "y": 260, - "wires": [] - }, - { - "id": "8cc6f5051471b6e0", - "type": "function", - "z": "bde2c7d9084e1fa9", - "name": "SEND msg to DCX", - "func": "msg.topic = \"kp1/\" + msg.applicationVersion + \"/dcx/\" + msg.token + \"/json\";\n\nreturn msg;", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 1270, - "y": 360, - "wires": [ - [ - "207c92efc66d09e7", - "9a4cb5651b35323f" - ] - ] - }, - { - "id": "207c92efc66d09e7", - "type": "debug", - "z": "bde2c7d9084e1fa9", - "name": "", - "active": true, - "tosidebar": true, - "console": false, - "tostatus": false, - "complete": "true", - "targetType": "full", - "statusVal": "", - "statusType": "auto", - "x": 1450, - "y": 380, - "wires": [] - }, - { - "id": "6bb92953f4c7c05a", - "type": "function", - "z": "bde2c7d9084e1fa9", - "name": "PARSE AVL IO data", - "func": "var avl = msg.avl;\n\nvar payload = {};\npayload.timestamp = avl.timestamp;\npayload.altitude = avl.GPS.altitude;\npayload.angle = avl.GPS.angle;\npayload.satellites = avl.GPS.satellites;\npayload.latitude = avl.GPS.latitude;\npayload.longitude = avl.GPS.longitude;\n\nif (avl.axis != undefined) {\n payload.axis_x = avl.axis.x;\n payload.axis_y = avl.axis.y;\n payload.axis_z = avl.axis.z;\n}\n\n// fuel Used GPS\nvar fuelUsedGps = getIoData(12);\nif (fuelUsedGps != null) {\n payload.fuelUsedGps = fuelUsedGps;\n}\n\n// fuel Rate GPS\nvar fuelRateGps = getIoData(13);\nif (fuelRateGps != null) {\n payload.fuelRateGps = fuelRateGps;\n}\n\n// total odometer\nvar totalOdometer = getIoData(16);\nif (totalOdometer != null) {\n payload.totalOdometer = totalOdometer / 1000;\n}\n\n// gsmSignal\nvar gsmSignal = getIoData(21);\nif (gsmSignal != null) {\n payload.gsmSignal = gsmSignal;\n}\n\n// speed\nvar speed = getIoData(24);\nif (speed != null) {\n payload.speed = speed;\n}\n\n// obdDtcNumber\nvar obdDtcNumber = getIoData(30);\nif (obdDtcNumber != null) {\n payload.obdDtcNumber = obdDtcNumber;\n}\n\n// obdEngineLoad\nvar obdEngineLoad = getIoData(31);\nif (obdEngineLoad != null) {\n payload.obdEngineLoad = obdEngineLoad;\n}\n\n// obdCoolantTemperature\nvar obdCoolantTemperature = getIoData(32);\nif (obdCoolantTemperature != null) {\n payload.obdCoolantTemperature = obdCoolantTemperature;\n}\n\n// obdShortFuelTrim\nvar obdShortFuelTrim = getIoData(33);\nif (obdShortFuelTrim != null) {\n payload.obdShortFuelTrim = obdShortFuelTrim;\n}\n\n// obdFuelPressure\nvar obdFuelPressure = getIoData(34);\nif (obdFuelPressure != null) {\n payload.obdFuelPressure = obdFuelPressure;\n}\n\n// obdIntakeMAP\nvar obdIntakeMAP = getIoData(35);\nif (obdIntakeMAP != null) {\n payload.obdIntakeMAP = obdIntakeMAP;\n}\n\n// obdEngineRPM\nvar obdEngineRPM = getIoData(36);\nif (obdEngineRPM != null) {\n payload.obdEngineRPM = obdEngineRPM;\n}\n\n// obdVehicleSpeed\nvar obdVehicleSpeed = getIoData(37);\nif (obdVehicleSpeed != null) {\n payload.obdVehicleSpeed = obdVehicleSpeed;\n}\n\n// obdTimingAdvance\nvar obdTimingAdvance = getIoData(38);\nif (obdTimingAdvance != null) {\n payload.obdTimingAdvance = obdTimingAdvance;\n}\n\n// obdIntakeAirTemperature\nvar obdIntakeAirTemperature = getIoData(39);\nif (obdIntakeAirTemperature != null) {\n payload.obdIntakeAirTemperature = obdIntakeAirTemperature;\n}\n\n// obdThrottlePosition\nvar obdThrottlePosition = getIoData(41);\nif (obdThrottlePosition != null) {\n payload.obdThrottlePosition = obdThrottlePosition;\n}\n\n// obdDistanceTraveledMILon\nvar obdDistanceTraveledMILon = getIoData(43);\nif (obdDistanceTraveledMILon != null) {\n payload.obdDistanceTraveledMILon = obdDistanceTraveledMILon;\n}\n\n// obdFuelLevel\nvar obdFuelLevel = getIoData(48);\nif (obdFuelLevel != null) {\n payload.obdFuelLevel = obdFuelLevel;\n} else {\n payload.obdFuelLevel = 50;\n}\n\n// engineOilTemperature\nvar engineOilTemperature = getIoData(58);\nif (engineOilTemperature != null) {\n payload.engineOilTemperature = engineOilTemperature;\n}\n\n// fuelRate\nvar fuelRate = getIoData(60);\nif (fuelRate != null) {\n payload.fuelRate = fuelRate;\n}\n\n// externalVoltage\nvar externalVoltage = getIoData(66);\nif (externalVoltage != null) {\n payload.externalVoltage = externalVoltage;\n}\n\n// batteryVoltage\nvar batteryVoltage = getIoData(67);\nif (batteryVoltage != null) {\n payload.batteryVoltage = batteryVoltage;\n}\n\n// batteryCurrent\nvar batteryCurrent = getIoData(68);\nif (batteryCurrent != null) {\n payload.batteryCurrent = batteryCurrent;\n}\n\n// gnssStatus\nvar gnssStatus = getIoData(69);\nif (gnssStatus != null) {\n payload.gnssStatus = gnssStatus;\n}\n\n// batteryLevel\nvar batteryLevel = getIoData(113);\nif (batteryLevel != null) {\n payload.batteryLevel = batteryLevel;\n}\n\n// tripOdometer\nvar tripOdometer = getIoData(199);\nif (tripOdometer != null) {\n payload.tripOdometer = tripOdometer;\n}\n\n// gsmCellId\nvar gsmCellId = getIoData(205);\nif (gsmCellId != null) {\n payload.gsmCellId = gsmCellId;\n}\n\n// gsmAreaCode\nvar gsmAreaCode = getIoData(206);\nif (gsmAreaCode != null) {\n payload.gsmAreaCode = gsmAreaCode;\n}\n\n// ignition\nvar ignition = getIoData(239);\nif (ignition != null) {\n payload.ignition = ignition;\n}\n\n// movement\nvar movement = getIoData(240);\nif (movement != null) {\n payload.movement = movement;\n}\n\n// btStatus\nvar btStatus = getIoData(263);\nif (btStatus != null) {\n payload.btStatus = btStatus;\n}\n\n// instantMovement\nvar instantMovement = getIoData(303);\nif (instantMovement != null) {\n payload.instantMovement = instantMovement;\n}\n\n// obdOemTotalMileage\nvar obdOemTotalMileage = getIoData(389);\nif (obdOemTotalMileage != null) {\n payload.obdOemTotalMileage = obdOemTotalMileage;\n}\n\n// obdOemFuelLevel\nvar obdOemFuelLevel = getIoData(390);\nif (obdOemFuelLevel != null) {\n payload.obdOemFuelLevel = obdOemFuelLevel / 10;\n} else {\n payload.obdOemFuelLevel = 50;\n}\n\n// creates message to send\nvar result = {};\nresult.payload = payload;\nresult.token = msg.token;\nresult.applicationVersion = msg.applicationVersion;\n\nreturn result;\n\n//**********************************************************************************************\n// getIoData\n// Get IO data with specified AVL ID\n//**********************************************************************************************\nfunction getIoData(id) {\n if (avl.ioData.get(id) != null) {\n return avl.ioData.get(id);\n } else {\n return avl.ioData.get(id.toString());\n }\n}", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 960, - "y": 200, - "wires": [ - [ - "a7b4e83044812b5a" - ] - ] - }, - { - "id": "4bb019c7b06b724c", - "type": "function", - "z": "bde2c7d9084e1fa9", - "name": "TO msgs", - "func": "var avl = msg.payload.avl[msg.numberOfData - 1];\n\nvar messages = [];\nfor (var i=0; i 0x7FFFFFFF) {\n value -= 0x100000000;\n }\n return value / 10000000;\n}\n\n//**********************************************************************************************\n// parseIOelement\n//**********************************************************************************************\nfunction parseIOelement() {\n avl.eventIoID = getNextInt16();\n\n //if (avl.eventIoID == 385) {\n // parseBeacon();\n // getNextInt8();\n //} else {\n parseUsualIOelements();\n decodeUsualIOelements();\n //}\n}\n\n//**********************************************************************************************\n// parseBeacon\n//**********************************************************************************************\nfunction parseBeacon(array) {\n const BEACON_LENGTH = 20;\n const EDDY_LENGTH = 16;\n\n var avl = {};\n\n avl.beaconLength = array.length;\n\n var ptr = 0;\n\n // dataPart\n avl.dataPart = array[ptr++];\n avl.beaconRecordsCount = avl.dataPart & 0x0F;\n avl.recordNumber = (avl.dataPart & 0xF0) >> 4;\n\n if (avl.beaconLength < EDDY_LENGTH) {\n return avl;\n }\n\n // flags\n avl.flag = array[ptr++];\n avl.sygnalStrenghAvailable = ((avl.flag & 0x01) > 0) ? 1 : 0;\n avl.beaconDataSent = ((avl.flag & 0x20) > 0) ? 1 : 0;\n\n // beacons\n if (avl.beaconDataSent != 0) {\n // beacon data\n avl.beaconId = array.slice(ptr, ptr + BEACON_LENGTH);\n ptr += BEACON_LENGTH;\n if (avl.sygnalStrenghAvailable != 0) {\n avl.BeaconRssi = array[ptr++];\n }\n }\n\n return avl;\n}\n\n//**********************************************************************************************\n// parseUsualIOelements\n//**********************************************************************************************\nfunction parseUsualIOelements() {\n avl.nTotalIo = getNextInt16();\n avl.n1Io = getNextInt16();\n avl.ioData = new Map();\n var i = 0;\n for (i = 0; i < avl.n1Io; i++) {\n var n1IoId = getNextInt16();\n var n1IoValue = getNextInt8();\n if (n1IoValue >= 128) {\n n1IoValue = n1IoValue - 256;\n }\n avl.ioData.set(n1IoId, n1IoValue);\n }\n\n if (inputDataPtr >= parsedMsg.fullPacketLength) { return [null, null]; }\n avl.n2Io = getNextInt16();\n for (i = 0; i < avl.n2Io; i++) {\n var n2IoId = getNextInt16();\n var n2IoValue = getNextInt16();\n if (n2IoValue >= 0x8000) {\n n2IoValue = n2IoValue - 0x8000;\n }\n avl.ioData.set(n2IoId, n2IoValue);\n }\n\n if (inputDataPtr >= parsedMsg.fullPacketLength) { return [null, null]; }\n avl.n4Io = getNextInt16();\n for (i = 0; i < avl.n4Io; i++) {\n var n4IoId = getNextInt16();\n var n4IoValue = getNextInt32();\n if (n4IoValue >= 0x80000000) {\n n4IoValue = n4IoValue - 0x80000000;\n }\n avl.ioData.set(n4IoId, n4IoValue);\n }\n\n if (inputDataPtr >= parsedMsg.fullPacketLength) { return [null, null]; }\n avl.n8Io = getNextInt16();\n for (i = 0; i < avl.n8Io; i++) {\n var n8IoId = getNextInt16();\n //var n8IoSubArray = getNextSubArray(8);\n var n8IoValue = getNextInt64();\n if (n8IoValue >= 0x8000000000000000) {\n n8IoValue = n8IoValue - 0x8000000000000000;\n }\n //node.warn(n8IoValue);\n avl.ioData.set(n8IoId, n8IoValue);\n }\n avl.nxIo = getNextInt16();\n for (i = 0; i < avl.nxIo; i++) {\n var nxIoId = getNextInt16();\n var nxIoLength = getNextInt16();\n if (nxIoId == 385) {\n avl.ioData.set(nxIoId, parseBeacon(getNextSubArray(nxIoLength)));\n } else {\n avl.ioData.set(nxIoId, getNextSubArray(nxIoLength));\n }\n }\n}\n\n//**********************************************************************************************\n// decodeUsualIOelements\n//**********************************************************************************************\nfunction decodeUsualIOelements() {\n avl.axis = {};\n avl.axis.x = avl.ioData.get(17);\n avl.axis.y = avl.ioData.get(18);\n avl.axis.z = avl.ioData.get(19);\n}\n\n//**********************************************************************************************\n// getCharArray\n//**********************************************************************************************\nfunction getCharArray(array) {\n const result = [];\n for (var i = 0; i < array.length; i++) {\n result.push(String.fromCharCode(array[i]));\n }\n return result;\n}\n\n//**********************************************************************************************\n// getNextSubArray\n//**********************************************************************************************\nfunction getNextSubArray(length) {\n var subarray = inputMsg.slice(inputDataPtr, inputDataPtr + length);\n inputDataPtr += length;\n return subarray;\n}\n\n//**********************************************************************************************\n// getNextInt8\n//**********************************************************************************************\nfunction getNextInt8() {\n return inputMsg[inputDataPtr++];\n}\n\n//**********************************************************************************************\n// getNextInt16\n//**********************************************************************************************\nfunction getNextInt16() {\n var value = inputMsg[inputDataPtr++];\n value = (value << 8) + inputMsg[inputDataPtr++];\n return value;\n}\n\n//**********************************************************************************************\n// getNextInt32\n//**********************************************************************************************\nfunction getNextInt32() {\n var value = inputMsg[inputDataPtr++];\n value = (value << 8) + inputMsg[inputDataPtr++];\n value = (value << 8) + inputMsg[inputDataPtr++];\n value = (value << 8) + inputMsg[inputDataPtr++];\n return value;\n}\n\n//**********************************************************************************************\n// getNextInt64\n//**********************************************************************************************\nfunction getNextInt64() {\n var value = inputMsg[inputDataPtr++];\n value = (value << 8) + inputMsg[inputDataPtr++];\n value = (value << 8) + inputMsg[inputDataPtr++];\n value = (value << 8) + inputMsg[inputDataPtr++];\n value = (value << 8) + inputMsg[inputDataPtr++];\n value = (value << 8) + inputMsg[inputDataPtr++];\n value = (value << 8) + inputMsg[inputDataPtr++];\n value = (value << 8) + inputMsg[inputDataPtr++];\n return value;\n}\n\n//**********************************************************************************************\n// Calculates the buffers CRC-16/IBM.\n//**********************************************************************************************\nfunction crc16(buffer, startPtr, length) {\n var crc = 0;\n var odd;\n\n for (var i = 0; i < length; i++) {\n crc = crc ^ buffer[i + startPtr];\n\n var numBit = 0;\n do {\n odd = crc & 0x0001;\n crc = crc >> 1;\n if (odd == 1) {\n crc = crc ^ 0xA001;\n }\n numBit++;\n } while (numBit < 8);\n }\n\n return crc;\n};", + "outputs": 2, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 260, + "wires": [ + [ + "0e7ef225e445c758", + "18b3dfde097451d1" + ], + [ + "63b71825da12406c", + "3d65e2931542de30" + ] + ] + }, + { + "id": "0e7ef225e445c758", + "type": "debug", + "z": "bde2c7d9084e1fa9", + "name": "PARSED data", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "true", + "targetType": "full", + "statusVal": "", + "statusType": "auto", + "x": 520, + "y": 240, + "wires": [] + }, + { + "id": "e54797cf40844cf2", + "type": "inject", + "z": "bde2c7d9084e1fa9", + "name": "Trigger", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": true, + "onceDelay": "", + "topic": "", + "payload": "", + "payloadType": "date", + "x": 140, + "y": 100, + "wires": [ + [ + "ed4c731ecb5921bf" + ] + ] + }, + { + "id": "cb562ce75e8f1d6a", + "type": "function", + "z": "bde2c7d9084e1fa9", + "name": "USER config", + "func": "/*\n Fill before using:\n - application version\n*/\n\nconst TRACKER_APP_VERSION = \"chfq5afsj3ic738hqpd0-v1\";\nflow.set(\"TRACKER_APP_VERSION\", TRACKER_APP_VERSION);\n\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 530, + "y": 100, + "wires": [ + [] + ] + }, + { + "id": "ed4c731ecb5921bf", + "type": "function", + "z": "bde2c7d9084e1fa9", + "name": "INIT flow context", + "func": "const tcpSessions = new Map();\nflow.set(\"TCP_SESSIONS\", tcpSessions);\n\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 330, + "y": 100, + "wires": [ + [ + "cb562ce75e8f1d6a" + ] + ] + }, + { + "id": "fabe947dd3edbd38", + "type": "comment", + "z": "bde2c7d9084e1fa9", + "name": "Please, fill USER config before using!!!", + "info": "", + "x": 610, + "y": 60, + "wires": [] + }, + { + "id": "18b3dfde097451d1", + "type": "function", + "z": "bde2c7d9084e1fa9", + "name": "FIND IMEI by sessionID", + "func": "var IMEI = lookForImeiBySession(msg._session);\n\nif (IMEI != null) {\n var moduleIMEI = toImeiString(Buffer.from(IMEI, 'utf8'));\n\n msg.token = moduleIMEI;\n msg.applicationVersion = flow.get(\"TRACKER_APP_VERSION\");\n\n return msg;\n}\n\nnode.warn(\"Session with ID: \" + msg._session.id + \" not found\");\nreturn null;\n\n//****************************************************************************************\n// functions\n//****************************************************************************************\nfunction lookForImeiBySession(session) {\n var tempIMEI = null;\n const TCP_SESSIONS = flow.get(\"TCP_SESSIONS\");\n TCP_SESSIONS.forEach(function (value, key, map) {\n if(value.id === session.id) {\n tempIMEI = key;\n }\n });\n return tempIMEI;\n}\n\nfunction toImeiString(IMEIarray) {\n var result = \"\";\n for (var i = 0; i < IMEIarray.length; i++) {\n result += String.fromCharCode(IMEIarray[i]);\n }\n return result;\n}", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 550, + "y": 200, + "wires": [ + [ + "4bb019c7b06b724c" + ] + ] + }, + { + "id": "30c07c74d031f354", + "type": "function", + "z": "bde2c7d9084e1fa9", + "name": "SAVE IMEI and send TCP reply", + "func": "var inputDataPtr = 0;\n\nvar inputMsg = msg.payload;\n\n// IMEI length & IMEI\nvar imeiLength = getNextInt16();\nif (imeiLength != 15) {\n node.error(\"Wrong imei length: \" + imeiLength);\n return null;\n}\nvar moduleIMEI = toImeiString(getNextSubArray(imeiLength));\n\nif (msg._session.type !== \"tcp\") {\n node.warn(\"Wrong session type: \" + msg.session.type);\n return;\n}\n\nconst TCP_SESSIONS = flow.get(\"TCP_SESSIONS\");\nif (TCP_SESSIONS.get(moduleIMEI)) {\n node.debug(\"Update session for the IMEI: \" + moduleIMEI);\n TCP_SESSIONS.set(moduleIMEI, msg._session);\n} else {\n node.debug(\"Create session for the IMEI: \" + moduleIMEI);\n TCP_SESSIONS.set(moduleIMEI, msg._session);\n}\nflow.set(\"TCP_SESSIONS\", TCP_SESSIONS);\n\nmsg.payload = Buffer.from(\"\\x01\");\n\nreturn msg;\n\n\n//**********************************************************************************************\n// toImeiString\n//**********************************************************************************************\nfunction toImeiString(IMEIarray) {\n var result = \"\";\n for (var i = 0; i < IMEIarray.length; i++) {\n result += String.fromCharCode(IMEIarray[i]);\n }\n return result;\n}\n\n//**********************************************************************************************\n// getNextSubArray\n//**********************************************************************************************\nfunction getNextSubArray(length) {\n var subarray = inputMsg.slice(inputDataPtr, inputDataPtr + length);\n inputDataPtr += length;\n return subarray;\n}\n\n//**********************************************************************************************\n// getNextInt16\n//**********************************************************************************************\nfunction getNextInt16() {\n var value = inputMsg[inputDataPtr++];\n value = value * 256 + inputMsg[inputDataPtr++];\n return value;\n}", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 490, + "y": 540, + "wires": [ + [ + "63b71825da12406c" + ] + ] + }, + { + "id": "507b354d815858fa", + "type": "function", + "z": "bde2c7d9084e1fa9", + "name": "SEND msg to EPMX", + "func": "var requestId = Math.floor(Math.random()*100);\n\n// creates message to send\nmsg.topic = \"kp1/\" + msg.applicationVersion + \"/epmx/\" + msg.token + \"/update/keys/\" + requestId;\n\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 1260, + "y": 280, + "wires": [ + [ + "2ee0531dc3f57930", + "9a4cb5651b35323f" + ] + ] + }, + { + "id": "2ee0531dc3f57930", + "type": "debug", + "z": "bde2c7d9084e1fa9", + "name": "", + "active": false, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "true", + "targetType": "full", + "statusVal": "", + "statusType": "auto", + "x": 1450, + "y": 260, + "wires": [] + }, + { + "id": "8cc6f5051471b6e0", + "type": "function", + "z": "bde2c7d9084e1fa9", + "name": "SEND msg to DCX", + "func": "msg.topic = \"kp1/\" + msg.applicationVersion + \"/dcx/\" + msg.token + \"/json\";\n\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 1270, + "y": 360, + "wires": [ + [ + "207c92efc66d09e7", + "9a4cb5651b35323f" + ] + ] + }, + { + "id": "207c92efc66d09e7", + "type": "debug", + "z": "bde2c7d9084e1fa9", + "name": "", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "true", + "targetType": "full", + "statusVal": "", + "statusType": "auto", + "x": 1450, + "y": 380, + "wires": [] + }, + { + "id": "6bb92953f4c7c05a", + "type": "function", + "z": "bde2c7d9084e1fa9", + "name": "PARSE AVL IO data", + "func": "var avl = msg.avl;\n\nvar payload = {};\npayload.timestamp = avl.timestamp;\npayload.altitude = avl.GPS.altitude;\npayload.angle = avl.GPS.angle;\npayload.satellites = avl.GPS.satellites;\npayload.latitude = avl.GPS.latitude;\npayload.longitude = avl.GPS.longitude;\n\nif (avl.axis != undefined) {\n payload.axis_x = avl.axis.x;\n payload.axis_y = avl.axis.y;\n payload.axis_z = avl.axis.z;\n}\n\n// fuel Used GPS\nvar fuelUsedGps = getIoData(12);\nif (fuelUsedGps != null) {\n payload.fuelUsedGps = fuelUsedGps;\n}\n\n// fuel Rate GPS\nvar fuelRateGps = getIoData(13);\nif (fuelRateGps != null) {\n payload.fuelRateGps = fuelRateGps;\n}\n\n// total odometer\nvar totalOdometer = getIoData(16);\nif (totalOdometer != null) {\n payload.totalOdometer = totalOdometer / 1000;\n}\n\n// gsmSignal\nvar gsmSignal = getIoData(21);\nif (gsmSignal != null) {\n payload.gsmSignal = gsmSignal;\n}\n\n// speed\nvar speed = getIoData(24);\nif (speed != null) {\n payload.speed = speed;\n}\n\n// obdDtcNumber\nvar obdDtcNumber = getIoData(30);\nif (obdDtcNumber != null) {\n payload.obdDtcNumber = obdDtcNumber;\n}\n\n// obdEngineLoad\nvar obdEngineLoad = getIoData(31);\nif (obdEngineLoad != null) {\n payload.obdEngineLoad = obdEngineLoad;\n}\n\n// obdCoolantTemperature\nvar obdCoolantTemperature = getIoData(32);\nif (obdCoolantTemperature != null) {\n payload.obdCoolantTemperature = obdCoolantTemperature;\n}\n\n// obdShortFuelTrim\nvar obdShortFuelTrim = getIoData(33);\nif (obdShortFuelTrim != null) {\n payload.obdShortFuelTrim = obdShortFuelTrim;\n}\n\n// obdFuelPressure\nvar obdFuelPressure = getIoData(34);\nif (obdFuelPressure != null) {\n payload.obdFuelPressure = obdFuelPressure;\n}\n\n// obdIntakeMAP\nvar obdIntakeMAP = getIoData(35);\nif (obdIntakeMAP != null) {\n payload.obdIntakeMAP = obdIntakeMAP;\n}\n\n// obdEngineRPM\nvar obdEngineRPM = getIoData(36);\nif (obdEngineRPM != null) {\n payload.obdEngineRPM = obdEngineRPM;\n}\n\n// obdVehicleSpeed\nvar obdVehicleSpeed = getIoData(37);\nif (obdVehicleSpeed != null) {\n payload.obdVehicleSpeed = obdVehicleSpeed;\n}\n\n// obdTimingAdvance\nvar obdTimingAdvance = getIoData(38);\nif (obdTimingAdvance != null) {\n payload.obdTimingAdvance = obdTimingAdvance;\n}\n\n// obdIntakeAirTemperature\nvar obdIntakeAirTemperature = getIoData(39);\nif (obdIntakeAirTemperature != null) {\n payload.obdIntakeAirTemperature = obdIntakeAirTemperature;\n}\n\n// obdThrottlePosition\nvar obdThrottlePosition = getIoData(41);\nif (obdThrottlePosition != null) {\n payload.obdThrottlePosition = obdThrottlePosition;\n}\n\n// obdDistanceTraveledMILon\nvar obdDistanceTraveledMILon = getIoData(43);\nif (obdDistanceTraveledMILon != null) {\n payload.obdDistanceTraveledMILon = obdDistanceTraveledMILon;\n}\n\n// obdFuelLevel\nvar obdFuelLevel = getIoData(48);\nif (obdFuelLevel != null) {\n payload.obdFuelLevel = obdFuelLevel;\n} else {\n payload.obdFuelLevel = 50;\n}\n\n// engineOilTemperature\nvar engineOilTemperature = getIoData(58);\nif (engineOilTemperature != null) {\n payload.engineOilTemperature = engineOilTemperature;\n}\n\n// fuelRate\nvar fuelRate = getIoData(60);\nif (fuelRate != null) {\n payload.fuelRate = fuelRate;\n}\n\n// externalVoltage\nvar externalVoltage = getIoData(66);\nif (externalVoltage != null) {\n payload.externalVoltage = externalVoltage;\n}\n\n// batteryVoltage\nvar batteryVoltage = getIoData(67);\nif (batteryVoltage != null) {\n payload.batteryVoltage = batteryVoltage;\n}\n\n// batteryCurrent\nvar batteryCurrent = getIoData(68);\nif (batteryCurrent != null) {\n payload.batteryCurrent = batteryCurrent;\n}\n\n// gnssStatus\nvar gnssStatus = getIoData(69);\nif (gnssStatus != null) {\n payload.gnssStatus = gnssStatus;\n}\n\n// batteryLevel\nvar batteryLevel = getIoData(113);\nif (batteryLevel != null) {\n payload.batteryLevel = batteryLevel;\n}\n\n// tripOdometer\nvar tripOdometer = getIoData(199);\nif (tripOdometer != null) {\n payload.tripOdometer = tripOdometer;\n}\n\n// gsmCellId\nvar gsmCellId = getIoData(205);\nif (gsmCellId != null) {\n payload.gsmCellId = gsmCellId;\n}\n\n// gsmAreaCode\nvar gsmAreaCode = getIoData(206);\nif (gsmAreaCode != null) {\n payload.gsmAreaCode = gsmAreaCode;\n}\n\n// ignition\nvar ignition = getIoData(239);\nif (ignition != null) {\n payload.ignition = ignition;\n}\n\n// movement\nvar movement = getIoData(240);\nif (movement != null) {\n payload.movement = movement;\n}\n\n// btStatus\nvar btStatus = getIoData(263);\nif (btStatus != null) {\n payload.btStatus = btStatus;\n}\n\n// instantMovement\nvar instantMovement = getIoData(303);\nif (instantMovement != null) {\n payload.instantMovement = instantMovement;\n}\n\n// obdOemTotalMileage\nvar obdOemTotalMileage = getIoData(389);\nif (obdOemTotalMileage != null) {\n payload.obdOemTotalMileage = obdOemTotalMileage;\n}\n\n// obdOemFuelLevel\nvar obdOemFuelLevel = getIoData(390);\nif (obdOemFuelLevel != null) {\n payload.obdOemFuelLevel = obdOemFuelLevel / 10;\n} else {\n payload.obdOemFuelLevel = 50;\n}\n\n// creates message to send\nvar result = {};\nresult.payload = payload;\nresult.token = msg.token;\nresult.applicationVersion = msg.applicationVersion;\n\nreturn result;\n\n//**********************************************************************************************\n// getIoData\n// Get IO data with specified AVL ID\n//**********************************************************************************************\nfunction getIoData(id) {\n if (avl.ioData.get(id) != null) {\n return avl.ioData.get(id);\n } else {\n return avl.ioData.get(id.toString());\n }\n}", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 960, + "y": 200, + "wires": [ + [ + "a7b4e83044812b5a" + ] + ] + }, + { + "id": "4bb019c7b06b724c", + "type": "function", + "z": "bde2c7d9084e1fa9", + "name": "TO msgs", + "func": "var avl = msg.payload.avl[msg.numberOfData - 1];\n\nvar messages = [];\nfor (var i=0; i