Hi All,
I am trying to draw lines representing a link between two points, dependent on the rssi, the color of the line changes.
The "Link" function node is -
if (msg.payload.rssi > -100)(
colour = "red")
else if (msg.payload.rssi > -105)(
colour = "orange")
else if (msg.payload.rssi > -110)(
colour = "yellow")
else if (msg.payload.rssi > -115)(
colour = "lightgreen")
else if (msg.payload.rssi > -115)(
colour = "teal")
else (
colour = "blue")
//"layer": "Lines",
msg.payload = {"name": msg._msgid,
"color": colour,
"layer": "Link",
"line": [ [msg.payload.location.latitude, msg.payload.location.longitude], [msg.decoded_payload.latitude, msg.decoded_payload.longitude]]}
delete msg.parts
delete msg.decoded_payload
return msg;
This is the function node that draws the line, the data is called from a DB processed and then sent to this function node that sends it to the WorldMap node.
The issue is that the all the lines are drawn on the layer in red.
If I turn the "layer": "Link" off and on then lines become the correct color.
[
{
"id": "cbd42246da9ac917",
"type": "mysql",
"z": "c95be8d7138e80c7",
"mydb": "e15aca1763c788ca",
"name": "",
"x": 250,
"y": 1320,
"wires": [
[
"d40697cb3ac3d87f",
"f8551766e828b8ae"
]
]
},
{
"id": "d40697cb3ac3d87f",
"type": "ui_table",
"z": "c95be8d7138e80c7",
"group": "5aff7d5d8f1ac07b",
"name": "json",
"order": 2,
"width": "30",
"height": "20",
"columns": [],
"outputs": 0,
"cts": false,
"x": 410,
"y": 1320,
"wires": []
},
{
"id": "99c45552cfdf596b",
"type": "comment",
"z": "c95be8d7138e80c7",
"name": "json",
"info": "",
"x": 110,
"y": 1280,
"wires": []
},
{
"id": "cbe845ed11062e41",
"type": "debug",
"z": "c95be8d7138e80c7",
"name": "",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": true,
"complete": "true",
"targetType": "full",
"statusVal": "payload",
"statusType": "auto",
"x": 1090,
"y": 1340,
"wires": []
},
{
"id": "f8551766e828b8ae",
"type": "split",
"z": "c95be8d7138e80c7",
"name": "",
"splt": "\\n",
"spltType": "str",
"arraySplt": 1,
"arraySpltType": "len",
"stream": false,
"addname": "",
"x": 130,
"y": 1420,
"wires": [
[
"569806dbca0761ea"
]
]
},
{
"id": "569806dbca0761ea",
"type": "function",
"z": "c95be8d7138e80c7",
"name": "JSON.parse",
"func": "\nconst array = JSON.parse(msg.payload.json);\nmsg.payload = array\n\ndelete msg.payload.json\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 290,
"y": 1420,
"wires": [
[
"4959bd61ad1704ba",
"d34c5f85537f6309"
]
]
},
{
"id": "ab14ce39fbd3bad3",
"type": "function",
"z": "c95be8d7138e80c7",
"name": "Prep array",
"func": "\nmsg.end_device_ids = msg.payload.end_device_ids\nmsg.received_at = msg.payload.received_at\nmsg.payload = msg.payload.uplink_message.rx_metadata\ndelete msg.topic\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 850,
"y": 1440,
"wires": [
[
"38532bb7329a9874"
]
]
},
{
"id": "38532bb7329a9874",
"type": "split",
"z": "c95be8d7138e80c7",
"name": "",
"splt": "\\n",
"spltType": "str",
"arraySplt": 1,
"arraySpltType": "len",
"stream": false,
"addname": "",
"x": 990,
"y": 1440,
"wires": [
[
"2162519740094497",
"a194aa10011a4491",
"86b9edfe427adff1",
"cbe845ed11062e41"
]
]
},
{
"id": "d34c5f85537f6309",
"type": "function",
"z": "c95be8d7138e80c7",
"name": "Decoder - Micro Tracker",
"func": "let data = msg.payload.uplink_message.frm_payload;\n bytes = new Buffer(data,'Base64');\n\nlet decoded = context.Decoder(bytes, msg.payload.uplink_message.f_port);\nmsg.decoded_payload = decoded;\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "context.Decoder = function(bytes, port) {\n function step_size(lo, hi, nbits, nresv) {\n return 1.0 / ((((1<<nbits) - 1) - nresv) / (hi - lo));\n }\n\n function mt_value_decode(value, lo, hi, nbits, nresv) {\n return (value - nresv / 2) * step_size(lo, hi, nbits, nresv) + lo;\n }\n\n // Gets the zero-based unsigned numeric value of the given bit(s)\n function bits(value, lsb, msb) {\n var len = msb - lsb + 1;\n var mask = (1<<len) - 1;\n return value>>lsb & mask;\n }\n\n // Gets the boolean value of the given bit\n function bit(value, bit) {\n return (value & (1<<bit)) > 0;\n }\n\n // Gets a hexadecimal representation ensuring a leading zero for each byte\n function hex(bytes, separator) {\n return bytes.map(function (b) {\n return (\"0\" + b.toString(16)).substr(-2);\n }).join(separator || \"\");\n }\n\n // Decodes 4 bytes into a signed integer, MSB\n function int32(bytes) {\n // JavaScript bitwise operators always work with 32 bits signed integers\n return bytes[0]<<24 | bytes[1]<<16 | bytes[2]<<8 | bytes[3];\n }\n\n // Decodes 4 bytes into an unsigned integer, MSB\n function uint32(bytes) {\n \n return (bytes[0]<<24 | bytes[1]<<16 | bytes[2]<<8 | bytes[3])>>>0; \n }\n\n // Decodes 1 to 4 MAC addresses and their RSSI\n function mac_rssi(bytes) {\n var items = [];\n for (var offset = 0; offset < bytes.length; offset += 7) {\n items.push({\n mac_address: hex(bytes.slice(offset, offset + 6), \":\"),\n // Sign-extend to 32 bits to support negative values; dBm\n rssi: bytes[offset + 6]<<24>>24,\n });\n }\n return items;\n }\n\n function message(code, descriptions) {\n return {\n code: code,\n description: code < 0 || code >= descriptions.length ? \"UNKNOWN\" : descriptions[code]\n };\n }\n\n var decoded = {};\n var i;\n\n var type = bytes[0];\n\n // All message types, except for Frame pending messages, share the same header\n if (type !== 0x00) {\n // Note: the Data Storage Integration stores nested objects as text\n decoded.status = {\n mode: message(bits(bytes[1], 5, 7), [\"Standby\", \"Motion tracking\", \"Permanent tracking\",\n \"Motion start/end tracking\", \"Activity tracking\", \"OFF\"]),\n sos: bit(bytes[1], 4),\n tracking: bit(bytes[1], 3),\n moving: bit(bytes[1], 2),\n periodic: bit(bytes[1], 1),\n on_demand: bit(bytes[1], 0)\n };\n\n // Trackers with a rechargeable battery:the percentage reflects the actual value\n decoded.battery = bytes[2]/100;\n decoded.battery = bytes[2];\n //Temperature\n decoded.temperature = Math.round(100 * mt_value_decode(bytes[3], -44, 85, 8, 0)) / 100;\n \n decoded.ack = bits(bytes[4], 4, 7);\n \n decoded.data = bits(bytes[4], 0, 3);\n //MCU and BLE fwVersion\n decoded.lastResetCause = \"lastResetCause: \" + bytes[5];\n decoded.mcuFirmware = \"fwVersion: \" + bytes[6] + \".\" + bytes[7] + \".\" + bytes[8];\n decoded.bleFirmware = \"bleFwVersion\" + bytes[9] + \".\" + bytes[10] + \".\" + bytes[11];\n\n }\n\n switch (type) {\n case 0x00:\n decoded.type = \"FRAME PENDING\";\n decoded.token = bytes[1];\n break;\n\n case 0x03:\n decoded.type = \"POSITION\";\n switch (decoded.data) {\n case 0:\n decoded.position_type = \"GPS fix\";\n decoded.age = mt_value_decode(bytes[5], 0, 2040, 8, 0);\n // Signed 32 bits integers; LSB is always zero\n decoded.latitude = (bytes[6]<<24 | bytes[7]<<16 | bytes[8]<<8) / 1e7;\n decoded.longitude = (bytes[9]<<24 | bytes[10]<<16 | bytes[11]<<8) / 1e7;\n // Estimated Horizontal Position Error\n decoded.ehpe = mt_value_decode(bytes[12], 0, 1000, 8, 0);\n break;\n\n case 1:\n decoded.position_type = \"GPS timeout\";\n decoded.timeout_cause = message(bytes[5], [\"User timeout cause\"]);\n for (i = 0; i < 4; i++) {\n // Carrier over noise (dBm) for the i-th satellite seen\n decoded[\"cn\" + i] = mt_value_decode(bytes[6 + i], 0, 2040, 8, 0);\n }\n break;\n\n case 2:\n // Documented as obsolete\n decoded.error = message(0, [\"UNSUPPORTED POSITION TYPE \" + decoded.data]);\n break;\n\n case 3:\n decoded.position_type = \"WIFI timeout\";\n for (i = 0; i < 6; i++) {\n decoded[\"v_bat\" + (i + 1)] = mt_value_decode(bytes[5 + i], 2.8, 4.2, 8, 2);\n }\n break;\n\n case 4:\n decoded.position_type = \"WIFI failure\";\n for (i = 0; i < 6; i++) {\n // Most of time a WIFI timeout occurs due to a low battery condition\n decoded[\"v_bat\" + (i + 1)] = mt_value_decode(bytes[5 + i], 2.8, 4.2, 8, 2);\n }\n decoded.error = message(bytes[11], [\"WIFI connection failure\", \"Scan failure\",\n \"Antenna unavailable\", \"WIFI not supported on this device\"]);\n break;\n\n case 5:\n case 6:\n decoded.position_type = \"LP-GPS data\";\n // Encrypted; not described in the documentation\n decoded.error = message(0, [\"UNSUPPORTED POSITION TYPE \" + decoded.data]);\n break;\n\n case 7:\n decoded.position_type = \"BLE beacon scan\";\n decoded.age = mt_value_decode(bytes[5], 0, 2040, 8, 0);\n // Remaining data: up to 4 beacons\n decoded.beacons = mac_rssi(bytes.slice(6));\n break;\n\n case 8:\n decoded.position_type = \"BLE beacon failure\";\n decoded.error = message(bytes[5], [\"BLE is not responding\", \"Internal error\", \"Shared antenna not available\",\n \"Scan already on going\", \"No beacon detected\", \"Hardware incompatibility\"]);\n break;\n\n // Test with: 0358D895090EC46E1FF44B9EB76466B3B87454AD500959CA1ED4AD525E67DA14A1AC\n // or 032CD1890900C46E1FF44B9EC5C83A355A3898A6\n case 9:\n decoded.position_type = \"WIFI BSSIDs\";\n decoded.age = mt_value_decode(bytes[5], 0, 2040, 8, 0);\n // Remaining data: up to 4 WiFi BSSIDs\n decoded.stations = mac_rssi(bytes.slice(6));\n break;\n\n default:\n decoded.error = message(0, [\"UNSUPPORTED POSITION TYPE \" + decoded.data]);\n }\n break;\n\n case 0x04:\n decoded.type = \"ENERGY STATUS\";\n break;\n\n case 0x05:\n decoded.type = \"HEARTBEAT\";\n break;\n\n case 0x07:\n // Activity status message and configuration message share the same identifier\n var tag = bytes[5];\n switch (tag) {\n case 1:\n decoded.type = \"ACTIVITY STATUS\";\n decoded.activity_counter = uint32(bytes.slice(6, 10));\n break;\n\n case 2:\n decoded.type = \"CONFIGURATION\";\n for (i = 0; i < 5; i++) {\n var offset = 6 + 5 * i;\n decoded[\"param\" + i] = {\n type: bytes[offset],\n value: uint32(bytes.slice(offset + 1, offset + 5))\n };\n }\n break;\n\n default:\n decoded.error = message(0, [\"UNSUPPORTED POSITION TYPE \" + decoded.data + \"/\" + tag]);\n }\n break;\n\n case 0x09:\n decoded.type = \"SHUTDOWN\";\n break;\n\n case 0xFF:\n decoded.type = \"DEBUG\";\n break;\n\n default:\n decoded.error = message(0, [\"UNSUPPORTED MESSAGE TYPE \" + type]);\n }\n\n // Just some redundant debug info\n decoded.debug = {\n payload: hex(bytes),\n length: bytes.length,\n port: port,\n server_time: new Date().toISOString()\n };\n\n return decoded;\n}\n",
"finalize": "",
"libs": [],
"x": 510,
"y": 1420,
"wires": [
[
"3b11c0953e60f2fc"
]
]
},
{
"id": "3b11c0953e60f2fc",
"type": "switch",
"z": "c95be8d7138e80c7",
"name": "",
"property": "decoded_payload.latitude",
"propertyType": "msg",
"rules": [
{
"t": "nnull"
}
],
"checkall": "true",
"repair": false,
"outputs": 1,
"x": 690,
"y": 1440,
"wires": [
[
"ab14ce39fbd3bad3",
"e10ea59d357c0371"
]
]
},
{
"id": "ebf062319e90978f",
"type": "ui_worldmap",
"z": "c95be8d7138e80c7",
"group": "ee8b70d64868c9f1",
"order": 0,
"width": 0,
"height": 0,
"name": "",
"lat": "-29.7",
"lon": "30.2",
"zoom": "",
"layer": "OSM",
"cluster": "",
"maxage": "",
"usermenu": "hide",
"layers": "hide",
"panit": "false",
"panlock": "false",
"zoomlock": "false",
"hiderightclick": "true",
"coords": "none",
"showgrid": "false",
"allowFileDrop": "false",
"path": "/worldmap",
"mapname": "",
"mapurl": "",
"mapopt": "",
"mapwms": false,
"x": 1300,
"y": 1380,
"wires": []
},
{
"id": "3ab507f600e582c1",
"type": "worldmap",
"z": "c95be8d7138e80c7",
"name": "",
"lat": "",
"lon": "",
"zoom": "",
"layer": "",
"cluster": "",
"maxage": "",
"usermenu": "show",
"layers": "show",
"panit": "false",
"panlock": "false",
"zoomlock": "false",
"hiderightclick": "false",
"coords": "false",
"showgrid": "false",
"allowFileDrop": "false",
"path": "/worldmap",
"mapname": "",
"mapurl": "",
"mapopt": "",
"mapwms": false,
"x": 1320,
"y": 1440,
"wires": []
},
{
"id": "2162519740094497",
"type": "function",
"z": "c95be8d7138e80c7",
"name": "Links",
"func": "\nif (msg.payload.rssi > -100)(\n colour = \"red\")\n else if (msg.payload.rssi > -105)(\n colour = \"orange\")\n else if (msg.payload.rssi > -110)(\n colour = \"yellow\")\n else if (msg.payload.rssi > -115)(\n colour = \"lightgreen\")\n else if (msg.payload.rssi > -115)(\n colour = \"teal\")\n else (\n colour = \"blue\")\n //\"layer\": \"Lines\",\nmsg.payload = {\"name\": msg._msgid,\n \"color\": colour,\n \"layer\": \"Link\",\n \"line\": [ [msg.payload.location.latitude, msg.payload.location.longitude], [msg.decoded_payload.latitude, msg.decoded_payload.longitude]]}\ndelete msg.parts\ndelete msg.decoded_payload\n\n\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 1130,
"y": 1400,
"wires": [
[
"3ab507f600e582c1"
]
]
},
{
"id": "c69411934537a7cb",
"type": "ui_button",
"z": "c95be8d7138e80c7",
"name": "",
"group": "ee8b70d64868c9f1",
"order": 3,
"width": 0,
"height": 0,
"passthru": false,
"label": "button",
"tooltip": "",
"color": "",
"bgcolor": "",
"className": "",
"icon": "",
"payload": "",
"payloadType": "str",
"topic": "SELECT * FROM soiot.json order by timestamp desc;",
"topicType": "str",
"x": 110,
"y": 1320,
"wires": [
[
"cbd42246da9ac917"
]
]
},
{
"id": "a194aa10011a4491",
"type": "function",
"z": "c95be8d7138e80c7",
"name": "Gateways",
"func": "\nmsg.payload = { \"name\": msg.payload.gateway_ids.gateway_id, \"lat\":msg.payload.location.latitude, \"lon\":msg.payload.location.longitude, \"icon\": \"cloud\", \"iconColor\": 'blue'}\n\ndelete msg.parts\ndelete msg.decoded_payload\n\n\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 1140,
"y": 1440,
"wires": [
[
"3ab507f600e582c1"
]
]
},
{
"id": "86b9edfe427adff1",
"type": "function",
"z": "c95be8d7138e80c7",
"name": "Nodes",
"func": "\nif (msg.payload.rssi > -100)(\n colour = \"red\")\n else if (msg.payload.rssi > -105)(\n colour = \"orange\")\n else if (msg.payload.rssi > -110)(\n colour = \"yellow\")\n else if (msg.payload.rssi > -115)(\n colour = \"lightgreen\")\n else if (msg.payload.rssi > -115)(\n colour = \"teal\")\n else (\n colour = \"blue\")\n\n\n\n\nmsg.payload = { \"name\": msg._msgid, \"lat\":msg.decoded_payload.latitude, \"lon\":msg.decoded_payload.longitude, \"icon\":\"fa-circle\", \"iconColor\": colour, \"dev_eui\":msg.end_device_ids.dev_eui, \"time\":msg.received_at, \"rssi\":msg.payload.rssi}\n\ndelete msg.parts\ndelete msg.decoded_payload\n\n\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 1130,
"y": 1480,
"wires": [
[
"3ab507f600e582c1"
]
]
},
{
"id": "e10ea59d357c0371",
"type": "debug",
"z": "c95be8d7138e80c7",
"name": "",
"active": false,
"tosidebar": true,
"console": false,
"tostatus": true,
"complete": "true",
"targetType": "full",
"statusVal": "payload",
"statusType": "auto",
"x": 790,
"y": 1360,
"wires": []
},
{
"id": "4959bd61ad1704ba",
"type": "function",
"z": "c95be8d7138e80c7",
"name": "Decoder - Micro Tracker",
"func": "let data = msg.payload.uplink_message.frm_payload;\n bytes = new Buffer(data,'Base64');\n\nlet decoded = context.Decoder(bytes, msg.payload.uplink_message.f_port);\nmsg.decoded_payload = decoded;\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "// Decode an uplink message from an array of bytes to an object of fields\ncontext.Decoder = function Decoder(bytes, port)\n{\n var decoded = {};\n if (port === 1)\n {\n decoded.type = \"position\";\n\n decoded.latitude = bytes[0] + bytes[1] * 256 +\n bytes[2] * 65536 + bytes[3] * 16777216;\n if (decoded.latitude >= 0x80000000)\n decoded.latitude -= 0x100000000;\n decoded.latitude /= 1e7;\n\n decoded.longitude = bytes[4] + bytes[5] * 256 +\n bytes[6] * 65536 + bytes[7] * 16777216;\n if (decoded.longitude >= 0x80000000)\n decoded.longitude -= 0x100000000;\n decoded.longitude /= 1e7;\n\n decoded.inTrip = ((bytes[8] & 0x1) !== 0) ? true : false;\n decoded.fixFailed = ((bytes[8] & 0x2) !== 0) ? true : false;\n decoded.manDown = ((bytes[8] & 0x4) !== 0) ? true : false;\n decoded.headingDeg = (bytes[9] & 0x7) * 45;\n\n decoded.speedKmph = (bytes[9] >> 3) * 5;\n decoded.batV = bytes[10] * 0.025;\n }\n else if (port === 2)\n {\n decoded.type = \"downlink ack\";\n\n decoded.sequence = (bytes[0] & 0x7F);\n decoded.accepted = ((bytes[0] & 0x80) !== 0) ? true : false;\n decoded.fwMaj = bytes[1];\n decoded.fwMin = bytes[2];\n }\n else if (port === 3)\n {\n decoded.type = \"stats\";\n\n decoded.initialBatV = 4.0 + 0.100 * (bytes[0] & 0xF);\n decoded.txCount = 32 * ((bytes[0] >> 4) + (bytes[1] & 0x7F) * 16);\n decoded.tripCount = 32 * ((bytes[1] >> 7) + (bytes[2] & 0xFF) * 2\n + (bytes[3] & 0x0F) * 512);\n decoded.gpsSuccesses = 32 * ((bytes[3] >> 4) + (bytes[4] & 0x3F) * 16);\n decoded.gpsFails = 32 * ((bytes[4] >> 6) + (bytes[5] & 0x3F) * 4);\n decoded.aveGpsFixS = 1 * ((bytes[5] >> 6) + (bytes[6] & 0x7F) * 4);\n decoded.aveGpsFailS = 1 * ((bytes[6] >> 7) + (bytes[7] & 0xFF) * 2);\n decoded.aveGpsFreshenS = 1 * ((bytes[7] >> 8) + (bytes[8] & 0xFF) * 1);\n decoded.wakeupsPerTrip = 1 * ((bytes[8] >> 8) + (bytes[9] & 0x7F) * 1);\n decoded.uptimeWeeks = 1 * ((bytes[9] >> 7) + (bytes[10] & 0xFF) * 2);\n }\n return decoded;\n}\n",
"finalize": "",
"libs": [],
"x": 510,
"y": 1460,
"wires": [
[
"3b11c0953e60f2fc"
]
]
},
{
"id": "e15aca1763c788ca",
"type": "MySQLdatabase",
"name": "",
"host": "dbsoiot.civilwbkm1wy.eu-west-1.rds.amazonaws.com",
"port": "3306",
"db": "soiot",
"tz": "",
"charset": "UTF8"
},
{
"id": "5aff7d5d8f1ac07b",
"type": "ui_group",
"name": "json",
"tab": "fb6f9c9fea96c38c",
"order": 5,
"disp": true,
"width": "36",
"collapse": false,
"className": ""
},
{
"id": "ee8b70d64868c9f1",
"type": "ui_group",
"name": "map",
"tab": "fb6f9c9fea96c38c",
"order": 6,
"disp": true,
"width": "36",
"collapse": false,
"className": ""
},
{
"id": "fb6f9c9fea96c38c",
"type": "ui_tab",
"name": "DB Managment",
"icon": "dashboard",
"order": 1,
"disabled": false,
"hidden": fals
}
]