Timeserver: filter gateway with ms timestamp
This commit is contained in:
parent
f7aede199d
commit
d4ddb4811f
@ -153,7 +153,7 @@
|
|||||||
"y": 200,
|
"y": 200,
|
||||||
"wires": [
|
"wires": [
|
||||||
[
|
[
|
||||||
"f868bce2.dde67"
|
"831ab883.d6a238"
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -182,37 +182,12 @@
|
|||||||
"y": 40,
|
"y": 40,
|
||||||
"wires": []
|
"wires": []
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"id": "f868bce2.dde67",
|
|
||||||
"type": "switch",
|
|
||||||
"z": "449c1517.e25f4c",
|
|
||||||
"name": "Timechecker",
|
|
||||||
"property": "payload.metadata.gateways[0].time",
|
|
||||||
"propertyType": "msg",
|
|
||||||
"rules": [
|
|
||||||
{
|
|
||||||
"t": "lte",
|
|
||||||
"v": "payload.metadata.time",
|
|
||||||
"vt": "msg"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"checkall": "true",
|
|
||||||
"repair": false,
|
|
||||||
"outputs": 1,
|
|
||||||
"x": 590,
|
|
||||||
"y": 200,
|
|
||||||
"wires": [
|
|
||||||
[
|
|
||||||
"831ab883.d6a238"
|
|
||||||
]
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"id": "831ab883.d6a238",
|
"id": "831ab883.d6a238",
|
||||||
"type": "function",
|
"type": "function",
|
||||||
"z": "449c1517.e25f4c",
|
"z": "449c1517.e25f4c",
|
||||||
"name": "Generate Time Answer",
|
"name": "Generate Time Answer",
|
||||||
"func": "/* LoRaWAN Timeserver\n\nconstruct 6 byte timesync_answer from gateway timestamp and node's time_sync_req\n\nbyte meaning\n0 sequence number (taken from node's time_sync_req)\n1..4 current second (from epoch time 1970)\n5 1/250ths fractions of current second\n\n*/\n\nfunction timecompare(a, b) {\n \n const timeA = a.time;\n const timeB = b.time;\n\n let comparison = 0;\n if (timeA > timeB) {\n comparison = 1;\n } else if (timeA < timeB) {\n comparison = -1;\n }\n return comparison;\n}\n\nlet confidence = 2000; // max millisecond diff gateway time to server time\n\nvar deviceMsg = { payload: msg.payload.dev_id };\nvar gateways = msg.payload.metadata.gateways;\nvar gateway_time = gateways.map(gw => {\n return {\n time: new Date(gw.time),\n eui: gw.gtw_id,\n }\n });\nvar server_time = new Date(msg.payload.metadata.time);\n\n// validate all gateway timestamps against lorawan server_time (which is assumed to be recent)\nvar gw_timestamps = gateway_time.filter(function (element) {\n return ((element.time > (server_time - confidence) && element.time <= server_time));\n});\n\n// if no timestamp left, we have no valid one and exit\nif (gw_timestamps.length === 0) return [\"n/a\", \"n/a\", deviceMsg, 0xff];\n\n// sort time array in ascending order to find most recent timestamp for time answer\ngw_timestamps.sort(timecompare);\n\nvar timestamp = gw_timestamps[0].time;\nvar eui = gw_timestamps[0].eui;\nvar offset = server_time - timestamp;\n\nvar seconds = Math.floor(timestamp/1000);\nvar fractions = (timestamp % 1000) / 4;\nvar seqno = msg.payload.payload_raw[0];\n\nlet buf = new ArrayBuffer(6);\nnew DataView(buf).setUint8(0, seqno);\nnew DataView(buf).setUint32(1, seconds);\nnew DataView(buf).setUint8(5, fractions);\n\nmsg.payload = new Buffer(new Uint8Array(buf));\nvar euiMsg = { payload: eui };\nvar offsetMsg = { payload: offset };\n\nreturn [euiMsg, offsetMsg, deviceMsg, msg];",
|
"func": "/* LoRaWAN Timeserver\n\nconstruct 6 byte timesync_answer from gateway timestamp and node's time_sync_req\n\nbyte meaning\n0 sequence number (taken from node's time_sync_req)\n1..4 current second (from epoch time 1970)\n5 1/250ths fractions of current second\n\n*/\n\nfunction timecompare(a, b) {\n \n const timeA = a.time;\n const timeB = b.time;\n\n let comparison = 0;\n if (timeA > timeB) {\n comparison = 1;\n } else if (timeA < timeB) {\n comparison = -1;\n }\n return comparison;\n}\n\nlet confidence = 2000; // max millisecond diff gateway time to server time\n\nvar deviceMsg = { payload: msg.payload.dev_id };\nvar gateway_list = msg.payload.metadata.gateways;\n\n// filter all gateway timestamps that have milliseconds part (which we assume have a \".\")\nvar gateways = gateway_list.filter(function (element) {\n return (element.time.includes(\".\"));\n});\n\nvar gateway_time = gateways.map(gw => {\n return {\n time: new Date(gw.time),\n eui: gw.gtw_id,\n }\n });\nvar server_time = new Date(msg.payload.metadata.time);\n\n// validate all gateway timestamps against lorawan server_time (which is assumed to be recent)\nvar gw_timestamps = gateway_time.filter(function (element) {\n return ((element.time > (server_time - confidence) && element.time <= server_time));\n});\n\n// if no timestamp left, we have no valid one and exit\nif (gw_timestamps.length === 0) return [\"n/a\", \"n/a\", deviceMsg, 0xff];\n\n// sort time array in ascending order to find most recent timestamp for time answer\ngw_timestamps.sort(timecompare);\n\nvar timestamp = gw_timestamps[0].time;\nvar eui = gw_timestamps[0].eui;\nvar offset = server_time - timestamp;\n\nvar seconds = Math.floor(timestamp/1000);\nvar fractions = (timestamp % 1000) / 4;\nvar seqno = msg.payload.payload_raw[0];\n\nlet buf = new ArrayBuffer(6);\nnew DataView(buf).setUint8(0, seqno);\nnew DataView(buf).setUint32(1, seconds);\nnew DataView(buf).setUint8(5, fractions);\n\nmsg.payload = new Buffer(new Uint8Array(buf));\nvar euiMsg = { payload: eui };\nvar offsetMsg = { payload: offset };\n\nreturn [euiMsg, offsetMsg, deviceMsg, msg];",
|
||||||
"outputs": 4,
|
"outputs": 4,
|
||||||
"noerr": 0,
|
"noerr": 0,
|
||||||
"x": 360,
|
"x": 360,
|
||||||
@ -251,7 +226,7 @@
|
|||||||
"tostatus": true,
|
"tostatus": true,
|
||||||
"complete": "payload",
|
"complete": "payload",
|
||||||
"x": 700,
|
"x": 700,
|
||||||
"y": 280,
|
"y": 240,
|
||||||
"wires": [],
|
"wires": [],
|
||||||
"icon": "node-red/bridge.png"
|
"icon": "node-red/bridge.png"
|
||||||
},
|
},
|
||||||
@ -268,7 +243,7 @@
|
|||||||
"format": "{{msg.payload}}",
|
"format": "{{msg.payload}}",
|
||||||
"layout": "col-center",
|
"layout": "col-center",
|
||||||
"x": 810,
|
"x": 810,
|
||||||
"y": 336,
|
"y": 300,
|
||||||
"wires": []
|
"wires": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -294,7 +269,7 @@
|
|||||||
"seg1": "",
|
"seg1": "",
|
||||||
"seg2": "",
|
"seg2": "",
|
||||||
"x": 710,
|
"x": 710,
|
||||||
"y": 416,
|
"y": 380,
|
||||||
"wires": []
|
"wires": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -310,7 +285,7 @@
|
|||||||
"format": "{{msg.payload}}",
|
"format": "{{msg.payload}}",
|
||||||
"layout": "col-center",
|
"layout": "col-center",
|
||||||
"x": 700,
|
"x": 700,
|
||||||
"y": 376,
|
"y": 340,
|
||||||
"wires": []
|
"wires": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -322,7 +297,7 @@
|
|||||||
"outputs": 1,
|
"outputs": 1,
|
||||||
"noerr": 0,
|
"noerr": 0,
|
||||||
"x": 670,
|
"x": 670,
|
||||||
"y": 336,
|
"y": 300,
|
||||||
"wires": [
|
"wires": [
|
||||||
[
|
[
|
||||||
"8712a5ac.ed18e8"
|
"8712a5ac.ed18e8"
|
||||||
@ -342,7 +317,7 @@
|
|||||||
"format": "{{msg.payload}}",
|
"format": "{{msg.payload}}",
|
||||||
"layout": "col-center",
|
"layout": "col-center",
|
||||||
"x": 700,
|
"x": 700,
|
||||||
"y": 456,
|
"y": 420,
|
||||||
"wires": []
|
"wires": []
|
||||||
},
|
},
|
||||||
{
|
{
|
Loading…
Reference in New Issue
Block a user