[ { "id": "f86392651850d084", "type": "tab", "label": "Meshtastic Flow", "disabled": false, "info": "", "env": [] }, { "id": "a832ad4ec196570a", "type": "subflow", "name": "Ingest from MQTT", "info": "", "category": "input", "in": [], "out": [ { "x": 1430, "y": 100, "wires": [ { "id": "13c14b6192865d27", "port": 0 } ] } ], "env": [], "meta": {}, "color": "#67EA94", "outputLabels": [ "Decoded Packets" ], "icon": "@meshtastic/node-red-contrib-meshtastic/logo.svg" }, { "id": "8dd264d8b2b469c1", "type": "subflow", "name": "Measurement: Mesh", "info": "", "category": "output", "in": [ { "x": 120, "y": 200, "wires": [ { "id": "96e553854838f2f4" } ] } ], "out": [], "env": [], "meta": {}, "color": "#C0DEED", "inputLabels": [ "Packet" ], "icon": "node-red-contrib-influxdb/influxdb.png" }, { "id": "3e0ee1b8ba4768f0", "type": "subflow", "name": "Measurement: Packet", "info": "", "category": "output", "in": [ { "x": 120, "y": 140, "wires": [ { "id": "ea40b1047dcb281e" } ] } ], "out": [], "env": [], "meta": {}, "color": "#C0DEED", "inputLabels": [ "Packet" ], "icon": "node-red-contrib-influxdb/influxdb.png" }, { "id": "f9e40322037c429a", "type": "subflow", "name": "Measurement: Position", "info": "", "category": "output", "in": [ { "x": 160, "y": 180, "wires": [ { "id": "af1ead55008aa3a1" } ] } ], "out": [], "env": [], "meta": {}, "color": "#C0DEED", "inputLabels": [ "Position" ], "icon": "node-red-contrib-influxdb/influxdb.png" }, { "id": "496cbfc0434e783d", "type": "subflow", "name": "Measurement: Device Telemetry", "info": "", "category": "output", "in": [ { "x": 100, "y": 120, "wires": [ { "id": "33c5dc88fcd1bf4b" } ] } ], "out": [], "env": [], "meta": {}, "color": "#C0DEED", "inputLabels": [ "Device Telemetry" ], "icon": "node-red-contrib-influxdb/influxdb.png" }, { "id": "0ca01258e3f5252a", "type": "subflow", "name": "Measurement: Environment Telemetry", "info": "", "category": "output", "in": [ { "x": 60, "y": 120, "wires": [ { "id": "8569754e02703706" } ] } ], "out": [], "env": [], "meta": {}, "color": "#C0DEED", "inputLabels": [ "Environment Telemetry" ], "icon": "node-red-contrib-influxdb/influxdb.png" }, { "id": "d96c8f45d69c34f7", "type": "influxdb", "hostname": "influxdb", "port": "8086", "protocol": "http", "database": "msh", "name": "Local InfluxDB", "usetls": false, "tls": "", "influxdbVersion": "1.x", "url": "http://localhost:8086", "rejectUnauthorized": true }, { "id": "07b2da65ae42f546", "type": "mqtt-broker", "name": "Mosquito", "broker": "mqtt-mosquitto", "port": "1883", "clientid": "", "autoConnect": true, "usetls": false, "protocolVersion": "4", "keepalive": "60", "cleansession": true, "birthTopic": "node-red", "birthQos": "0", "birthRetain": "true", "birthPayload": "node-red connected", "birthMsg": {}, "closeTopic": "node-red", "closeQos": "0", "closeRetain": "true", "closePayload": "node-red disconnected", "closeMsg": {}, "willTopic": "", "willQos": "0", "willPayload": "", "willMsg": {}, "userProps": "", "sessionExpiry": "" }, { "id": "63da12e4baeff017", "type": "debug", "z": "a832ad4ec196570a", "name": "Node Names and Hardware Injected", "active": false, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "statusVal": "", "statusType": "auto", "x": 1490, "y": 40, "wires": [] }, { "id": "4c809ff0174c8ff0", "type": "function", "z": "a832ad4ec196570a", "name": "Translate Node Identifiers to Hex", "func": "msg.payload.packet.toHex = '!' + msg.payload.packet.to.toString(16).padStart(8,0)\nmsg.payload.packet.fromHex = '!' + msg.payload.packet.from.toString(16).padStart(8, 0)\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 840, "y": 100, "wires": [ [ "13c14b6192865d27", "63fd66d3272ed10b" ] ] }, { "id": "7e3ebbab282b1482", "type": "debug", "z": "a832ad4ec196570a", "name": "Original Messages", "active": false, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "statusVal": "", "statusType": "auto", "x": 790, "y": 60, "wires": [] }, { "id": "08806f9cfe03f282", "type": "debug", "z": "a832ad4ec196570a", "name": "Duplicate Messages", "active": false, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "statusVal": "", "statusType": "auto", "x": 800, "y": 140, "wires": [] }, { "id": "938a1c3c0bdbd155", "type": "mqtt in", "z": "a832ad4ec196570a", "name": "Injest from MQTT", "topic": "msh/+/c/#", "qos": "1", "datatype": "auto-detect", "broker": "07b2da65ae42f546", "nl": false, "rap": true, "rh": 0, "inputs": 0, "x": 100, "y": 100, "wires": [ [ "1ed79fa8cae54ee4" ] ] }, { "id": "e35eb249e35ecfb3", "type": "debug", "z": "a832ad4ec196570a", "name": "Decoded Message", "active": false, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "statusVal": "", "statusType": "auto", "x": 490, "y": 60, "wires": [] }, { "id": "63fd66d3272ed10b", "type": "debug", "z": "a832ad4ec196570a", "name": "Nodes Identified by Hex", "active": false, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "statusVal": "", "statusType": "auto", "x": 1130, "y": 60, "wires": [] }, { "id": "13c14b6192865d27", "type": "function", "z": "a832ad4ec196570a", "name": "Inject Node Names and Hardware", "func": "var nodeShortNames = global.get('nodeShortNames')\nvar nodeLongNames = global.get('nodeLongNames')\nvar nodeHardware = global.get('nodeHardware')\n\nif (nodeShortNames === undefined) nodeShortNames = {}\nif (nodeLongNames === undefined) nodeLongNames = {}\nif (nodeHardware === undefined) nodeHardware = {}\n\nvar packet = msg.payload.packet\n\nvar unknown = \"unknown\"\n\nvar hardwareMap = {\n 0: \"UNSET\",\n 1: \"TLORA_V2\",\n 2: \"TLORA_V1\",\n 3: \"TLORA_V2_1_1.6\",\n 4: \"TBEAM\",\n 5: \"HELTEC_V2_0\",\n 6: \"TBEAM_V0.7\",\n 7: \"T_ECHO\",\n 8: \"TLORA_V1_1.3\",\n 9: \"RAK4631\",\n 10: \"HELTEC_V2_1\",\n 11: \"HELTEC_V1\",\n 12: \"LILYGO_TBEAM_S3_CORE\",\n 13: \"RAK11200\",\n 14: \"NANO_G1\",\n 15: \"TLORA_V2_1_1.8\",\n 16: \"TLORA_T3_S3\",\n 17: \"NANO_G1_EXPLORER\",\n 18: \"NANO_G2_ULTRA\",\n 19: \"LORA_TYPE\",\n 25: \"STATION_G1\",\n 26: \"RAK11310\",\n 32: \"LORA_RELAY_V1\",\n 33: \"NRF52840DK\",\n 34: \"PPR\",\n 35: \"GENIEBLOCKS\",\n 36: \"NRF52_UNKNOWN\",\n 37: \"PORTDUINO\",\n 38: \"ANDROID_SIM\",\n 39: \"DIY_V1\",\n 40: \"NRF52840_PCA10059\",\n 41: \"DR_DEV\",\n 42: \"M5STACK\",\n 43: \"HELTEC_V3\",\n 44: \"HELTEC_WSL_V3\",\n 45: \"BETAFPV_2400_TX\",\n 46: \"BETAFPV_900_NANO_TX\",\n 47: \"RPI_PICO\",\n 48: \"HELTEC_WIRELESS_TRACKER\",\n 49: \"HELTEC_WIRELESS_PAPER\",\n 50: \"T_DECK\",\n 51: \"T_WATCH_S3\",\n 52: \"PICOMPUTER_S3\",\n 53: \"HELTEC_HT62\",\n 54: \"EBYTE_ESP32_S3\",\n 255: \"PRIVATE_HW\"\n}\n\n// inject From names and hardware info\nif (nodeShortNames.hasOwnProperty(packet.fromHex)){\n packet.fromShortName = nodeShortNames[packet.fromHex]\n} else {\n packet.fromShortName = unknown\n}\n\nif (nodeShortNames.hasOwnProperty(packet.fromHex)) {\n packet.fromShortName = nodeShortNames[packet.fromHex]\n} else {\n packet.fromShortName = unknown\n}\n\nif (nodeLongNames.hasOwnProperty(packet.fromHex)) {\n packet.fromLongName = nodeLongNames[packet.fromHex]\n} else {\n packet.fromLongName = unknown\n}\n\nif (nodeHardware.hasOwnProperty(packet.fromHex)) {\n packet.fromHardware = hardwareMap[nodeHardware[packet.fromHex]]\n} else {\n packet.fromHardware = unknown\n}\n\n// handle messages to mesh\nif (packet.toHex === \"!ffffffff\") {\n packet.toShortName = \"mesh\"\n packet.toLongName = \"Mesh\"\n packet.toHardware = \"MESH\"\n return msg\n}\n\n// inject To names and hardware info\nif (nodeShortNames.hasOwnProperty(packet.toHex)) {\n packet.toShortName = nodeShortNames[packet.toHex]\n packet.toLongName = nodeLongNames[packet.toHex]\n packet.toHardware = hardwareMap[nodeHardware[packet.toHex]]\n} else {\n packet.toShortName = unknown\n packet.toLongName = unknown\n packet.toHardware = unknown\n}\n\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1160, "y": 100, "wires": [ [ "63da12e4baeff017" ] ] }, { "id": "855fd449b14d6e09", "type": "function", "z": "a832ad4ec196570a", "name": "Deduplicate Packets by Id", "func": "const packetIdCacheGloabalKey = 'packetIdCache'\nconst expirySeconds = 300;\nvar idCache = global.get(packetIdCacheGloabalKey)\n\nif (idCache === undefined) {\n idCache = {}\n}\n\n// clean dead keys\nfor (var key in idCache) {\n if (idCache[key] <= new Date().getTime()) {\n delete idCache[key];\n }\n};\n\nvar id = msg.payload.packet.id\n\nif (idCache[id]) {\n // message is a duplicate, send to the duplicate output and exit\n return [null, msg];\n}\n\nidCache[id] = new Date().getTime() + (expirySeconds * 1000)\n\nglobal.set(packetIdCacheGloabalKey, idCache);\n\nreturn [msg, null];", "outputs": 2, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 510, "y": 100, "wires": [ [ "4c809ff0174c8ff0", "7e3ebbab282b1482" ], [ "08806f9cfe03f282" ] ], "outputLabels": [ "Original", "Duplicate" ], "icon": "node-red/split.svg" }, { "id": "1ed79fa8cae54ee4", "type": "decode", "z": "a832ad4ec196570a", "name": "Decode", "x": 300, "y": 100, "wires": [ [ "e35eb249e35ecfb3", "855fd449b14d6e09" ] ] }, { "id": "96e553854838f2f4", "type": "template", "z": "8dd264d8b2b469c1", "name": "Generate Mesh Measurement", "field": "payload", "fieldType": "msg", "format": "handlebars", "syntax": "mustache", "template": "[{\n \"id\": \"{{payload.packet.from}}{{payload.packet.to}}\",\n \"source\": \"{{payload.packet.fromLongName}}\",\n \"target\": \"{{payload.packet.toLongName}}\",\n \"rxSnr\": {{payload.packet.rxSnr}},\n \"rxRssi\": {{payload.packet.rxRssi}}\n},\n{\n \"from\": \"{{payload.packet.fromHex}}\",\n \"fromShortName\": \"{{payload.packet.fromShortName}}\",\n \"fromLongName\": \"{{payload.packet.fromLongName}}\",\n \"fromHardware\": \"{{payload.packet.fromHardware}}\",\n \"to\": \"{{payload.packet.toHex}}\",\n \"toShortName\": \"{{payload.packet.toShortName}}\",\n \"toLongName\": \"{{payload.packet.toLongName}}\",\n \"toHardware\": \"{{payload.packet.toHardware}}\",\n \"channelId\": \"{{payload.channelId}}\",\n \"gatewayId\": \"{{payload.gatewayId}}\"\n}]", "output": "json", "x": 330, "y": 200, "wires": [ [ "70d77a69a1aedb60", "565bf6107aace3ce" ] ], "icon": "font-awesome/fa-power-off" }, { "id": "70d77a69a1aedb60", "type": "influxdb out", "z": "8dd264d8b2b469c1", "influxdb": "d96c8f45d69c34f7", "name": "Write Mesh Measurement", "measurement": "Mesh", "precision": "", "retentionPolicy": "", "database": "database", "precisionV18FluxV20": "ms", "retentionPolicyV18Flux": "", "org": "organisation", "bucket": "bucket", "x": 710, "y": 180, "wires": [] }, { "id": "565bf6107aace3ce", "type": "debug", "z": "8dd264d8b2b469c1", "name": "Mesh Measurement", "active": false, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "statusVal": "", "statusType": "auto", "x": 700, "y": 220, "wires": [] }, { "id": "ea40b1047dcb281e", "type": "template", "z": "3e0ee1b8ba4768f0", "name": "Generate Packet Measurement", "field": "payload", "fieldType": "msg", "format": "handlebars", "syntax": "mustache", "template": "[{\n \"rxTime\": {{payload.packet.rxTime}},\n \"rxSnr\": {{payload.packet.rxSnr}},\n \"hopLimit\": {{payload.packet.hopLimit}},\n \"priority\": {{payload.packet.priority}},\n \"rxRssi\": {{payload.packet.rxRssi}},\n \"delayed\": {{payload.packet.delayed}}\n},\n{\n \"from\": \"{{payload.packet.fromHex}}\",\n \"fromShortName\": \"{{payload.packet.fromShortName}}\",\n \"fromLongName\": \"{{payload.packet.fromLongName}}\",\n \"fromHardware\": \"{{payload.packet.fromHardware}}\",\n \"to\": \"{{payload.packet.toHex}}\",\n \"toShortName\": \"{{payload.packet.toShortName}}\",\n \"toLongName\": \"{{payload.packet.toLongName}}\",\n \"toHardware\": \"{{payload.packet.toHardware}}\",\n \"channelId\": \"{{payload.channelId}}\",\n \"gatewayId\": \"{{payload.gatewayId}}\"\n}]", "output": "json", "x": 330, "y": 140, "wires": [ [ "54c9586ca95b7ed1", "eabe626826678b37" ] ], "icon": "font-awesome/fa-power-off" }, { "id": "54c9586ca95b7ed1", "type": "influxdb out", "z": "3e0ee1b8ba4768f0", "influxdb": "d96c8f45d69c34f7", "name": "Write Packet Measurement", "measurement": "Packet", "precision": "", "retentionPolicy": "", "database": "database", "precisionV18FluxV20": "ms", "retentionPolicyV18Flux": "", "org": "organisation", "bucket": "bucket", "x": 720, "y": 120, "wires": [] }, { "id": "eabe626826678b37", "type": "debug", "z": "3e0ee1b8ba4768f0", "name": "Packet Measurement", "active": false, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "statusVal": "", "statusType": "auto", "x": 700, "y": 160, "wires": [] }, { "id": "af1ead55008aa3a1", "type": "function", "z": "f9e40322037c429a", "name": "Generate Position Measurement", "func": "var payload = msg.payload.packet.decoded.payload\n\nvar out = [{\n \"latitude\": (payload.latitudeI * 1e-7),\n \"longitude\": (payload.longitudeI * 1e-7),\n \"altitude\": payload.altitude,\n \"satsInView\": payload.satsInView,\n \"groundSpeed\": payload.groundSpeed,\n \"groundTrack\": payload.groundTrack,\n \"pDOP\": payload.pDOP,\n},\n{\n \"from\": msg.payload.packet.fromHex,\n \"fromShortName\": msg.payload.packet.fromShortName,\n \"fromLongName\": msg.payload.packet.fromLongName,\n \"fromHardware\": msg.payload.packet.fromHardware,\n \"to\": msg.payload.packet.toHex,\n \"toShortName\": msg.payload.packet.toShortName,\n \"toLongName\": msg.payload.packet.toLongName,\n \"toHardware\": msg.payload.packet.toHardware,\n \"channelId\": msg.payload.channelId,\n \"gatewayId\": msg.payload.gatewayId\n}]\n\nmsg.payload = out\n\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 370, "y": 180, "wires": [ [ "99f9cca4b6a6bf62", "8359de37e139c84e" ] ], "icon": "font-awesome/fa-location-arrow" }, { "id": "99f9cca4b6a6bf62", "type": "influxdb out", "z": "f9e40322037c429a", "influxdb": "d96c8f45d69c34f7", "name": "Write Position Measurement", "measurement": "Position", "precision": "", "retentionPolicy": "", "database": "database", "precisionV18FluxV20": "ms", "retentionPolicyV18Flux": "", "org": "organisation", "bucket": "bucket", "x": 680, "y": 180, "wires": [] }, { "id": "8359de37e139c84e", "type": "debug", "z": "f9e40322037c429a", "name": "Position Measurement", "active": false, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "statusVal": "", "statusType": "auto", "x": 660, "y": 140, "wires": [] }, { "id": "61aa5d3ba2f9797f", "type": "debug", "z": "496cbfc0434e783d", "name": "Device Measurement", "active": false, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "statusVal": "", "statusType": "auto", "x": 640, "y": 80, "wires": [] }, { "id": "33c5dc88fcd1bf4b", "type": "template", "z": "496cbfc0434e783d", "name": "Generate Device Measurement", "field": "payload", "fieldType": "msg", "format": "handlebars", "syntax": "mustache", "template": "[{\n \"air_util_tx\": {{payload.packet.decoded.payload.deviceMetrics.airUtilTx}},\n \"battery_level\": {{payload.packet.decoded.payload.deviceMetrics.batteryLevel}},\n \"channel_utilization\": {{payload.packet.decoded.payload.deviceMetrics.channelUtilization}},\n \"voltage\": {{payload.packet.decoded.payload.deviceMetrics.voltage}}\n},\n{\n \"from\": \"{{payload.packet.fromHex}}\",\n \"fromShortName\": \"{{payload.packet.fromShortName}}\",\n \"fromLongName\": \"{{payload.packet.fromLongName}}\",\n \"fromHardware\": \"{{payload.packet.fromHardware}}\",\n \"to\": \"{{payload.packet.toHex}}\",\n \"toShortName\": \"{{payload.packet.toShortName}}\",\n \"toLongName\": \"{{payload.packet.toLongName}}\",\n \"toHardware\": \"{{payload.packet.toHardware}}\",\n \"channelId\": \"{{payload.channelId}}\",\n \"gatewayId\": \"{{payload.gatewayId}}\"\n}]", "output": "json", "x": 310, "y": 120, "wires": [ [ "61aa5d3ba2f9797f", "c7fd5f39b31851f5" ] ], "icon": "font-awesome/fa-power-off" }, { "id": "c7fd5f39b31851f5", "type": "influxdb out", "z": "496cbfc0434e783d", "influxdb": "d96c8f45d69c34f7", "name": "Write Device Measurement", "measurement": "Device", "precision": "", "retentionPolicy": "", "database": "database", "precisionV18FluxV20": "ms", "retentionPolicyV18Flux": "", "org": "organisation", "bucket": "bucket", "x": 660, "y": 120, "wires": [] }, { "id": "8569754e02703706", "type": "template", "z": "0ca01258e3f5252a", "name": "Generate Environment Measurement", "field": "payload", "fieldType": "msg", "format": "handlebars", "syntax": "mustache", "template": "[{\n \"barometric_pressure\": {{payload.packet.decoded.payload.environmentMetrics.barometricPressure}},\n \"gas_resistance\": {{payload.packet.decoded.payload.environmentMetrics.gasResistance}},\n \"relative_humidity\": {{payload.packet.decoded.payload.environmentMetrics.relativeHumidity}},\n \"temperature\": {{payload.packet.decoded.payload.environmentMetrics.temperature}}\n},\n{\n \"from\": \"{{payload.packet.fromHex}}\",\n \"fromShortName\": \"{{payload.packet.fromShortName}}\",\n \"fromLongName\": \"{{payload.packet.fromLongName}}\",\n \"fromHardware\": \"{{payload.packet.fromHardware}}\",\n \"to\": \"{{payload.packet.toHex}}\",\n \"toShortName\": \"{{payload.packet.toShortName}}\",\n \"toLongName\": \"{{payload.packet.toLongName}}\",\n \"toHardware\": \"{{payload.packet.toHardware}}\",\n \"channelId\": \"{{payload.channelId}}\",\n \"gatewayId\": \"{{payload.gatewayId}}\"\n}]", "output": "json", "x": 290, "y": 120, "wires": [ [ "d714c7fefad20f11", "a3c383330d74e1bb" ] ], "icon": "font-awesome/fa-thermometer-2" }, { "id": "d714c7fefad20f11", "type": "debug", "z": "0ca01258e3f5252a", "name": "Environment Measurement", "active": false, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "statusVal": "", "statusType": "auto", "x": 620, "y": 80, "wires": [] }, { "id": "a3c383330d74e1bb", "type": "influxdb out", "z": "0ca01258e3f5252a", "influxdb": "d96c8f45d69c34f7", "name": "Write Environment Measurement", "measurement": "Environment", "precision": "", "retentionPolicy": "", "database": "database", "precisionV18FluxV20": "ms", "retentionPolicyV18Flux": "", "org": "organisation", "bucket": "bucket", "x": 640, "y": 120, "wires": [] }, { "id": "a047428628dbff56", "type": "switch", "z": "f86392651850d084", "name": "Split by PortNum", "property": "payload.packet.decoded.portnum", "propertyType": "msg", "rules": [ { "t": "eq", "v": "0", "vt": "num" }, { "t": "eq", "v": "1", "vt": "num" }, { "t": "eq", "v": "2", "vt": "num" }, { "t": "eq", "v": "3", "vt": "num" }, { "t": "eq", "v": "4", "vt": "num" }, { "t": "eq", "v": "5", "vt": "num" }, { "t": "eq", "v": "6", "vt": "num" }, { "t": "eq", "v": "7", "vt": "num" }, { "t": "eq", "v": "8", "vt": "num" }, { "t": "eq", "v": "9", "vt": "num" }, { "t": "eq", "v": "10", "vt": "num" }, { "t": "eq", "v": "32", "vt": "num" }, { "t": "eq", "v": "33", "vt": "num" }, { "t": "eq", "v": "64", "vt": "num" }, { "t": "eq", "v": "65", "vt": "num" }, { "t": "eq", "v": "66", "vt": "num" }, { "t": "eq", "v": "67", "vt": "num" }, { "t": "eq", "v": "68", "vt": "num" }, { "t": "eq", "v": "69", "vt": "num" }, { "t": "eq", "v": "70", "vt": "num" }, { "t": "eq", "v": "71", "vt": "num" }, { "t": "eq", "v": "256", "vt": "num" }, { "t": "eq", "v": "257", "vt": "num" }, { "t": "else" } ], "checkall": "false", "repair": false, "outputs": 24, "x": 550, "y": 580, "wires": [ [ "0cbf9e15ee49dd3b" ], [ "800ecb302b9aeda5" ], [ "c444184615027953" ], [ "773afcf51939b5fa" ], [ "32de28bb83f90d75" ], [ "c8b2b611c4f4de8f" ], [ "77bec82633bda9be" ], [ "bbbae940dcf3ad57" ], [ "54668b99186bd7d2" ], [ "8cde754ffcfc7677" ], [ "d6fd48624565b5c3" ], [ "af9061b29a714914" ], [ "4f36ea8401f4b411" ], [ "8b87527e3a095dd2" ], [ "23512665dd03b721" ], [ "e6397214979b1171" ], [ "5621d444d33ec358" ], [ "5442b8ec1222dcf0" ], [ "12cb863008575224" ], [ "05dd3202f55db6c6" ], [ "d2fee47f93ca47de" ], [ "f66a3825a2bc89b5" ], [ "fb509c71a14a98a3" ], [ "2ddb2d4afe427f56" ] ], "outputLabels": [ "Unknown", "Text Message", "Remote Hardware", "Position", "Node Info", "Routing", "Admin", "Compressed (Canned) Text Message", "Waypoint", "Audio", "Detection Sensor", "Reply", "IP Tunnel", "Serial", "Store-Forward", "Range Test", "Telemetry", "Zero-GPS Positioning System", "Simulator", "Trace Route", "Neighbor Info", "Private", "ATAK Forwarder", "Unmatched Port Number" ], "icon": "font-awesome/fa-inbox" }, { "id": "800ecb302b9aeda5", "type": "debug", "z": "f86392651850d084", "name": "Text", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "statusVal": "", "statusType": "auto", "x": 910, "y": 180, "wires": [] }, { "id": "0cbf9e15ee49dd3b", "type": "debug", "z": "f86392651850d084", "name": "Unknown App", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "statusVal": "", "statusType": "auto", "x": 940, "y": 140, "wires": [] }, { "id": "7fa2849d08656963", "type": "debug", "z": "f86392651850d084", "name": "NodeInfo", "active": false, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "statusVal": "", "statusType": "auto", "x": 1240, "y": 280, "wires": [] }, { "id": "5621d444d33ec358", "type": "switch", "z": "f86392651850d084", "name": "Telemetry Type", "property": "payload.packet.decoded.payload", "propertyType": "msg", "rules": [ { "t": "hask", "v": "deviceMetrics", "vt": "str" }, { "t": "hask", "v": "environmentMetrics", "vt": "str" }, { "t": "else" } ], "checkall": "true", "repair": false, "outputs": 3, "x": 940, "y": 800, "wires": [ [ "b580aaf34162d927" ], [ "7cc5becf0784992e" ], [ "1a84a37a75dbd35f" ] ], "outputLabels": [ "Device", "Environment", "Unknown" ], "icon": "node-red/status.svg" }, { "id": "1a84a37a75dbd35f", "type": "debug", "z": "f86392651850d084", "name": "Unknown Telemetry", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "statusVal": "", "statusType": "auto", "x": 1270, "y": 840, "wires": [] }, { "id": "385f733a74c1a3e2", "type": "catch", "z": "f86392651850d084", "name": "", "scope": null, "uncaught": false, "x": 100, "y": 100, "wires": [ [ "459e35735d9b3edc" ] ] }, { "id": "459e35735d9b3edc", "type": "debug", "z": "f86392651850d084", "name": "errors", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "statusVal": "", "statusType": "auto", "x": 250, "y": 100, "wires": [] }, { "id": "05dd3202f55db6c6", "type": "debug", "z": "f86392651850d084", "name": "Trace Route", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "statusVal": "", "statusType": "auto", "x": 930, "y": 940, "wires": [] }, { "id": "c8b2b611c4f4de8f", "type": "debug", "z": "f86392651850d084", "name": "Routing", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "statusVal": "", "statusType": "auto", "x": 920, "y": 340, "wires": [] }, { "id": "77bec82633bda9be", "type": "debug", "z": "f86392651850d084", "name": "Admin", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "statusVal": "", "statusType": "auto", "x": 910, "y": 380, "wires": [] }, { "id": "bbbae940dcf3ad57", "type": "debug", "z": "f86392651850d084", "name": "Canned", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "statusVal": "", "statusType": "auto", "x": 920, "y": 420, "wires": [] }, { "id": "54668b99186bd7d2", "type": "debug", "z": "f86392651850d084", "name": "Waypoint", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "statusVal": "", "statusType": "auto", "x": 920, "y": 460, "wires": [] }, { "id": "8cde754ffcfc7677", "type": "debug", "z": "f86392651850d084", "name": "Audio", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "statusVal": "", "statusType": "auto", "x": 910, "y": 500, "wires": [] }, { "id": "d6fd48624565b5c3", "type": "debug", "z": "f86392651850d084", "name": "Detection Sensor", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "statusVal": "", "statusType": "auto", "x": 950, "y": 540, "wires": [] }, { "id": "af9061b29a714914", "type": "debug", "z": "f86392651850d084", "name": "Reply", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "statusVal": "", "statusType": "auto", "x": 910, "y": 580, "wires": [] }, { "id": "4f36ea8401f4b411", "type": "debug", "z": "f86392651850d084", "name": "IP Tunnel", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "statusVal": "", "statusType": "auto", "x": 920, "y": 620, "wires": [] }, { "id": "8b87527e3a095dd2", "type": "debug", "z": "f86392651850d084", "name": "Serial", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "statusVal": "", "statusType": "auto", "x": 910, "y": 660, "wires": [] }, { "id": "23512665dd03b721", "type": "debug", "z": "f86392651850d084", "name": "Store-Forward", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "statusVal": "", "statusType": "auto", "x": 940, "y": 700, "wires": [] }, { "id": "e6397214979b1171", "type": "debug", "z": "f86392651850d084", "name": "Range Test", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "statusVal": "", "statusType": "auto", "x": 930, "y": 740, "wires": [] }, { "id": "c444184615027953", "type": "debug", "z": "f86392651850d084", "name": "Remote Hardware", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "statusVal": "", "statusType": "auto", "x": 950, "y": 220, "wires": [] }, { "id": "5442b8ec1222dcf0", "type": "debug", "z": "f86392651850d084", "name": "Zero-GPS Positioning", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "statusVal": "", "statusType": "auto", "x": 960, "y": 860, "wires": [] }, { "id": "12cb863008575224", "type": "debug", "z": "f86392651850d084", "name": "Simulator", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "statusVal": "", "statusType": "auto", "x": 920, "y": 900, "wires": [] }, { "id": "f66a3825a2bc89b5", "type": "debug", "z": "f86392651850d084", "name": "Private", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "statusVal": "", "statusType": "auto", "x": 920, "y": 1020, "wires": [] }, { "id": "fb509c71a14a98a3", "type": "debug", "z": "f86392651850d084", "name": "ATAK Forwarder", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "statusVal": "", "statusType": "auto", "x": 940, "y": 1060, "wires": [] }, { "id": "2ddb2d4afe427f56", "type": "debug", "z": "f86392651850d084", "name": "New Application", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "statusVal": "", "statusType": "auto", "x": 940, "y": 1100, "wires": [] }, { "id": "32de28bb83f90d75", "type": "function", "z": "f86392651850d084", "name": "Add Node Info to Global Context", "func": "var nodeShortNames = global.get('nodeShortNames')\nvar nodeLongNames = global.get('nodeLongNames')\nvar nodeHardware = global.get('nodeHardware')\n\nif (nodeShortNames === undefined) nodeShortNames = {}\nif (nodeLongNames === undefined) nodeLongNames = {}\nif (nodeHardware === undefined) nodeHardware = {}\n\nvar payload = msg.payload.packet.decoded.payload\n\nif (!(nodeShortNames.hasOwnProperty(payload.id)) || !(nodeShortNames[payload.id] === payload.shortName)){\n nodeShortNames[payload.id] = payload.shortName\n}\n\nif (!(nodeLongNames.hasOwnProperty(payload.id)) || !(nodeLongNames[payload.id] === payload.longName)) {\n nodeLongNames[payload.id] = payload.longName\n}\n\nif (!(nodeHardware.hasOwnProperty(payload.id)) || !(nodeHardware[payload.id] === payload.hwModel)) {\n nodeHardware[payload.id] = payload.hwModel\n}\n\nglobal.set('nodeShortNames', nodeShortNames)\nglobal.set('nodeLongNames', nodeLongNames)\nglobal.set('nodeHardware', nodeHardware)\n\nconst nodeInfo = {\n nodeShortNames, \n nodeLongNames, \n nodeHardware}\n\nreturn [msg, nodeInfo];", "outputs": 2, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 990, "y": 300, "wires": [ [ "7fa2849d08656963" ], [ "3442c0ba5b13848f" ] ], "inputLabels": [ "NodeInfo" ], "outputLabels": [ "NodeInfo", "Global Context" ] }, { "id": "3442c0ba5b13848f", "type": "debug", "z": "f86392651850d084", "name": "Global Context Node Info", "active": false, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "statusVal": "", "statusType": "auto", "x": 1290, "y": 320, "wires": [] }, { "id": "d2fee47f93ca47de", "type": "function", "z": "f86392651850d084", "name": "Translate NeighborInfo Node Identifiers to Hex", "func": "let payload = msg.payload.packet.decoded.payload;\n\npayload.nodeIdHex = '!' + payload.nodeId.toString(16).padStart(8,0);\npayload.lastSentByIdHex = '!' + payload.lastSentById.toString(16).padStart(8, 0);\n\npayload.neighbors.forEach(function(neighbor) {\n neighbor.nodeIdHex = '!' + neighbor.nodeId.toString(16).padStart(8, 0)\n});\n\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1040, "y": 980, "wires": [ [ "4663655785e75cd6" ] ] }, { "id": "4663655785e75cd6", "type": "debug", "z": "f86392651850d084", "name": "Neighbor Info", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "statusVal": "", "statusType": "auto", "x": 1340, "y": 980, "wires": [] }, { "id": "3757dfefbc17bb5c", "type": "subflow:a832ad4ec196570a", "z": "f86392651850d084", "name": "", "x": 130, "y": 580, "wires": [ [ "a047428628dbff56", "32e8b9b72c6c19ce", "51611eebf11d2a12" ] ] }, { "id": "32e8b9b72c6c19ce", "type": "subflow:8dd264d8b2b469c1", "z": "f86392651850d084", "name": "Measurement: Mesh", "x": 560, "y": 320, "wires": [] }, { "id": "51611eebf11d2a12", "type": "subflow:3e0ee1b8ba4768f0", "z": "f86392651850d084", "name": "Measurement: Packet", "x": 560, "y": 360, "wires": [] }, { "id": "773afcf51939b5fa", "type": "subflow:f9e40322037c429a", "z": "f86392651850d084", "name": "Measurement: Position", "x": 960, "y": 260, "wires": [] }, { "id": "b580aaf34162d927", "type": "subflow:496cbfc0434e783d", "z": "f86392651850d084", "name": "Measurement: Device Telemetry", "x": 1310, "y": 760, "wires": [] }, { "id": "7cc5becf0784992e", "type": "subflow:0ca01258e3f5252a", "z": "f86392651850d084", "name": "Measurement: Environment Telemetry", "x": 1330, "y": 800, "wires": [] } ]