diff --git a/compose.yaml b/compose.yaml
index 0e9416d..fb189fc 100644
--- a/compose.yaml
+++ b/compose.yaml
@@ -1,10 +1,9 @@
################################################################################
# common-services configuration file
-# in order: frigate, influxdb, node-red
+# in order: frigate, node-red
# this should be located in the ~/code folder, with each container's directory
################################################################################
include:
- frigate/docker-compose-frigate.yml
- - influxdb/docker-compose-influxdb.yml
- nodered/docker-compose-node-red.yml
diff --git a/docker-influxdb/docker-compose-influxdb.yaml b/docker-influxdb/docker-compose-influxdb.yaml
deleted file mode 100644
index ed3ceb2..0000000
--- a/docker-influxdb/docker-compose-influxdb.yaml
+++ /dev/null
@@ -1,40 +0,0 @@
-################################################################################
-# InfluxDB Compose
-################################################################################
-# setup at https://hub.docker.com/_/influxdb
-# Environment variables:
-# DOCKER_INFLUXDB_INIT_MODE: "setup"
-# DOCKER_INFLUXDB_INIT_USERNAME: "my-user" # The username to set for the system's initial super-user (Required).
-# DOCKER_INFLUXDB_INIT_PASSWORD: "my-password" # The password to set for the system's inital super-user (Required).
-# DOCKER_INFLUXDB_INIT_ORG: "my-org" # The name to set for the system's initial organization (Required).
-# DOCKER_INFLUXDB_INIT_BUCKET: "my-bucket" # The name to set for the system's initial bucket (Required).
-# DOCKER_INFLUXDB_INIT_RETENTION: "" # The duration the system's initial bucket should retain data. If not set, the initial bucket will retain data forever.
-# DOCKER_INFLUXDB_INIT_ADMIN_TOKEN: "my-super-secret-auth-token" # The authentication token to associate with the system's initial super-user. If not set, a token will be auto-generated by the system.
-################################################################################
-services:
- influxdb:
- container_name: influxdb
- restart: unless-stopped
- image: influxdb:2.7.5
- volumes:
- - ~/code/influxdb/data:/var/lib/influxdb2
- - ~/code/influxdb/config:/etc/influxdb2
- - ~/code/backup:/home/influxdb/backup
- - /etc/localtime:/etc/localtime:ro
- ports:
- - "8086:8086"
- environment:
- DOCKER_INFLUXDB_INIT_MODE: "setup"
- DOCKER_INFLUXDB_INIT_USERNAME: "influxdb_user"
- DOCKER_INFLUXDB_INIT_PASSWORD: "influxdb_pass"
- DOCKER_INFLUXDB_INIT_ORG: "taffic_monitor_01"
- DOCKER_INFLUXDB_INIT_BUCKET: "influxdb_bucket"
- DOCKER_INFLUXDB_INIT_ADMIN_TOKEN: "influxdb_admin_token"
- depends_on:
- frigate:
- condition: service_healthy
- healthcheck:
- test: ["CMD", "curl", "-f", "http://localhost:8086/ping"]
- interval: 5s
- timeout: 10s
- retries: 5
diff --git a/docker-nodered/docker-compose-node-red.yaml b/docker-nodered/docker-compose-node-red.yaml
index 150c60c..7f2cebb 100644
--- a/docker-nodered/docker-compose-node-red.yaml
+++ b/docker-nodered/docker-compose-node-red.yaml
@@ -31,14 +31,10 @@ services:
NODE_RED_ENABLE_SAFE_MODE: false
VAR_LOCATION: "ne26th-wasco-sb-01"
VAR_RADAR_CAMERA: "picam_h264"
- VAR_INFLUXDB_ORG: "taffic_monitor_01"
- VAR_INFLUXDB_BUCKET: "influxdb_bucket"
VAR_EVENTS_DB: "tmdb"
VAR_EVENTS_TABLE: "events"
VAR_MQTT_USER: "mqtt_user" #broker settings
VAR_MQTT_PASS: "mqtt_pass" #broker settings
depends_on:
frigate:
- condition: service_healthy
- influxdb:
condition: service_healthy
\ No newline at end of file
diff --git a/node-red-project/flows.json b/node-red-project/flows.json
index a3a81c9..7836dea 100644
--- a/node-red-project/flows.json
+++ b/node-red-project/flows.json
@@ -41,14 +41,18 @@
},
"nodes": [
"35c0bee67148cfa7",
- "9496fe7a475726de",
- "617c9bb213538929",
- "526eb1967dda78c4"
+ "526eb1967dda78c4",
+ "e3aa00721bf6faff",
+ "54ae78579d38e81b",
+ "831310a0a0549da3",
+ "13059459bbc48328",
+ "585b91535ae4e8a3",
+ "477f8523e9784029"
],
- "x": 534,
- "y": 699,
- "w": 852,
- "h": 142
+ "x": 394,
+ "y": 719,
+ "w": 1092,
+ "h": 262
},
{
"id": "1d00b3011a12b204",
@@ -59,14 +63,18 @@
"label": true
},
"nodes": [
- "4681243b9c70e906",
- "b8db51ab64a3d61e",
- "67f64c75edc0ef13"
+ "67f64c75edc0ef13",
+ "0749f4279a336caf",
+ "56b9668b4f365f7b",
+ "ef4ad9faa7ec12e7",
+ "81c98c5e01bbfe09",
+ "87412467471d97a6",
+ "8a653740e4fc4f6a"
],
- "x": 534,
+ "x": 394,
"y": 499,
- "w": 452,
- "h": 182
+ "w": 992,
+ "h": 202
},
{
"id": "e138c998bef7d520",
@@ -77,15 +85,19 @@
"label": true
},
"nodes": [
- "d5e5d0f288f9b186",
- "7b220a40adc14e3c",
"d88af763b70480d0",
- "5f62cb744592b108"
+ "5f62cb744592b108",
+ "dd48c6017098fe1d",
+ "e113c181976ad898",
+ "e1461efd368bbee3",
+ "825ddab22453e37c",
+ "1ddee1427e02c980",
+ "d7eb8cf6f750f369"
],
- "x": 534,
- "y": 859,
- "w": 752,
- "h": 202
+ "x": 394,
+ "y": 999,
+ "w": 1092,
+ "h": 242
},
{
"id": "e5b5b46703e248e9",
@@ -96,15 +108,18 @@
"label": true
},
"nodes": [
- "da47f12a5e2cd512",
- "ef9cb704c91a3ef6",
- "c1c1371cdf7151aa",
- "58e0b10c67841b60"
+ "58e0b10c67841b60",
+ "1d1c479b2567efbd",
+ "795c120719c982de",
+ "8180a480a85a6636",
+ "a1583c68a1dad33e",
+ "382bf388390f91bd",
+ "6580ac98734eba2e"
],
- "x": 534,
- "y": 1079,
- "w": 792,
- "h": 202
+ "x": 394,
+ "y": 1259,
+ "w": 1172,
+ "h": 222
},
{
"id": "0a6e123f5e53c029",
@@ -169,26 +184,24 @@
"id": "76417db2b472ef4f",
"type": "group",
"z": "28627559bebdc324",
- "name": "influxdb TimedSpeedCounts (.counts, .speed_average)",
+ "name": "radar TimedSpeedCounts (.counts, .speed_average)",
"style": {
"label": true
},
"nodes": [
"15797ab24727f84d",
- "6a422507b2a5bbca",
- "e256c1d68cf20f43",
- "dd294de96fa60d7d",
- "319859b48b6eebad",
- "1b7c2967fd6a85a4",
- "537d771bb5b1eff5",
- "b2b5e83db3663f9e",
- "a432e760cc77e6cb",
- "0e1614cf2e5f9942"
+ "0e1614cf2e5f9942",
+ "7cc031e5a7d773a4",
+ "79900a566af02159",
+ "39d895a16ca6f6f1",
+ "62be7d38b991716c",
+ "cbb3b02ca505a55b",
+ "7db4b197df9eb075"
],
"x": 14,
"y": 839,
- "w": 1232,
- "h": 648
+ "w": 1178,
+ "h": 508
},
{
"id": "9b9e4fc50b744fc3",
@@ -290,13 +303,15 @@
},
"nodes": [
"7992eb250ae9d20f",
- "0bcc4cc5c0656a3b",
- "4ddff0572e76c3c6",
"7f063afdbac396ce",
"cbef8a3acc3d1495",
- "dd3face6611c0380",
"ad7393ac18c4083b",
- "407dbf096111ea43"
+ "b39062019fac1a66",
+ "7f50d9d83bdb7f14",
+ "c123fc5ed5e14e8a",
+ "673e45159a2dfccf",
+ "6c7eefa45db08cbc",
+ "cd72f360292bca50"
],
"x": 54,
"y": 479,
@@ -312,19 +327,18 @@
"label": true
},
"nodes": [
- "aba78041f885343a",
- "4eaade5db6a7a443",
- "bfad85a411436e1c",
- "d2b467822152a66e",
- "1a0b6df61dbcb683",
- "f444ee737beb9007",
"3fc9a8ed49514be5",
- "069f41d6a4ff8474"
+ "97a0c601b8918ede",
+ "772d6574f4181a44",
+ "c768d8ea1b8cf953",
+ "b277514c42c255e9",
+ "27b2f56921067f35",
+ "a804f93d06561c17"
],
- "x": 534,
- "y": 1319,
- "w": 772,
- "h": 282
+ "x": 394,
+ "y": 1499,
+ "w": 1052,
+ "h": 222
},
{
"id": "53e4faf6d3ece28c",
@@ -350,6 +364,116 @@
"w": 892,
"h": 322
},
+ {
+ "id": "541d31d14bcd8b00",
+ "type": "group",
+ "z": "239d7b3ba410ad5e",
+ "name": "comments table",
+ "style": {
+ "label": true
+ },
+ "nodes": [
+ "6a05187a692bed7c",
+ "fee2d22032a11056",
+ "f27b6d01ae7836d6",
+ "8f0bcaf04756da4f",
+ "e8b8e45c4bc045d8",
+ "840802d34d143ded",
+ "8d65b604e8d9e7f9",
+ "db1f35650c8d6448",
+ "6e2a152aecd929d3"
+ ],
+ "x": 14,
+ "y": 19,
+ "w": 1192,
+ "h": 222
+ },
+ {
+ "id": "0e3b2be7bcc3d3b8",
+ "type": "group",
+ "z": "239d7b3ba410ad5e",
+ "name": "DOWNLOAD tmdb - create JSON Events file from query",
+ "style": {
+ "label": true
+ },
+ "nodes": [
+ "f43a276d3a899fe8",
+ "c25ade7ddaeca697",
+ "c45589c369c843a5",
+ "f2bd56710ba03238",
+ "ecb0810a22dc4a5c",
+ "b4e0b45a7bedd728",
+ "5124f45846b94ef0",
+ "7050ed881890ce4d",
+ "82073a9c3e0f504f",
+ "44f3b2f2c2ae88fe"
+ ],
+ "x": 14,
+ "y": 619,
+ "w": 1272,
+ "h": 262
+ },
+ {
+ "id": "81c973dcdca1a4f0",
+ "type": "group",
+ "z": "239d7b3ba410ad5e",
+ "name": "database download links",
+ "style": {
+ "label": true
+ },
+ "nodes": [
+ "f31a598d.9fd2c8",
+ "98261154.3006",
+ "34dc99e5.495466",
+ "38d65d59.1d8aa2",
+ "3b8014a.86ad8ec",
+ "5b18a8e7.fb8da8",
+ "5de7cbb4.fa21a4",
+ "67ecfa7f.3f0e24"
+ ],
+ "x": 14,
+ "y": 259,
+ "w": 692,
+ "h": 262
+ },
+ {
+ "id": "1bfaaf118f38aee0",
+ "type": "group",
+ "z": "239d7b3ba410ad5e",
+ "name": "DOWNLOAD tmdb - create JSON Radar file from query",
+ "style": {
+ "label": true
+ },
+ "nodes": [
+ "38b44ecb9288caf2",
+ "55b8ab3b2b7af294",
+ "790a89794204c383",
+ "314a302b5d86fb5a",
+ "b00e6ad2a4612cad",
+ "7dba386e57337c72",
+ "04df9cb8c0753abb",
+ "3557178575375eb6",
+ "29583ca6de66fedf",
+ "91cae91e61fcea38",
+ "68fecdfda8e4e774",
+ "8c660460752a27b2",
+ "d50d86038fe1af32",
+ "b5e099e92ce27bf6",
+ "f77b0f12f5047d25",
+ "fbf290de9b7b858f",
+ "35dd409613d47a60",
+ "729b953264ce47aa",
+ "23b1ba527419b29b",
+ "b519f0927284d44a",
+ "2f3cc99c3c41ab90",
+ "62e90c91d0238273",
+ "c00796fd5642dae0"
+ ],
+ "x": 14,
+ "y": 919,
+ "w": 1392,
+ "h": 502
+ },
{
"id": "0e1614cf2e5f9942",
"type": "group",
@@ -366,7 +490,7 @@
"57fa6ca2b7d290e3"
],
"x": 54,
- "y": 1299,
+ "y": 1159,
"w": 1112,
"h": 162
},
@@ -495,21 +619,6 @@
"userProps": "",
"sessionExpiry": ""
},
- {
- "id": "73598328fc95017b",
- "type": "influxdb",
- "hostname": "127.0.0.1",
- "port": "8086",
- "protocol": "http",
- "database": "database",
- "name": "influxdb-node-red",
- "usetls": false,
- "tls": "",
- "influxdbVersion": "2.0",
- "url": "http://influxdb:8086",
- "timeout": "10",
- "rejectUnauthorized": true
- },
{
"id": "d65c36624d553ee7",
"type": "serial-port",
@@ -630,7 +739,7 @@
{
"id": "665d947f9a312a33",
"type": "ui_tab",
- "name": "Monitoring",
+ "name": "Monitoring Tab",
"icon": "dashboard",
"order": 1,
"disabled": false,
@@ -661,7 +770,7 @@
{
"id": "ddb9d86f10b3f6a7",
"type": "ui_tab",
- "name": "Database",
+ "name": "Database Tab",
"icon": "input",
"disabled": false,
"hidden": false
@@ -669,7 +778,7 @@
{
"id": "c0886ba4111fbfae",
"type": "ui_group",
- "name": "Database Output",
+ "name": "Database Downloads",
"tab": "ddb9d86f10b3f6a7",
"order": 2,
"disp": true,
@@ -686,7 +795,7 @@
{
"id": "d3f63882e39b03a6",
"type": "ui_group",
- "name": "Database Input",
+ "name": "Comments Input",
"tab": "ddb9d86f10b3f6a7",
"order": 1,
"disp": true,
@@ -694,6 +803,42 @@
"collapse": false,
"className": ""
},
+ {
+ "id": "1d8d8c9a28569355",
+ "type": "sqlitedb",
+ "db": "/db/radar",
+ "mode": "RWC"
+ },
+ {
+ "id": "eab37b30ecd3f935",
+ "type": "ui_group",
+ "name": "Events JSON Generator",
+ "tab": "ddb9d86f10b3f6a7",
+ "order": 4,
+ "disp": true,
+ "width": "6",
+ "collapse": false,
+ "className": ""
+ },
+ {
+ "id": "f0ca9c7dffb5ae3c",
+ "type": "ui_group",
+ "name": "Radar JSON Generator",
+ "tab": "ddb9d86f10b3f6a7",
+ "order": 5,
+ "disp": true,
+ "width": "6",
+ "collapse": false,
+ "className": ""
+ },
+ {
+ "id": "8a89c15ae12a462a",
+ "type": "ui_tab",
+ "name": "ThingsBoard tab",
+ "icon": "dashboard",
+ "disabled": false,
+ "hidden": false
+ },
{
"id": "e43506628b4a1cdb",
"type": "comment",
@@ -752,40 +897,8 @@
"targetType": "msg",
"statusVal": "",
"statusType": "auto",
- "x": 1160,
- "y": 740,
- "wires": []
- },
- {
- "id": "9496fe7a475726de",
- "type": "function",
- "z": "94d07e407c25f282",
- "g": "04cc3b7b3e019683",
- "name": "format influxdb write TimedSpeedCounts",
- "func": "\nconst newMsg = {};\n\nnewMsg.payload = [\n {\n speed_average: Number(msg.payload.TimedSpeedCounts.average),\n count: Number(msg.payload.TimedSpeedCounts.count),\n time: (msg.payload.TimedSpeedCounts.time*1000)\n },\n {\n location: env.get(\"VAR_LOCATION\"),\n direction: String(msg.payload.TimedSpeedCounts.direction),\n speed_units: msg.payload.TimedSpeedCounts.units\n }\n];\nreturn newMsg;",
- "outputs": 1,
- "timeout": 0,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 720,
- "y": 740,
- "wires": [
- [
- "617c9bb213538929",
- "35c0bee67148cfa7"
- ]
- ]
- },
- {
- "id": "a9d702a51bc8f0c9",
- "type": "comment",
- "z": "94d07e407c25f282",
- "name": "variables to pass",
- "info": "Via Docker Environment \n- `device_ip` of Pi (for influxDB server) --- env.get(\"VAR_DEVICE_IP\")\n- `location` string (for influxDB `location` tag) --- env.get(\"VAR_LOCATION\")\n- `radar_camera` name of camera (for attaching speeds to events) - needs to match Frigate config --- env.get(\"VAR_RADAR_CAMERA\") \n- `influxdb_database` --- env.get(\"VAR_INFLUXDB_BUCKET\")\n\n",
- "x": 360,
- "y": 60,
+ "x": 600,
+ "y": 800,
"wires": []
},
{
@@ -795,31 +908,10 @@
"g": "04cc3b7b3e019683",
"name": "TimedSpeedCounts are @O and @|300 (5-min)",
"info": "",
- "x": 1160,
- "y": 800,
+ "x": 600,
+ "y": 760,
"wires": []
},
- {
- "id": "4681243b9c70e906",
- "type": "function",
- "z": "94d07e407c25f282",
- "g": "1d00b3011a12b204",
- "name": "format influxdb write DetectedObjectVelocity",
- "func": "\nconst newMsg = {};\n\nnewMsg.payload = [\n {\n velocity: Number(msg.payload.DetectedObjectVelocity),\n time: (msg.payload.time*1000)\n },\n {\n location: env.get(\"VAR_LOCATION\"),\n direction: String(msg.payload.direction),\n velocity_units: msg.payload.unit\n }\n];\nreturn newMsg;",
- "outputs": 1,
- "timeout": 0,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 730,
- "y": 580,
- "wires": [
- [
- "b8db51ab64a3d61e"
- ]
- ]
- },
{
"id": "affe7cfb9861e62d",
"type": "serial in",
@@ -844,51 +936,13 @@
"y": 120,
"wires": []
},
- {
- "id": "617c9bb213538929",
- "type": "influxdb out",
- "z": "94d07e407c25f282",
- "g": "04cc3b7b3e019683",
- "influxdb": "73598328fc95017b",
- "name": "write influxdb TimedSpeedCounts",
- "measurement": "TimedSpeedCounts",
- "precision": "",
- "retentionPolicy": "",
- "database": "database",
- "precisionV18FluxV20": "ms",
- "retentionPolicyV18Flux": "",
- "org": "taffic_monitor_01",
- "bucket": "${VAR_INFLUXDB_BUCKET}",
- "x": 800,
- "y": 800,
- "wires": []
- },
- {
- "id": "b8db51ab64a3d61e",
- "type": "influxdb out",
- "z": "94d07e407c25f282",
- "g": "1d00b3011a12b204",
- "influxdb": "73598328fc95017b",
- "name": "write influxdb DetectedObjectVelocity",
- "measurement": "DetectedObjectVelocity",
- "precision": "",
- "retentionPolicy": "",
- "database": "database",
- "precisionV18FluxV20": "ms",
- "retentionPolicyV18Flux": "",
- "org": "taffic_monitor_01",
- "bucket": "${VAR_INFLUXDB_BUCKET}",
- "x": 810,
- "y": 640,
- "wires": []
- },
{
"id": "67f64c75edc0ef13",
"type": "debug",
"z": "94d07e407c25f282",
"g": "1d00b3011a12b204",
"name": "debug-radar-write-DetectObjectVelocity",
- "active": true,
+ "active": false,
"tosidebar": true,
"console": false,
"tostatus": false,
@@ -896,7 +950,7 @@
"targetType": "msg",
"statusVal": "",
"statusType": "auto",
- "x": 720,
+ "x": 580,
"y": 540,
"wires": []
},
@@ -1171,60 +1225,21 @@
"y": 540,
"wires": [
[
- "4681243b9c70e906",
- "67f64c75edc0ef13"
+ "67f64c75edc0ef13",
+ "8a653740e4fc4f6a"
],
[
- "9496fe7a475726de"
+ "35c0bee67148cfa7",
+ "585b91535ae4e8a3"
],
[
- "7b220a40adc14e3c",
- "ef9cb704c91a3ef6"
+ "d88af763b70480d0",
+ "d7eb8cf6f750f369",
+ "6580ac98734eba2e"
],
[
"3fc9a8ed49514be5",
- "4eaade5db6a7a443"
- ]
- ]
- },
- {
- "id": "d5e5d0f288f9b186",
- "type": "influxdb out",
- "z": "94d07e407c25f282",
- "g": "e138c998bef7d520",
- "influxdb": "73598328fc95017b",
- "name": "write influxdb RawSpeedMagnitude",
- "measurement": "RawSpeedMagnitude",
- "precision": "",
- "retentionPolicy": "",
- "database": "database",
- "precisionV18FluxV20": "ms",
- "retentionPolicyV18Flux": "",
- "org": "taffic_monitor_01",
- "bucket": "${VAR_INFLUXDB_BUCKET}",
- "x": 800,
- "y": 960,
- "wires": []
- },
- {
- "id": "7b220a40adc14e3c",
- "type": "function",
- "z": "94d07e407c25f282",
- "g": "e138c998bef7d520",
- "name": "format influxdb write raw speed, magnitude",
- "func": "var thisDirection = msg.payload.speed > 0 ? \"inbound\" : \"outbound\";\n\nconst newMsg = {};\n\nnewMsg.payload = [\n { //first object holds _field (speed_unit:value, magnitude:value)\n speed: String(msg.payload.speed),\n magnitude: String(msg.payload.magnitude),\n time: (msg.payload.time*1000)\n },\n { //second object holds tags\n location: env.get(\"VAR_LOCATION\"),\n direction: thisDirection,\n speed_units: msg.payload.unit\n }\n];\nreturn newMsg;",
- "outputs": 1,
- "timeout": 0,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 730,
- "y": 900,
- "wires": [
- [
- "d5e5d0f288f9b186",
- "d88af763b70480d0"
+ "a804f93d06561c17"
]
]
},
@@ -1242,8 +1257,8 @@
"targetType": "msg",
"statusVal": "",
"statusType": "auto",
- "x": 1110,
- "y": 900,
+ "x": 550,
+ "y": 1080,
"wires": []
},
{
@@ -1253,8 +1268,8 @@
"g": "e138c998bef7d520",
"name": "handle O3 speeds by saving array to each _value",
"info": "",
- "x": 740,
- "y": 1020,
+ "x": 600,
+ "y": 1040,
"wires": []
},
{
@@ -1271,67 +1286,8 @@
"targetType": "msg",
"statusVal": "",
"statusType": "auto",
- "x": 670,
- "y": 1560,
- "wires": []
- },
- {
- "id": "da47f12a5e2cd512",
- "type": "influxdb out",
- "z": "94d07e407c25f282",
- "g": "e5b5b46703e248e9",
- "influxdb": "73598328fc95017b",
- "name": "write influxdb RawSpeedMagnitude_single",
- "measurement": "RawSpeedMagnitude_single",
- "precision": "",
- "retentionPolicy": "",
- "database": "database",
- "precisionV18FluxV20": "ms",
- "retentionPolicyV18Flux": "",
- "org": "taffic_monitor_01",
- "bucket": "${VAR_INFLUXDB_BUCKET}",
- "x": 830,
- "y": 1180,
- "wires": []
- },
- {
- "id": "ef9cb704c91a3ef6",
- "type": "function",
- "z": "94d07e407c25f282",
- "g": "e5b5b46703e248e9",
- "name": "format influxdb write raw speed, magnitude single",
- "func": "var thisDirection = msg.payload.speed > 0 ? \"inbound\" : \"outbound\";\n\nconst newMsg = {};\n\nnewMsg.payload = [\n { //first object holds _field (speed_unit:value, magnitude:value)\n speed: String(msg.payload.speed[0]),\n magnitude: String(msg.payload.magnitude[0]),\n time: (msg.payload.time*1000)\n },\n { //second object holds tags\n location: env.get(\"VAR_LOCATION\"),\n direction: thisDirection,\n speed_units: msg.payload.unit\n }\n];\nreturn newMsg;",
- "outputs": 1,
- "timeout": 0,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 750,
- "y": 1120,
- "wires": [
- [
- "da47f12a5e2cd512",
- "c1c1371cdf7151aa"
- ]
- ]
- },
- {
- "id": "c1c1371cdf7151aa",
- "type": "debug",
- "z": "94d07e407c25f282",
- "g": "e5b5b46703e248e9",
- "name": "debug-radar-raws-speeds-write_single",
- "active": false,
- "tosidebar": true,
- "console": false,
- "tostatus": false,
- "complete": "payload",
- "targetType": "msg",
- "statusVal": "",
- "statusType": "auto",
- "x": 1130,
- "y": 1120,
+ "x": 510,
+ "y": 1540,
"wires": []
},
{
@@ -1341,8 +1297,8 @@
"g": "e5b5b46703e248e9",
"name": "manually take top 1 speed, magnitude (effectively O1)",
"info": "",
- "x": 760,
- "y": 1240,
+ "x": 660,
+ "y": 1440,
"wires": []
},
{
@@ -1404,48 +1360,53 @@
]
},
{
- "id": "aba78041f885343a",
+ "id": "0749f4279a336caf",
"type": "sqlite",
"z": "94d07e407c25f282",
- "g": "35a68b2baec193d2",
- "mydb": "2f60c1ab30a6fc8f",
- "sqlquery": "prepared",
- "sql": "INSERT INTO radar_oc_payload (end_time, start_time, delta_time_msec, dir, frames, max_mph, min_mph, max_mag, avg_mag, frames_per_mph, length_ft)\nVALUES ($end_time, $start_time, $delta_time_msec, $dir, $frames, $max_mph, $min_mph, $max_mag, $avg_mag, $frames_per_mph, $length_ft);",
+ "g": "1d00b3011a12b204",
+ "mydb": "1d8d8c9a28569355",
+ "sqlquery": "msg.topic",
+ "sql": "",
"name": "",
- "x": 1020,
- "y": 1500,
+ "x": 940,
+ "y": 580,
"wires": [
- []
+ [
+ "81c98c5e01bbfe09"
+ ]
]
},
{
- "id": "4eaade5db6a7a443",
- "type": "function",
+ "id": "56b9668b4f365f7b",
+ "type": "inject",
"z": "94d07e407c25f282",
- "g": "35a68b2baec193d2",
- "name": "write params for radar_oc_payload insert",
- "func": "\nconst obj = msg.payload;\n\nconst keyedObj = Object.keys(obj).reduce((acc, key) => {\n acc[`$${key}`] = obj[key];\n return acc;\n}, {});\n\nmsg.params = keyedObj;\n\nreturn msg;",
- "outputs": 1,
- "timeout": 0,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
+ "g": "1d00b3011a12b204",
+ "name": "create radar_dov table",
+ "props": [
+ {
+ "p": "topic",
+ "vt": "str"
+ }
+ ],
+ "repeat": "",
+ "crontab": "",
+ "once": true,
+ "onceDelay": 0.1,
+ "topic": "CREATE TABLE IF NOT EXISTS radar_dov (time REAL, unit TEXT, direction TEXT, velocity REAL);",
"x": 740,
- "y": 1500,
+ "y": 580,
"wires": [
[
- "aba78041f885343a",
- "d2b467822152a66e"
+ "0749f4279a336caf"
]
]
},
{
- "id": "bfad85a411436e1c",
+ "id": "ef4ad9faa7ec12e7",
"type": "inject",
"z": "94d07e407c25f282",
- "g": "35a68b2baec193d2",
- "name": "create radar_oc_payload table",
+ "g": "1d00b3011a12b204",
+ "name": "select latest 5 rows from radar_dov",
"props": [
{
"p": "topic",
@@ -1454,58 +1415,119 @@
],
"repeat": "",
"crontab": "",
- "once": true,
+ "once": false,
"onceDelay": 0.1,
- "topic": "CREATE TABLE IF NOT EXISTS radar_oc_payload ( end_time REAL, start_time REAL, delta_time_msec INTEGER, dir TEXT, frames INTEGER, max_mph REAL, min_mph REAL, max_mag REAL, avg_mag REAL, frames_per_mph REAL, length_ft REAL );",
- "x": 710,
- "y": 1360,
+ "topic": "SELECT * FROM radar_dov ORDER BY time DESC LIMIT 5;",
+ "x": 700,
+ "y": 620,
"wires": [
[
- "1a0b6df61dbcb683"
+ "0749f4279a336caf"
]
]
},
{
- "id": "d2b467822152a66e",
+ "id": "81c98c5e01bbfe09",
"type": "debug",
"z": "94d07e407c25f282",
- "g": "35a68b2baec193d2",
- "name": "debug 20",
- "active": false,
+ "g": "1d00b3011a12b204",
+ "name": "debug: last 5 rows radar_dov",
+ "active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
- "complete": "true",
- "targetType": "full",
+ "complete": "payload",
+ "targetType": "msg",
"statusVal": "",
"statusType": "auto",
- "x": 1020,
- "y": 1560,
+ "x": 1220,
+ "y": 580,
"wires": []
},
{
- "id": "1a0b6df61dbcb683",
+ "id": "87412467471d97a6",
"type": "sqlite",
"z": "94d07e407c25f282",
- "g": "35a68b2baec193d2",
- "mydb": "2f60c1ab30a6fc8f",
+ "g": "1d00b3011a12b204",
+ "mydb": "1d8d8c9a28569355",
+ "sqlquery": "prepared",
+ "sql": "INSERT INTO radar_dov (time, unit, direction, velocity) \nVALUES ($time, $unit, $direction, $velocity);\n",
+ "name": "",
+ "x": 940,
+ "y": 660,
+ "wires": [
+ []
+ ]
+ },
+ {
+ "id": "8a653740e4fc4f6a",
+ "type": "function",
+ "z": "94d07e407c25f282",
+ "g": "1d00b3011a12b204",
+ "name": "write params for radar_dov insert",
+ "func": "//convert DetectedObjectVelocity to velocity for insertion\nmsg.payload.velocity = msg.payload.DetectedObjectVelocity;\ndelete msg.payload.DetectedObjectVelocity;\n\nconst obj = msg.payload;\n\nconst keyedObj = Object.keys(obj).reduce((acc, key) => {\n acc[`$${key}`] = obj[key];\n return acc;\n}, {});\n\nmsg.params = keyedObj;\n\nreturn msg;",
+ "outputs": 1,
+ "timeout": 0,
+ "noerr": 0,
+ "initialize": "",
+ "finalize": "",
+ "libs": [],
+ "x": 700,
+ "y": 660,
+ "wires": [
+ [
+ "87412467471d97a6"
+ ]
+ ]
+ },
+ {
+ "id": "e3aa00721bf6faff",
+ "type": "sqlite",
+ "z": "94d07e407c25f282",
+ "g": "04cc3b7b3e019683",
+ "mydb": "1d8d8c9a28569355",
"sqlquery": "msg.topic",
- "sql": "INSERT INTO radar_oc_payload (end_time, start_time, delta_time_msec, dir, frames, max_mph, min_mph, max_mag, avg_mag, frames_per_mph, length_ft)\nVALUES ($end_time, $start_time, $delta_time_msec, $dir, $frames, $max_mph, $min_mph, $max_mag, $avg_mag, $frames_per_mph, $length_ft);",
+ "sql": "",
"name": "",
- "x": 1020,
- "y": 1360,
+ "x": 980,
+ "y": 860,
"wires": [
[
- "069f41d6a4ff8474"
+ "13059459bbc48328"
]
]
},
{
- "id": "f444ee737beb9007",
+ "id": "54ae78579d38e81b",
"type": "inject",
"z": "94d07e407c25f282",
- "g": "35a68b2baec193d2",
- "name": "select latest 5 rows from radar_oc_payload",
+ "g": "04cc3b7b3e019683",
+ "name": "create radar_timedspeedcounts table",
+ "props": [
+ {
+ "p": "topic",
+ "vt": "str"
+ }
+ ],
+ "repeat": "",
+ "crontab": "",
+ "once": true,
+ "onceDelay": 0.1,
+ "topic": "CREATE TABLE IF NOT EXISTS radar_timed_speed_counts (time REAL, direction TEXT, units TEXT, count INTEGER, average REAL);",
+ "x": 730,
+ "y": 860,
+ "wires": [
+ [
+ "e3aa00721bf6faff"
+ ]
+ ]
+ },
+ {
+ "id": "831310a0a0549da3",
+ "type": "inject",
+ "z": "94d07e407c25f282",
+ "g": "04cc3b7b3e019683",
+ "name": "select latest 5 rows from radar_timedspeedcounts",
"props": [
{
"p": "topic",
@@ -1516,21 +1538,21 @@
"crontab": "",
"once": false,
"onceDelay": 0.1,
- "topic": "SELECT * FROM radar_oc_payload ORDER BY end_time DESC LIMIT 5;",
- "x": 740,
- "y": 1400,
+ "topic": "SELECT * FROM radar_timed_speed_counts ORDER BY time DESC LIMIT 5;",
+ "x": 700,
+ "y": 900,
"wires": [
[
- "1a0b6df61dbcb683"
+ "e3aa00721bf6faff"
]
]
},
{
- "id": "069f41d6a4ff8474",
+ "id": "13059459bbc48328",
"type": "debug",
"z": "94d07e407c25f282",
- "g": "35a68b2baec193d2",
- "name": "debug: last 5 rows radar_oc_payload",
+ "g": "04cc3b7b3e019683",
+ "name": "debug: last 5 rows radar_timedspeedcounts",
"active": true,
"tosidebar": true,
"console": false,
@@ -1539,72 +1561,120 @@
"targetType": "msg",
"statusVal": "",
"statusType": "auto",
- "x": 1110,
- "y": 1420,
+ "x": 1270,
+ "y": 860,
"wires": []
},
{
- "id": "481344ed5f4b69d9",
- "type": "debug",
- "z": "9269520ddb532b00",
- "name": "debug: Broker status events",
- "active": false,
- "tosidebar": true,
- "console": false,
- "tostatus": false,
- "complete": "payload",
- "targetType": "msg",
- "statusVal": "",
- "statusType": "auto",
- "x": 340,
- "y": 100,
- "wires": []
+ "id": "585b91535ae4e8a3",
+ "type": "function",
+ "z": "94d07e407c25f282",
+ "g": "04cc3b7b3e019683",
+ "name": "write params for radar_timedspeedcounts insert",
+ "func": "//get rid of outer TimedSpeedCounts object\nmsg.payload = msg.payload.TimedSpeedCounts;\n\nconst obj = msg.payload;\n\nconst keyedObj = Object.keys(obj).reduce((acc, key) => {\n acc[`$${key}`] = obj[key];\n return acc;\n}, {});\n\nmsg.params = keyedObj;\n\nreturn msg;",
+ "outputs": 1,
+ "timeout": 0,
+ "noerr": 0,
+ "initialize": "",
+ "finalize": "",
+ "libs": [],
+ "x": 700,
+ "y": 940,
+ "wires": [
+ [
+ "477f8523e9784029"
+ ]
+ ]
},
{
- "id": "ec1ea8bc9a502a12",
- "type": "debug",
- "z": "9269520ddb532b00",
- "name": "debug: broker publish events",
- "active": false,
- "tosidebar": true,
- "console": false,
- "tostatus": false,
- "complete": "payload",
- "targetType": "msg",
- "statusVal": "",
- "statusType": "auto",
- "x": 340,
- "y": 140,
- "wires": []
+ "id": "477f8523e9784029",
+ "type": "sqlite",
+ "z": "94d07e407c25f282",
+ "g": "04cc3b7b3e019683",
+ "mydb": "1d8d8c9a28569355",
+ "sqlquery": "prepared",
+ "sql": "INSERT INTO radar_timed_speed_counts (time, direction, units, count, average)\nVALUES ($time, $direction, $units, $count, $average);\n",
+ "name": "",
+ "x": 980,
+ "y": 940,
+ "wires": [
+ []
+ ]
},
{
- "id": "f20c74c0ccfd256c",
- "type": "mqtt in",
- "z": "9269520ddb532b00",
+ "id": "dd48c6017098fe1d",
+ "type": "sqlite",
+ "z": "94d07e407c25f282",
+ "g": "e138c998bef7d520",
+ "mydb": "1d8d8c9a28569355",
+ "sqlquery": "msg.topic",
+ "sql": "",
"name": "",
- "topic": "frigate/events",
- "qos": "2",
- "datatype": "auto-detect",
- "broker": "a5d65dd0e3566daa",
- "nl": false,
- "rap": true,
- "rh": 0,
- "inputs": 0,
- "x": 90,
- "y": 200,
+ "x": 960,
+ "y": 1120,
"wires": [
[
- "86c86b0d82d13028",
- "2deec9d340d5ed26"
+ "825ddab22453e37c"
]
]
},
{
- "id": "86c86b0d82d13028",
+ "id": "e113c181976ad898",
+ "type": "inject",
+ "z": "94d07e407c25f282",
+ "g": "e138c998bef7d520",
+ "name": "create radar_raw_speed_magnitude table",
+ "props": [
+ {
+ "p": "topic",
+ "vt": "str"
+ }
+ ],
+ "repeat": "",
+ "crontab": "",
+ "once": true,
+ "onceDelay": 0.1,
+ "topic": "CREATE TABLE IF NOT EXISTS radar_raw_speed_magnitude (time REAL, unit TEXT, magnitude TEXT, speed TEXT);",
+ "x": 700,
+ "y": 1120,
+ "wires": [
+ [
+ "dd48c6017098fe1d"
+ ]
+ ]
+ },
+ {
+ "id": "e1461efd368bbee3",
+ "type": "inject",
+ "z": "94d07e407c25f282",
+ "g": "e138c998bef7d520",
+ "name": "select latest 5 rows from radar_raw_speed_magnitude",
+ "props": [
+ {
+ "p": "topic",
+ "vt": "str"
+ }
+ ],
+ "repeat": "",
+ "crontab": "",
+ "once": false,
+ "onceDelay": 0.1,
+ "topic": "SELECT * FROM radar_raw_speed_magnitude ORDER BY time DESC LIMIT 5;",
+ "x": 660,
+ "y": 1160,
+ "wires": [
+ [
+ "dd48c6017098fe1d"
+ ]
+ ]
+ },
+ {
+ "id": "825ddab22453e37c",
"type": "debug",
- "z": "9269520ddb532b00",
- "name": "debug: published frigate messages",
- "active": false,
+ "z": "94d07e407c25f282",
+ "g": "e138c998bef7d520",
+ "name": "debug: last 5 rows radar_raw_speed_magnitude",
+ "active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
@@ -1612,463 +1682,408 @@
"targetType": "msg",
"statusVal": "",
"statusType": "auto",
- "x": 340,
- "y": 200,
+ "x": 1260,
+ "y": 1120,
"wires": []
},
{
- "id": "a5ddaaa9ffdc637e",
- "type": "aedes broker",
- "z": "9269520ddb532b00",
- "name": "frigate-local",
- "mqtt_port": "1883",
- "mqtt_ws_bind": "port",
- "mqtt_ws_port": "",
- "mqtt_ws_path": "",
- "cert": "",
- "key": "",
- "certname": "",
- "keyname": "",
- "persistence_bind": "memory",
- "dburl": "",
- "usetls": false,
- "x": 90,
- "y": 120,
- "wires": [
- [
- "481344ed5f4b69d9"
- ],
- [
- "ec1ea8bc9a502a12"
- ]
+ "id": "1ddee1427e02c980",
+ "type": "sqlite",
+ "z": "94d07e407c25f282",
+ "g": "e138c998bef7d520",
+ "mydb": "1d8d8c9a28569355",
+ "sqlquery": "prepared",
+ "sql": "INSERT INTO radar_raw_speed_magnitude (time, unit, magnitude, speed) \nVALUES ($time, $unit, $magnitude, $speed);",
+ "name": "",
+ "x": 960,
+ "y": 1200,
+ "wires": [
+ []
]
},
{
- "id": "056bd6503d1c42c6",
- "type": "catch",
- "z": "9269520ddb532b00",
- "name": "catch - flow-mqtt",
- "scope": null,
- "uncaught": false,
- "x": 100,
- "y": 40,
+ "id": "d7eb8cf6f750f369",
+ "type": "function",
+ "z": "94d07e407c25f282",
+ "g": "e138c998bef7d520",
+ "name": "write params for radar_raw_speed_magnitude insert",
+ "func": "\nmsg.payload.magnitude = `${JSON.stringify(msg.payload.magnitude)}`; //array, wrap in single quote for sqlite insert as text\nmsg.payload.speed = `${JSON.stringify(msg.payload.speed)}`; //array, wrap in single quote for sqlite insert as text\n\nconst obj = msg.payload;\n\nconst keyedObj = Object.keys(obj).reduce((acc, key) => {\n acc[`$${key}`] = obj[key];\n return acc;\n}, {});\n\nmsg.params = keyedObj;\n\nreturn msg;",
+ "outputs": 1,
+ "timeout": 0,
+ "noerr": 0,
+ "initialize": "",
+ "finalize": "",
+ "libs": [],
+ "x": 660,
+ "y": 1200,
"wires": [
[
- "9fa6890312a00114"
+ "1ddee1427e02c980"
]
]
},
{
- "id": "9fa6890312a00114",
- "type": "debug",
- "z": "9269520ddb532b00",
- "name": "catch - flow-mqtt",
- "active": true,
- "tosidebar": true,
- "console": false,
- "tostatus": false,
- "complete": "true",
- "targetType": "full",
- "statusVal": "",
- "statusType": "auto",
- "x": 320,
- "y": 40,
- "wires": []
- },
- {
- "id": "2deec9d340d5ed26",
- "type": "switch",
- "z": "9269520ddb532b00",
- "g": "0a5faeac9fbd6d55",
- "name": "payload.type == \"end\"",
- "property": "payload.type",
- "propertyType": "msg",
- "rules": [
+ "id": "97a0c601b8918ede",
+ "type": "inject",
+ "z": "94d07e407c25f282",
+ "g": "35a68b2baec193d2",
+ "name": "create radar_oc_payload table",
+ "props": [
{
- "t": "eq",
- "v": "end",
+ "p": "topic",
"vt": "str"
}
],
- "checkall": "true",
- "repair": false,
- "outputs": 1,
- "x": 180,
- "y": 360,
+ "repeat": "",
+ "crontab": "",
+ "once": true,
+ "onceDelay": 0.1,
+ "topic": "CREATE TABLE IF NOT EXISTS radar_oc_payload ( end_time REAL, start_time REAL, delta_time_msec INTEGER, dir TEXT, frames INTEGER, max_mph REAL, min_mph REAL, max_mag REAL, avg_mag REAL, frames_per_mph REAL, length_ft REAL );",
+ "x": 750,
+ "y": 1600,
"wires": [
[
- "76911cc7f28e7da2"
+ "772d6574f4181a44"
]
]
},
{
- "id": "274f87c31437c2d7",
- "type": "link out",
- "z": "9269520ddb532b00",
- "g": "53e4faf6d3ece28c",
- "name": "to dashboard",
- "mode": "link",
- "links": [
- "c249329109ac17d5"
- ],
- "x": 935,
- "y": 1000,
- "wires": []
+ "id": "772d6574f4181a44",
+ "type": "sqlite",
+ "z": "94d07e407c25f282",
+ "g": "35a68b2baec193d2",
+ "mydb": "1d8d8c9a28569355",
+ "sqlquery": "msg.topic",
+ "sql": "INSERT INTO radar_oc_payload (end_time, start_time, delta_time_msec, dir, frames, max_mph, min_mph, max_mag, avg_mag, frames_per_mph, length_ft)\nVALUES ($end_time, $start_time, $delta_time_msec, $dir, $frames, $max_mph, $min_mph, $max_mag, $avg_mag, $frames_per_mph, $length_ft);",
+ "name": "",
+ "x": 980,
+ "y": 1600,
+ "wires": [
+ [
+ "b277514c42c255e9"
+ ]
+ ]
},
{
- "id": "76911cc7f28e7da2",
- "type": "change",
- "z": "9269520ddb532b00",
- "g": "0a5faeac9fbd6d55",
- "name": "set frigate_event from payload.after",
- "rules": [
+ "id": "c768d8ea1b8cf953",
+ "type": "inject",
+ "z": "94d07e407c25f282",
+ "g": "35a68b2baec193d2",
+ "name": "select latest 5 rows from radar_oc_payload",
+ "props": [
{
- "t": "set",
- "p": "frigate_event",
- "pt": "msg",
- "to": "payload.after",
- "tot": "msg"
+ "p": "topic",
+ "vt": "str"
}
],
- "action": "",
- "property": "",
- "from": "",
- "to": "",
- "reg": false,
- "x": 260,
- "y": 400,
+ "repeat": "",
+ "crontab": "",
+ "once": false,
+ "onceDelay": 0.1,
+ "topic": "SELECT * FROM radar_oc_payload ORDER BY end_time DESC LIMIT 5;",
+ "x": 720,
+ "y": 1640,
"wires": [
[
- "7f063afdbac396ce"
+ "772d6574f4181a44"
]
]
},
{
- "id": "0bcc4cc5c0656a3b",
- "type": "function",
- "z": "9269520ddb532b00",
- "g": "71c085648c20e329",
- "name": "create influxdb query, return DetectedObjectVelocity median",
- "func": "var query = \"\";\n\nquery += \"from(bucket: \\\"\" + env.get(\"VAR_INFLUXDB_BUCKET\") +\"\\\")\\n\";\nquery += \" |> range(start: \" + (Math.floor(msg.frigate_event.start_time)-2) +\", stop: \" + (Math.ceil(msg.frigate_event.end_time)+2) + \")\\n\";\nquery += \" |> filter(fn: (r) => r[\\\"_measurement\\\"] == \\\"DetectedObjectVelocity\\\")\\n\";\nquery += \" |> filter(fn: (r) => r[\\\"_field\\\"] == \\\"velocity\\\")\\n\";\nquery += \" |> filter(fn: (r) => r[\\\"location\\\"] == \\\"\" + env.get(\"VAR_LOCATION\") + \"\\\")\\n\";\nquery += \" |> median(column: \\\"_value\\\")\\n\"; \n\nmsg.query = query;\nreturn msg;",
- "outputs": 1,
- "timeout": 0,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 320,
- "y": 640,
- "wires": [
- [
- "407dbf096111ea43"
- ]
- ]
+ "id": "b277514c42c255e9",
+ "type": "debug",
+ "z": "94d07e407c25f282",
+ "g": "35a68b2baec193d2",
+ "name": "debug: last 5 rows radar_oc_payload",
+ "active": true,
+ "tosidebar": true,
+ "console": false,
+ "tostatus": false,
+ "complete": "payload",
+ "targetType": "msg",
+ "statusVal": "",
+ "statusType": "auto",
+ "x": 1250,
+ "y": 1600,
+ "wires": []
},
{
- "id": "4ddff0572e76c3c6",
- "type": "influxdb in",
- "z": "9269520ddb532b00",
- "g": "71c085648c20e329",
- "influxdb": "73598328fc95017b",
- "name": "query, DetectedObjectVelocity, median",
- "query": "",
- "rawOutput": false,
- "precision": "",
- "retentionPolicy": "",
- "org": "taffic_monitor_01",
- "x": 450,
- "y": 720,
+ "id": "27b2f56921067f35",
+ "type": "sqlite",
+ "z": "94d07e407c25f282",
+ "g": "35a68b2baec193d2",
+ "mydb": "1d8d8c9a28569355",
+ "sqlquery": "prepared",
+ "sql": "INSERT INTO radar_oc_payload (end_time, start_time, delta_time_msec, dir, frames, max_mph, min_mph, max_mag, avg_mag, frames_per_mph, length_ft)\nVALUES ($end_time, $start_time, $delta_time_msec, $dir, $frames, $max_mph, $min_mph, $max_mag, $avg_mag, $frames_per_mph, $length_ft);",
+ "name": "",
+ "x": 980,
+ "y": 1680,
"wires": [
- [
- "dd3face6611c0380"
- ]
+ []
]
},
{
- "id": "7992eb250ae9d20f",
+ "id": "a804f93d06561c17",
"type": "function",
- "z": "9269520ddb532b00",
- "g": "71c085648c20e329",
- "name": "calculate direction based on frigate event zones",
- "func": "//pass all fields required for speed match to event\n\nconst myZoneNearIndex = msg.frigate_event.entered_zones.indexOf(\"zone_near\");\nconst myZoneFarIndex = msg.frigate_event.entered_zones.indexOf(\"zone_far\");\n\nmsg.frigate_event.calc_zone_direction = (myZoneNearIndex >= 0 && myZoneFarIndex >= 0) ? (myZoneFarIndex < myZoneNearIndex ? \"inbound\" : \"outbound\") : undefined;\n\nreturn msg;",
+ "z": "94d07e407c25f282",
+ "g": "35a68b2baec193d2",
+ "name": "write params for radar_oc_payload insert",
+ "func": "\nconst obj = msg.payload;\n\nconst keyedObj = Object.keys(obj).reduce((acc, key) => {\n acc[`$${key}`] = obj[key];\n return acc;\n}, {});\n\nmsg.params = keyedObj;\n\nreturn msg;",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
- "x": 280,
- "y": 580,
+ "x": 720,
+ "y": 1680,
"wires": [
[
- "0bcc4cc5c0656a3b"
+ "27b2f56921067f35"
]
]
},
{
- "id": "7f063afdbac396ce",
- "type": "switch",
- "z": "9269520ddb532b00",
- "g": "71c085648c20e329",
- "name": "object entered ANY zone (include possible misses)",
- "property": "frigate_event.entered_zones",
- "propertyType": "msg",
- "rules": [
- {
- "t": "nempty"
- },
+ "id": "1d1c479b2567efbd",
+ "type": "sqlite",
+ "z": "94d07e407c25f282",
+ "g": "e5b5b46703e248e9",
+ "mydb": "1d8d8c9a28569355",
+ "sqlquery": "msg.topic",
+ "sql": "",
+ "name": "",
+ "x": 980,
+ "y": 1300,
+ "wires": [
+ [
+ "a1583c68a1dad33e"
+ ]
+ ]
+ },
+ {
+ "id": "795c120719c982de",
+ "type": "inject",
+ "z": "94d07e407c25f282",
+ "g": "e5b5b46703e248e9",
+ "name": "create radar_raw_speed_magnitude_single table",
+ "props": [
{
- "t": "else"
+ "p": "topic",
+ "vt": "str"
}
],
- "checkall": "true",
- "repair": false,
- "outputs": 2,
- "x": 270,
- "y": 520,
+ "repeat": "",
+ "crontab": "",
+ "once": true,
+ "onceDelay": 0.1,
+ "topic": "CREATE TABLE IF NOT EXISTS radar_raw_speed_magnitude_single (time REAL, unit TEXT, magnitude REAL, speed REAL);",
+ "x": 690,
+ "y": 1300,
"wires": [
[
- "7992eb250ae9d20f"
- ],
- [
- "ad7393ac18c4083b"
+ "1d1c479b2567efbd"
]
]
},
{
- "id": "cbef8a3acc3d1495",
- "type": "change",
- "z": "9269520ddb532b00",
- "g": "71c085648c20e329",
- "name": "set event_direction_speed",
- "rules": [
+ "id": "8180a480a85a6636",
+ "type": "inject",
+ "z": "94d07e407c25f282",
+ "g": "e5b5b46703e248e9",
+ "name": "select latest 5 rows from radar_raw_speed_magnitude_single",
+ "props": [
{
- "t": "set",
- "p": "event_direction_speed",
- "pt": "msg",
- "to": "payload",
- "tot": "msg"
+ "p": "topic",
+ "vt": "str"
}
],
- "action": "",
- "property": "",
- "from": "",
- "to": "",
- "reg": false,
- "x": 910,
- "y": 520,
+ "repeat": "",
+ "crontab": "",
+ "once": false,
+ "onceDelay": 0.1,
+ "topic": "SELECT * FROM radar_raw_speed_magnitude_single ORDER BY time DESC LIMIT 5;",
+ "x": 660,
+ "y": 1340,
"wires": [
[
- "a96d834e3571c549"
+ "1d1c479b2567efbd"
]
]
},
{
- "id": "dd3face6611c0380",
- "type": "function",
- "z": "9269520ddb532b00",
- "g": "71c085648c20e329",
- "name": "match radar speed to event",
- "func": "const newMsg = {};\nnewMsg.radar_DetectedObjectVelocity_median = msg.payload;\n\n//if only 1 Radar.direction USE THAT\nif (msg.payload.length == 1) {\n // check if Event.calc_zone_direction MATCHES Radar.direction THEN good\n if (msg.frigate_event.calc_zone_direction == msg.payload[0].direction) {\n newMsg.status_match_event_radar_direction = \"radar_speed_direction_match\";\n newMsg.calc_event_direction = (msg.frigate_event.calc_zone_direction || undefined);\n newMsg.calc_event_speed = msg.payload[0]._value;\n }\n // if Event.calc_zone_direction == undefined THEN use 1 that came through radar \n else if (msg.frigate_event.calc_zone_direction == undefined) {\n newMsg.status_match_event_radar_direction = \"radar_speed_direction_assigned\";\n newMsg.calc_event_direction = msg.payload[0].direction;\n newMsg.calc_event_speed = msg.payload[0]._value;\n }\n}\n// multiple radar directions, but if Event.calc_zone_direction MATCHES Radar.direction THEN good\nelse if ((msg.payload.length > 1)\n && (msg.frigate_event.calc_zone_direction != undefined)) {\n\n //find matching median value to frigate_event\n var dirIndex = msg.payload.map((o) => o.direction).indexOf(msg.frigate_event.calc_zone_direction);\n if (dirIndex >= 0) {\n newMsg.status_match_event_radar_direction = \"radar_speed_direction_match\";\n newMsg.calc_event_direction = msg.payload[dirIndex].direction;\n newMsg.calc_event_speed = msg.payload[dirIndex]._value;\n }\n else {\n newMsg.status_match_event_radar_direction = \"radar_speed_direction_mismatch\";\n newMsg.calc_event_direction = undefined;\n newMsg.calc_event_speed = undefined;\n }\n}\n// if == 0 Radar.direction DO NOT REPORT\nelse {\n newMsg.status_match_event_radar_direction = \"no_radar_speed_detected\"; \n newMsg.calc_event_direction = (msg.frigate_event.calc_zone_direction || undefined);\n newMsg.calc_event_speed = undefined;\n }\n\nmsg.payload = newMsg;\n\nreturn msg;",
- "outputs": 1,
- "timeout": 0,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 620,
- "y": 780,
+ "id": "a1583c68a1dad33e",
+ "type": "debug",
+ "z": "94d07e407c25f282",
+ "g": "e5b5b46703e248e9",
+ "name": "debug: last 5 rows radar_raw_speed_magnitude_single",
+ "active": true,
+ "tosidebar": true,
+ "console": false,
+ "tostatus": false,
+ "complete": "payload",
+ "targetType": "msg",
+ "statusVal": "",
+ "statusType": "auto",
+ "x": 1310,
+ "y": 1300,
+ "wires": []
+ },
+ {
+ "id": "382bf388390f91bd",
+ "type": "sqlite",
+ "z": "94d07e407c25f282",
+ "g": "e5b5b46703e248e9",
+ "mydb": "1d8d8c9a28569355",
+ "sqlquery": "prepared",
+ "sql": "INSERT INTO radar_raw_speed_magnitude_single (time, unit, magnitude, speed) \nVALUES ($time, $unit, $magnitude, $speed);",
+ "name": "",
+ "x": 980,
+ "y": 1380,
"wires": [
- [
- "cbef8a3acc3d1495"
- ]
+ []
]
},
{
- "id": "ad7393ac18c4083b",
+ "id": "6580ac98734eba2e",
"type": "function",
- "z": "9269520ddb532b00",
- "g": "71c085648c20e329",
- "name": "pass no direction, no speed",
- "func": "//no speed\nconst newMsg = {};\n\nnewMsg.status_match_event_radar_direction = \"direction_speed_no_zones\"; \nnewMsg.calc_event_direction = undefined;\nnewMsg.calc_event_speed = undefined;\n\nmsg.payload = newMsg;\n\nreturn msg;",
+ "z": "94d07e407c25f282",
+ "g": "e5b5b46703e248e9",
+ "name": "write params for radar_raw_speed_magnitude_single insert",
+ "func": "\nmsg.payload.magnitude = msg.payload.magnitude[0]; //array, wrap in single quote for sqlite insert as text\nmsg.payload.speed = msg.payload.speed[0]; //array, wrap in single quote for sqlite insert as text\n\nconst obj = msg.payload;\n\nconst keyedObj = Object.keys(obj).reduce((acc, key) => {\n acc[`$${key}`] = obj[key];\n return acc;\n}, {});\n\nmsg.params = keyedObj;\n\nreturn msg;",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
- "x": 640,
- "y": 520,
+ "x": 660,
+ "y": 1380,
"wires": [
[
- "cbef8a3acc3d1495"
+ "382bf388390f91bd"
]
]
},
{
- "id": "407dbf096111ea43",
- "type": "delay",
+ "id": "481344ed5f4b69d9",
+ "type": "debug",
"z": "9269520ddb532b00",
- "g": "71c085648c20e329",
- "name": "delay 1 sec, to be sure InfluxDB writes",
- "pauseType": "delay",
- "timeout": "1",
- "timeoutUnits": "seconds",
- "rate": "1",
- "nbRateUnits": "1",
- "rateUnits": "second",
- "randomFirst": "1",
- "randomLast": "5",
- "randomUnits": "seconds",
- "drop": false,
- "allowrate": false,
- "outputs": 1,
- "x": 450,
- "y": 680,
- "wires": [
- [
- "4ddff0572e76c3c6"
- ]
- ]
+ "name": "debug: Broker status events",
+ "active": false,
+ "tosidebar": true,
+ "console": false,
+ "tostatus": false,
+ "complete": "payload",
+ "targetType": "msg",
+ "statusVal": "",
+ "statusType": "auto",
+ "x": 340,
+ "y": 100,
+ "wires": []
},
{
- "id": "23f825551d9fe7ee",
- "type": "comment",
+ "id": "ec1ea8bc9a502a12",
+ "type": "debug",
"z": "9269520ddb532b00",
- "name": "do these steps SEQUENTIALLY or they may overlap w a JOIN node",
- "info": "",
- "x": 260,
- "y": 260,
+ "name": "debug: broker publish events",
+ "active": false,
+ "tosidebar": true,
+ "console": false,
+ "tostatus": false,
+ "complete": "payload",
+ "targetType": "msg",
+ "statusVal": "",
+ "statusType": "auto",
+ "x": 340,
+ "y": 140,
"wires": []
},
{
- "id": "510b389597efaf1b",
- "type": "sqlite",
+ "id": "f20c74c0ccfd256c",
+ "type": "mqtt in",
"z": "9269520ddb532b00",
- "g": "53e4faf6d3ece28c",
- "mydb": "2f60c1ab30a6fc8f",
- "sqlquery": "msg.topic",
- "sql": "",
"name": "",
- "x": 760,
- "y": 1140,
- "wires": [
- [
- "d8786159d48401b9"
- ]
- ]
- },
- {
- "id": "b77bb1c374a198e4",
- "type": "inject",
- "z": "9269520ddb532b00",
- "g": "53e4faf6d3ece28c",
- "name": "create table events",
- "props": [
- {
- "p": "topic",
- "vt": "str"
- }
- ],
- "repeat": "",
- "crontab": "",
- "once": true,
- "onceDelay": 0.1,
- "topic": "CREATE TABLE IF NOT EXISTS events ( id TEXT PRIMARY KEY, camera TEXT, label TEXT, sub_label, top_score REAL, frame_time REAL, start_time REAL, end_time REAL, entered_zones, direction_calc TEXT, speed_calc REAL, location TEXT );",
- "x": 550,
- "y": 1140,
+ "topic": "frigate/events",
+ "qos": "2",
+ "datatype": "auto-detect",
+ "broker": "a5d65dd0e3566daa",
+ "nl": false,
+ "rap": true,
+ "rh": 0,
+ "inputs": 0,
+ "x": 90,
+ "y": 200,
"wires": [
[
- "510b389597efaf1b"
+ "86c86b0d82d13028",
+ "2deec9d340d5ed26"
]
]
},
{
- "id": "61d6a19c99c60e0b",
- "type": "sqlite",
+ "id": "86c86b0d82d13028",
+ "type": "debug",
"z": "9269520ddb532b00",
- "g": "53e4faf6d3ece28c",
- "mydb": "2f60c1ab30a6fc8f",
- "sqlquery": "prepared",
- "sql": "INSERT INTO events (id, camera, label, sub_label, top_score, frame_time, start_time, end_time, entered_zones, direction_calc, speed_calc, location)\nVALUES ($id, $camera, $label, $sub_label, $top_score, $frame_time, $start_time, $end_time, json($entered_zones), $direction_calc, $speed_calc, $location);\n",
- "name": "tmdb.events, Prepared Statement",
- "x": 1060,
- "y": 940,
- "wires": [
- []
- ]
+ "name": "debug: published frigate messages",
+ "active": false,
+ "tosidebar": true,
+ "console": false,
+ "tostatus": false,
+ "complete": "payload",
+ "targetType": "msg",
+ "statusVal": "",
+ "statusType": "auto",
+ "x": 340,
+ "y": 200,
+ "wires": []
},
{
- "id": "a96d834e3571c549",
- "type": "function",
+ "id": "a5ddaaa9ffdc637e",
+ "type": "aedes broker",
"z": "9269520ddb532b00",
- "g": "53e4faf6d3ece28c",
- "name": "write params for events insert",
- "func": "const newMsg = {};\nnewMsg.payload = {}; // contain everything going into a DB record, single record\nnewMsg.payload = {}; // single collection of strings\n\n// Frigate Event info\nnewMsg.payload.id = msg.frigate_event.id;\nnewMsg.payload.camera = msg.frigate_event.camera;\nnewMsg.payload.label = msg.frigate_event.label;\nnewMsg.payload.sub_label = msg.frigate_event.sub_label;\nnewMsg.payload.top_score = msg.frigate_event.top_score;\n\n//for Timestamp, Mongo prefers MILLISECONDS (frigate event and radar uses seconds)\nnewMsg.payload.frame_time = msg.frigate_event.frame_time;\nnewMsg.payload.start_time = msg.frigate_event.start_time;\nnewMsg.payload.end_time = msg.frigate_event.end_time;\n\nnewMsg.payload.entered_zones = `${JSON.stringify(msg.frigate_event.entered_zones)}`; //array, wrap in single quote for sqlite insert as text\nnewMsg.payload.direction_calc = (msg.event_direction_speed.calc_event_direction || undefined);\nnewMsg.payload.speed_calc = (msg.event_direction_speed.calc_event_speed || undefined);\n\n//newMsg.payload.thumbnail_base64jpg = msg.frigate_event_api_thumbnail;\n\nnewMsg.payload.location = env.get(\"VAR_LOCATION\");\n\n\nconst obj = newMsg.payload;\n\nmsg.payload = newMsg.payload;\n\nconst keyedObj = Object.keys(obj).reduce((acc, key) => {\n acc[`$${key}`] = obj[key];\n return acc;\n}, {});\n\nmsg.params = keyedObj;\n\nreturn msg;",
- "outputs": 1,
- "timeout": 0,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 490,
- "y": 940,
+ "name": "frigate-local",
+ "mqtt_port": "1883",
+ "mqtt_ws_bind": "port",
+ "mqtt_ws_port": "",
+ "mqtt_ws_path": "",
+ "cert": "",
+ "key": "",
+ "certname": "",
+ "keyname": "",
+ "persistence_bind": "memory",
+ "dburl": "",
+ "usetls": false,
+ "x": 90,
+ "y": 120,
"wires": [
[
- "61d6a19c99c60e0b",
- "59a579e6a1fa9a08"
+ "481344ed5f4b69d9"
+ ],
+ [
+ "ec1ea8bc9a502a12"
]
]
},
{
- "id": "e256d5e89eb39332",
- "type": "inject",
+ "id": "056bd6503d1c42c6",
+ "type": "catch",
"z": "9269520ddb532b00",
- "g": "53e4faf6d3ece28c",
- "name": "select latest 5 rows from events",
- "props": [
- {
- "p": "topic",
- "vt": "str"
- }
- ],
- "repeat": "",
- "crontab": "",
- "once": false,
- "onceDelay": 0.1,
- "topic": "SELECT * FROM events ORDER BY end_time DESC LIMIT 5;",
- "x": 510,
- "y": 1180,
+ "name": "catch - flow-mqtt",
+ "scope": null,
+ "uncaught": false,
+ "x": 100,
+ "y": 40,
"wires": [
[
- "510b389597efaf1b"
+ "9fa6890312a00114"
]
]
},
{
- "id": "d8786159d48401b9",
- "type": "debug",
- "z": "9269520ddb532b00",
- "g": "53e4faf6d3ece28c",
- "name": "sqlite select last 5 msgs",
- "active": true,
- "tosidebar": true,
- "console": false,
- "tostatus": false,
- "complete": "payload",
- "targetType": "msg",
- "statusVal": "",
- "statusType": "auto",
- "x": 1030,
- "y": 1140,
- "wires": []
- },
- {
- "id": "7f0ef976c7b79245",
+ "id": "9fa6890312a00114",
"type": "debug",
"z": "9269520ddb532b00",
- "g": "53e4faf6d3ece28c",
- "name": "composed tmdb.events message",
+ "name": "catch - flow-mqtt",
"active": true,
"tosidebar": true,
"console": false,
@@ -2077,84 +2092,1060 @@
"targetType": "full",
"statusVal": "",
"statusType": "auto",
- "x": 580,
- "y": 1040,
+ "x": 320,
+ "y": 40,
"wires": []
},
{
- "id": "59a579e6a1fa9a08",
- "type": "function",
+ "id": "2deec9d340d5ed26",
+ "type": "switch",
"z": "9269520ddb532b00",
- "g": "53e4faf6d3ece28c",
- "name": "cleanse final msg.payload to forward along",
- "func": "let newMsg = {};\n\nnewMsg.topic = \"Dashboard event payload\"\nnewMsg.payload = msg.payload;\n\nreturn newMsg;",
- "outputs": 1,
- "timeout": 0,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 570,
+ "g": "0a5faeac9fbd6d55",
+ "name": "payload.type == \"end\"",
+ "property": "payload.type",
+ "propertyType": "msg",
+ "rules": [
+ {
+ "t": "eq",
+ "v": "end",
+ "vt": "str"
+ }
+ ],
+ "checkall": "true",
+ "repair": false,
+ "outputs": 1,
+ "x": 180,
+ "y": 360,
+ "wires": [
+ [
+ "76911cc7f28e7da2"
+ ]
+ ]
+ },
+ {
+ "id": "274f87c31437c2d7",
+ "type": "link out",
+ "z": "9269520ddb532b00",
+ "g": "53e4faf6d3ece28c",
+ "name": "to dashboard",
+ "mode": "link",
+ "links": [
+ "c249329109ac17d5"
+ ],
+ "x": 935,
"y": 1000,
+ "wires": []
+ },
+ {
+ "id": "76911cc7f28e7da2",
+ "type": "change",
+ "z": "9269520ddb532b00",
+ "g": "0a5faeac9fbd6d55",
+ "name": "set frigate_event from payload.after",
+ "rules": [
+ {
+ "t": "set",
+ "p": "frigate_event",
+ "pt": "msg",
+ "to": "payload.after",
+ "tot": "msg"
+ }
+ ],
+ "action": "",
+ "property": "",
+ "from": "",
+ "to": "",
+ "reg": false,
+ "x": 260,
+ "y": 400,
"wires": [
[
- "7f0ef976c7b79245",
- "274f87c31437c2d7"
+ "7f063afdbac396ce"
+ ]
+ ]
+ },
+ {
+ "id": "7992eb250ae9d20f",
+ "type": "function",
+ "z": "9269520ddb532b00",
+ "g": "71c085648c20e329",
+ "name": "calculate direction based on frigate event zones",
+ "func": "//pass all fields required for speed match to event\n\nconst myZoneNearIndex = msg.frigate_event.entered_zones.indexOf(\"zone_near\");\nconst myZoneFarIndex = msg.frigate_event.entered_zones.indexOf(\"zone_far\");\n\nmsg.frigate_event.calc_zone_direction = (myZoneNearIndex >= 0 && myZoneFarIndex >= 0) ? (myZoneFarIndex < myZoneNearIndex ? \"inbound\" : \"outbound\") : undefined;\n\nreturn msg;",
+ "outputs": 1,
+ "timeout": 0,
+ "noerr": 0,
+ "initialize": "",
+ "finalize": "",
+ "libs": [],
+ "x": 280,
+ "y": 580,
+ "wires": [
+ [
+ "b39062019fac1a66"
+ ]
+ ]
+ },
+ {
+ "id": "7f063afdbac396ce",
+ "type": "switch",
+ "z": "9269520ddb532b00",
+ "g": "71c085648c20e329",
+ "name": "object entered ANY zone (include possible misses)",
+ "property": "frigate_event.entered_zones",
+ "propertyType": "msg",
+ "rules": [
+ {
+ "t": "nempty"
+ },
+ {
+ "t": "else"
+ }
+ ],
+ "checkall": "true",
+ "repair": false,
+ "outputs": 2,
+ "x": 270,
+ "y": 520,
+ "wires": [
+ [
+ "7992eb250ae9d20f"
+ ],
+ [
+ "ad7393ac18c4083b"
+ ]
+ ]
+ },
+ {
+ "id": "cbef8a3acc3d1495",
+ "type": "change",
+ "z": "9269520ddb532b00",
+ "g": "71c085648c20e329",
+ "name": "set event_direction_speed",
+ "rules": [
+ {
+ "t": "set",
+ "p": "event_direction_speed",
+ "pt": "msg",
+ "to": "payload",
+ "tot": "msg"
+ }
+ ],
+ "action": "",
+ "property": "",
+ "from": "",
+ "to": "",
+ "reg": false,
+ "x": 910,
+ "y": 520,
+ "wires": [
+ [
+ "a96d834e3571c549"
+ ]
+ ]
+ },
+ {
+ "id": "ad7393ac18c4083b",
+ "type": "function",
+ "z": "9269520ddb532b00",
+ "g": "71c085648c20e329",
+ "name": "pass no direction, no speed",
+ "func": "//no speed\nconst newMsg = {};\n\nnewMsg.status_match_event_radar_direction = \"direction_speed_no_zones\"; \nnewMsg.calc_event_direction = undefined;\nnewMsg.calc_event_speed = undefined;\n\nmsg.payload = newMsg;\n\nreturn msg;",
+ "outputs": 1,
+ "timeout": 0,
+ "noerr": 0,
+ "initialize": "",
+ "finalize": "",
+ "libs": [],
+ "x": 640,
+ "y": 520,
+ "wires": [
+ [
+ "cbef8a3acc3d1495",
+ "cd72f360292bca50"
+ ]
+ ]
+ },
+ {
+ "id": "23f825551d9fe7ee",
+ "type": "comment",
+ "z": "9269520ddb532b00",
+ "name": "do these steps SEQUENTIALLY or they may overlap w a JOIN node",
+ "info": "",
+ "x": 260,
+ "y": 260,
+ "wires": []
+ },
+ {
+ "id": "510b389597efaf1b",
+ "type": "sqlite",
+ "z": "9269520ddb532b00",
+ "g": "53e4faf6d3ece28c",
+ "mydb": "2f60c1ab30a6fc8f",
+ "sqlquery": "msg.topic",
+ "sql": "",
+ "name": "",
+ "x": 760,
+ "y": 1140,
+ "wires": [
+ [
+ "d8786159d48401b9"
+ ]
+ ]
+ },
+ {
+ "id": "b77bb1c374a198e4",
+ "type": "inject",
+ "z": "9269520ddb532b00",
+ "g": "53e4faf6d3ece28c",
+ "name": "create table events",
+ "props": [
+ {
+ "p": "topic",
+ "vt": "str"
+ }
+ ],
+ "repeat": "",
+ "crontab": "",
+ "once": true,
+ "onceDelay": 0.1,
+ "topic": "CREATE TABLE IF NOT EXISTS events ( id TEXT PRIMARY KEY, camera TEXT, label TEXT, sub_label, top_score REAL, frame_time REAL, start_time REAL, end_time REAL, entered_zones, direction_calc TEXT, speed_calc REAL, location TEXT );",
+ "x": 550,
+ "y": 1140,
+ "wires": [
+ [
+ "510b389597efaf1b"
+ ]
+ ]
+ },
+ {
+ "id": "61d6a19c99c60e0b",
+ "type": "sqlite",
+ "z": "9269520ddb532b00",
+ "g": "53e4faf6d3ece28c",
+ "mydb": "2f60c1ab30a6fc8f",
+ "sqlquery": "prepared",
+ "sql": "INSERT INTO events (id, camera, label, sub_label, top_score, frame_time, start_time, end_time, entered_zones, direction_calc, speed_calc, location)\nVALUES ($id, $camera, $label, $sub_label, $top_score, $frame_time, $start_time, $end_time, json($entered_zones), $direction_calc, $speed_calc, $location);\n",
+ "name": "tmdb.events, Prepared Statement",
+ "x": 1060,
+ "y": 940,
+ "wires": [
+ []
+ ]
+ },
+ {
+ "id": "a96d834e3571c549",
+ "type": "function",
+ "z": "9269520ddb532b00",
+ "g": "53e4faf6d3ece28c",
+ "name": "write params for events insert",
+ "func": "const newMsg = {};\nnewMsg.payload = {}; // contain everything going into a DB record, single record\nnewMsg.payload = {}; // single collection of strings\n\n// Frigate Event info\nnewMsg.payload.id = msg.frigate_event.id;\nnewMsg.payload.camera = msg.frigate_event.camera;\nnewMsg.payload.label = msg.frigate_event.label;\nnewMsg.payload.sub_label = msg.frigate_event.sub_label;\nnewMsg.payload.top_score = msg.frigate_event.top_score;\n\n//for Timestamp, Mongo prefers MILLISECONDS (frigate event and radar uses seconds)\nnewMsg.payload.frame_time = msg.frigate_event.frame_time;\nnewMsg.payload.start_time = msg.frigate_event.start_time;\nnewMsg.payload.end_time = msg.frigate_event.end_time;\n\nnewMsg.payload.entered_zones = `${JSON.stringify(msg.frigate_event.entered_zones)}`; //array, wrap in single quote for sqlite insert as text\nnewMsg.payload.direction_calc = (msg.event_direction_speed.calc_event_direction || undefined);\nnewMsg.payload.speed_calc = (msg.event_direction_speed.calc_event_speed || undefined);\n\n//newMsg.payload.thumbnail_base64jpg = msg.frigate_event_api_thumbnail;\n\nnewMsg.payload.location = env.get(\"VAR_LOCATION\");\n\n\nconst obj = newMsg.payload;\n\nmsg.payload = newMsg.payload;\n\nconst keyedObj = Object.keys(obj).reduce((acc, key) => {\n acc[`$${key}`] = obj[key];\n return acc;\n}, {});\n\nmsg.params = keyedObj;\n\nreturn msg;",
+ "outputs": 1,
+ "timeout": 0,
+ "noerr": 0,
+ "initialize": "",
+ "finalize": "",
+ "libs": [],
+ "x": 490,
+ "y": 940,
+ "wires": [
+ [
+ "61d6a19c99c60e0b",
+ "59a579e6a1fa9a08"
]
]
},
{
- "id": "3985037239b671c5",
- "type": "inject",
+ "id": "e256d5e89eb39332",
+ "type": "inject",
+ "z": "9269520ddb532b00",
+ "g": "53e4faf6d3ece28c",
+ "name": "select latest 5 rows from events",
+ "props": [
+ {
+ "p": "topic",
+ "vt": "str"
+ }
+ ],
+ "repeat": "",
+ "crontab": "",
+ "once": false,
+ "onceDelay": 0.1,
+ "topic": "SELECT * FROM events ORDER BY end_time DESC LIMIT 5;",
+ "x": 510,
+ "y": 1180,
+ "wires": [
+ [
+ "510b389597efaf1b"
+ ]
+ ]
+ },
+ {
+ "id": "d8786159d48401b9",
+ "type": "debug",
+ "z": "9269520ddb532b00",
+ "g": "53e4faf6d3ece28c",
+ "name": "sqlite select last 5 msgs",
+ "active": true,
+ "tosidebar": true,
+ "console": false,
+ "tostatus": false,
+ "complete": "payload",
+ "targetType": "msg",
+ "statusVal": "",
+ "statusType": "auto",
+ "x": 1030,
+ "y": 1140,
+ "wires": []
+ },
+ {
+ "id": "7f0ef976c7b79245",
+ "type": "debug",
+ "z": "9269520ddb532b00",
+ "g": "53e4faf6d3ece28c",
+ "name": "composed tmdb.events message",
+ "active": true,
+ "tosidebar": true,
+ "console": false,
+ "tostatus": false,
+ "complete": "true",
+ "targetType": "full",
+ "statusVal": "",
+ "statusType": "auto",
+ "x": 580,
+ "y": 1040,
+ "wires": []
+ },
+ {
+ "id": "59a579e6a1fa9a08",
+ "type": "function",
+ "z": "9269520ddb532b00",
+ "g": "53e4faf6d3ece28c",
+ "name": "cleanse final msg.payload to forward along",
+ "func": "let newMsg = {};\n\nnewMsg.topic = \"tm/event\"\nnewMsg.payload = msg.payload;\n\nreturn newMsg;",
+ "outputs": 1,
+ "timeout": 0,
+ "noerr": 0,
+ "initialize": "",
+ "finalize": "",
+ "libs": [],
+ "x": 570,
+ "y": 1000,
+ "wires": [
+ [
+ "7f0ef976c7b79245",
+ "274f87c31437c2d7"
+ ]
+ ]
+ },
+ {
+ "id": "b39062019fac1a66",
+ "type": "function",
+ "z": "9269520ddb532b00",
+ "g": "71c085648c20e329",
+ "name": "pull speed, direction for event period",
+ "func": "let query = \"SELECT * FROM radar_dov WHERE time BETWEEN \" + (Math.floor(msg.frigate_event.start_time) - 2) +\" AND \" + (Math.ceil(msg.frigate_event.end_time) + 2) + \";\";\n\nmsg.topic = query;\n\nreturn msg;",
+ "outputs": 1,
+ "timeout": 0,
+ "noerr": 0,
+ "initialize": "",
+ "finalize": "",
+ "libs": [],
+ "x": 350,
+ "y": 640,
+ "wires": [
+ [
+ "7f50d9d83bdb7f14"
+ ]
+ ]
+ },
+ {
+ "id": "7f50d9d83bdb7f14",
+ "type": "sqlite",
+ "z": "9269520ddb532b00",
+ "g": "71c085648c20e329",
+ "mydb": "1d8d8c9a28569355",
+ "sqlquery": "msg.topic",
+ "sql": "",
+ "name": "",
+ "x": 440,
+ "y": 680,
+ "wires": [
+ [
+ "c123fc5ed5e14e8a"
+ ]
+ ]
+ },
+ {
+ "id": "c123fc5ed5e14e8a",
+ "type": "function",
+ "z": "9269520ddb532b00",
+ "g": "71c085648c20e329",
+ "name": "calculate median per direction",
+ "func": "const medianVelocityPerDirection = {};\n\n// Group the data by direction\nconst groupedData = msg.payload.reduce((acc, curr) => {\n if (!acc[curr.direction]) {\n acc[curr.direction] = [];\n }\n acc[curr.direction].push(curr);\n return acc;\n}, {});\n\n// Calculate the median velocity for each direction\nfor (const direction in groupedData) {\n if (groupedData.hasOwnProperty(direction)) {\n const sortedVelocities = groupedData[direction].map(entry => entry.velocity).sort((a, b) => a - b);\n const medianIndex = Math.floor(sortedVelocities.length / 2);\n const medianVelocity =\n sortedVelocities.length % 2 === 0\n ? (sortedVelocities[medianIndex - 1] + sortedVelocities[medianIndex]) / 2\n : sortedVelocities[medianIndex];\n medianVelocityPerDirection[direction] = medianVelocity;\n }\n}\n\nmsg.payload = medianVelocityPerDirection;\n\nreturn msg;",
+ "outputs": 1,
+ "timeout": 0,
+ "noerr": 0,
+ "initialize": "",
+ "finalize": "",
+ "libs": [],
+ "x": 430,
+ "y": 740,
+ "wires": [
+ [
+ "673e45159a2dfccf"
+ ]
+ ]
+ },
+ {
+ "id": "673e45159a2dfccf",
+ "type": "function",
+ "z": "9269520ddb532b00",
+ "g": "71c085648c20e329",
+ "name": "match radar speed to event",
+ "func": "const newMsg = {};\nnewMsg.radar_DetectedObjectVelocity_median = msg.payload;\n\n//if only 1 Radar.direction USE THAT\nif (Object.keys(msg.payload).length == 1) {\n // check if Event.calc_zone_direction MATCHES Radar.direction THEN good\n if (msg.payload[msg.frigate_event.calc_zone_direction]) {\n newMsg.status_match_event_radar_direction = \"radar_speed_direction_match\";\n newMsg.calc_event_direction = (msg.frigate_event.calc_zone_direction || undefined);\n newMsg.calc_event_speed = msg.payload[msg.frigate_event.calc_zone_direction];\n }\n // if Event.calc_zone_direction == undefined THEN use 1 that came through radar \n else if (msg.frigate_event.calc_zone_direction == undefined) {\n newMsg.status_match_event_radar_direction = \"radar_speed_direction_assigned\";\n newMsg.calc_event_direction = Object.keys(msg.payload)[0];\n newMsg.calc_event_speed = msg.payload[Object.keys(msg.payload)[0]];\n }\n}\n// multiple radar directions, but if Event.calc_zone_direction MATCHES Radar.direction THEN good\nelse if ((Object.keys(msg.payload).length > 1)\n && (msg.frigate_event.calc_zone_direction != undefined)) {\n\n //find matching median value to frigate_event\n if (msg.payload[msg.frigate_event.calc_zone_direction]) {\n newMsg.status_match_event_radar_direction = \"radar_speed_direction_match\";\n newMsg.calc_event_direction = msg.frigate_event.calc_zone_direction;\n newMsg.calc_event_speed = msg.payload[msg.frigate_event.calc_zone_direction];\n }\n else {\n newMsg.status_match_event_radar_direction = \"radar_speed_direction_mismatch\";\n newMsg.calc_event_direction = undefined;\n newMsg.calc_event_speed = undefined;\n }\n}\n// if == 0 Radar.direction DO NOT REPORT\nelse {\n newMsg.status_match_event_radar_direction = \"no_radar_speed_detected\"; \n newMsg.calc_event_direction = (msg.frigate_event.calc_zone_direction || undefined);\n newMsg.calc_event_speed = undefined;\n }\n\nmsg.payload = newMsg;\n\nreturn msg;",
+ "outputs": 1,
+ "timeout": 0,
+ "noerr": 0,
+ "initialize": "",
+ "finalize": "",
+ "libs": [],
+ "x": 480,
+ "y": 780,
+ "wires": [
+ [
+ "cbef8a3acc3d1495",
+ "6c7eefa45db08cbc"
+ ]
+ ]
+ },
+ {
+ "id": "6c7eefa45db08cbc",
+ "type": "debug",
+ "z": "9269520ddb532b00",
+ "g": "71c085648c20e329",
+ "name": "debug 1",
+ "active": true,
+ "tosidebar": true,
+ "console": false,
+ "tostatus": false,
+ "complete": "true",
+ "targetType": "full",
+ "statusVal": "",
+ "statusType": "auto",
+ "x": 760,
+ "y": 780,
+ "wires": []
+ },
+ {
+ "id": "cd72f360292bca50",
+ "type": "debug",
+ "z": "9269520ddb532b00",
+ "g": "71c085648c20e329",
+ "name": "debug 2",
+ "active": true,
+ "tosidebar": true,
+ "console": false,
+ "tostatus": false,
+ "complete": "false",
+ "statusVal": "",
+ "statusType": "auto",
+ "x": 860,
+ "y": 580,
+ "wires": []
+ },
+ {
+ "id": "3985037239b671c5",
+ "type": "inject",
+ "z": "28627559bebdc324",
+ "g": "5173f4b3ac03407a",
+ "name": "trigger Event query every 60-min",
+ "props": [
+ {
+ "p": "payload"
+ },
+ {
+ "p": "topic",
+ "vt": "str"
+ }
+ ],
+ "repeat": "3600",
+ "crontab": "",
+ "once": true,
+ "onceDelay": "2",
+ "topic": "query",
+ "payload": "",
+ "payloadType": "date",
+ "x": 200,
+ "y": 600,
+ "wires": [
+ [
+ "928b71f25ce6e7b6"
+ ]
+ ]
+ },
+ {
+ "id": "08d030ffc3fe6adb",
+ "type": "ui_chart",
+ "z": "28627559bebdc324",
+ "g": "5aac1262472b0205",
+ "name": "frigate summary daily, objects",
+ "group": "06dde4be9a9a6b27",
+ "order": 3,
+ "width": 6,
+ "height": 7,
+ "label": "frigate api/events/summary daily object count for the last 10-days",
+ "chartType": "line",
+ "legend": "true",
+ "xformat": "Y-M-D",
+ "interpolate": "linear",
+ "nodata": "",
+ "dot": true,
+ "ymin": "",
+ "ymax": "",
+ "removeOlder": "10",
+ "removeOlderPoints": "10000",
+ "removeOlderUnit": "86400",
+ "cutout": 0,
+ "useOneColor": false,
+ "useUTC": false,
+ "colors": [
+ "#1f77b4",
+ "#aec7e8",
+ "#ff7f0e",
+ "#2ca02c",
+ "#98df8a",
+ "#d62728",
+ "#ff9896",
+ "#9467bd",
+ "#c5b0d5"
+ ],
+ "outputs": 1,
+ "useDifferentColor": false,
+ "className": "",
+ "x": 710,
+ "y": 240,
+ "wires": [
+ []
+ ]
+ },
+ {
+ "id": "b241a0ef89fd7ce4",
+ "type": "http request",
+ "z": "28627559bebdc324",
+ "g": "5aac1262472b0205",
+ "name": "frigate api/events/summary - Daily summary",
+ "method": "GET",
+ "ret": "obj",
+ "paytoqs": "ignore",
+ "url": "http://frigate:5000/api/events/summary",
+ "tls": "",
+ "persist": false,
+ "proxy": "",
+ "insecureHTTPParser": false,
+ "authType": "",
+ "senderr": false,
+ "headers": [],
+ "x": 310,
+ "y": 180,
+ "wires": [
+ [
+ "eb140f61419c6a08"
+ ]
+ ],
+ "info": "`{\"camera\":\"picam_gs_h264\",\n\"count\":83,\"day\":\"2024-03-21\",\n\"label\":\"bicycle\",\n\"sub_label\":null,\n\"zones\":[]}`"
+ },
+ {
+ "id": "91d3f8965f62f4b0",
+ "type": "inject",
+ "z": "28627559bebdc324",
+ "g": "5aac1262472b0205",
+ "name": "trigger summary Event query every 2-hours",
+ "props": [],
+ "repeat": "7200",
+ "crontab": "",
+ "once": true,
+ "onceDelay": "5",
+ "topic": "",
+ "x": 230,
+ "y": 120,
+ "wires": [
+ [
+ "b241a0ef89fd7ce4"
+ ]
+ ]
+ },
+ {
+ "id": "eb140f61419c6a08",
+ "type": "function",
+ "z": "28627559bebdc324",
+ "g": "5aac1262472b0205",
+ "name": "structure frigate api/summary",
+ "func": "var newMsg = [{}];\nnewMsg[0].series = [];\nnewMsg[0].data = [];\nnewMsg[0].label = [];\n\nmsg.payload.forEach((myItem) => {\n\n //only do this for the radar camera and 10 days or less ago\n if (myItem.camera == env.get(\"VAR_RADAR_CAMERA\") && new Date(myItem.day).getTime() >= Math.floor((Date.now() - 86400000 * 10))) {\n //if label doesn't exist, push it\n if (newMsg[0].series.indexOf(myItem.label) < 0) {\n newMsg[0].series.push(myItem.label);\n //create new data array element that matches the series index\n newMsg[0].data[newMsg[0].series.indexOf(myItem.label)] = [];\n }\n\n //Check if it's a new date or existing in data[0][0].x\n //datapoint for date \n let xIndex = newMsg[0].data[newMsg[0].series.indexOf(myItem.label)].findIndex((element) => element.x == String(new Date(myItem.day)));\n if (xIndex < 0) {\n //new date\n let thisDataPoint = {};\n thisDataPoint.x = new Date(myItem.day);\n thisDataPoint.y = myItem.count;\n newMsg[0].data[newMsg[0].series.indexOf(myItem.label)].push(thisDataPoint);\n }\n else {\n //date exists, sum counts\n newMsg[0].data[newMsg[0].series.indexOf(myItem.label)][xIndex].y += myItem.count;\n }\n\n };\n \n});\n\nmsg.payload = newMsg;\n\nreturn msg;",
+ "outputs": 1,
+ "timeout": 0,
+ "noerr": 0,
+ "initialize": "",
+ "finalize": "",
+ "libs": [],
+ "x": 400,
+ "y": 240,
+ "wires": [
+ [
+ "08d030ffc3fe6adb"
+ ]
+ ]
+ },
+ {
+ "id": "404ac097795a2da0",
+ "type": "inject",
+ "z": "28627559bebdc324",
+ "g": "0a6e123f5e53c029",
+ "name": "trigger Event query every 2-hours",
+ "props": [
+ {
+ "p": "payload"
+ },
+ {
+ "p": "topic",
+ "vt": "str"
+ }
+ ],
+ "repeat": "7200",
+ "crontab": "",
+ "once": true,
+ "onceDelay": "5",
+ "topic": "query",
+ "payload": "",
+ "payloadType": "date",
+ "x": 200,
+ "y": 360,
+ "wires": [
+ [
+ "5f3716d2176c3ab4"
+ ]
+ ]
+ },
+ {
+ "id": "b65e1877b1e04881",
+ "type": "ui_chart",
+ "z": "28627559bebdc324",
+ "g": "0a6e123f5e53c029",
+ "name": "events summary daily, objects",
+ "group": "06dde4be9a9a6b27",
+ "order": 4,
+ "width": 6,
+ "height": 7,
+ "label": "events daily object count for the last 10-days",
+ "chartType": "line",
+ "legend": "true",
+ "xformat": "Y-M-D",
+ "interpolate": "linear",
+ "nodata": "",
+ "dot": true,
+ "ymin": "",
+ "ymax": "",
+ "removeOlder": "10",
+ "removeOlderPoints": "10000",
+ "removeOlderUnit": "86400",
+ "cutout": 0,
+ "useOneColor": false,
+ "useUTC": false,
+ "colors": [
+ "#1f77b4",
+ "#aec7e8",
+ "#ff7f0e",
+ "#2ca02c",
+ "#98df8a",
+ "#d62728",
+ "#ff9896",
+ "#9467bd",
+ "#c5b0d5"
+ ],
+ "outputs": 1,
+ "useDifferentColor": false,
+ "className": "",
+ "x": 710,
+ "y": 480,
+ "wires": [
+ []
+ ]
+ },
+ {
+ "id": "c249329109ac17d5",
+ "type": "link in",
+ "z": "28627559bebdc324",
+ "name": "from mongo event capture",
+ "links": [
+ "d9a2cc1e81161549",
+ "274f87c31437c2d7"
+ ],
+ "x": 165,
+ "y": 1580,
+ "wires": [
+ [
+ "5ec2d3ba52f944f5",
+ "82bc0c11adb825f8",
+ "736d1e21a49f446b",
+ "f57e08e6fb9c0d09"
+ ]
+ ]
+ },
+ {
+ "id": "d66541089b01306e",
+ "type": "switch",
+ "z": "28627559bebdc324",
+ "g": "9b9e4fc50b744fc3",
+ "name": "only event with speed",
+ "property": "$abs(payload.speed_calc)",
+ "propertyType": "jsonata",
+ "rules": [
+ {
+ "t": "gt",
+ "v": "20",
+ "vt": "num"
+ }
+ ],
+ "checkall": "true",
+ "repair": false,
+ "outputs": 1,
+ "x": 750,
+ "y": 1940,
+ "wires": [
+ [
+ "c788d632f5e93a73"
+ ]
+ ]
+ },
+ {
+ "id": "2e680914d7da5c94",
+ "type": "switch",
+ "z": "28627559bebdc324",
+ "g": "9b9e4fc50b744fc3",
+ "name": "only zone_radar",
+ "property": "payload.entered_zones",
+ "propertyType": "msg",
+ "rules": [
+ {
+ "t": "cont",
+ "v": "zone_radar",
+ "vt": "str"
+ }
+ ],
+ "checkall": "true",
+ "repair": false,
+ "outputs": 1,
+ "x": 390,
+ "y": 1660,
+ "wires": [
+ [
+ "c2270f3050bf35ab"
+ ]
+ ]
+ },
+ {
+ "id": "c788d632f5e93a73",
+ "type": "function",
+ "z": "28627559bebdc324",
+ "g": "9b9e4fc50b744fc3",
+ "name": "store last N speed events",
+ "func": "//events_recent_radar should show the last N events where payload.entered_zones CONTAINS zone_radar\n\nvar myEvents = flow.get(\"events_recent_speed\") || [];\n//Keep only last X elements\nvar myArrLength = 3;\n\n//invert array so OLDEST IS FIRST, for functions\nmyEvents.reverse();\n\nif (myEvents.length >= myArrLength) {\n //remove first element (oldest event)\n myEvents.shift();\n}\n\n//add current event to end of array\nmyEvents.push(msg.payload);\n\n//invert array so NEWEST IS FIRST, for display\nmyEvents.reverse();\n\nflow.set(\"events_recent_speed\", myEvents);\n\nmsg.payload = myEvents;\n\nreturn msg;",
+ "outputs": 1,
+ "timeout": 0,
+ "noerr": 0,
+ "initialize": "// Code added here will be run once\n// whenever the node is started.\n\nif (flow.get(\"events_recent_radar\") === undefined) {\n flow.set(\"events_recent_radar\", [])\n}\n",
+ "finalize": "",
+ "libs": [],
+ "x": 800,
+ "y": 1980,
+ "wires": [
+ [
+ "4c087723a1d698e9"
+ ]
+ ]
+ },
+ {
+ "id": "e5391514131a2b5a",
+ "type": "function",
+ "z": "28627559bebdc324",
+ "g": "9b9e4fc50b744fc3",
+ "name": "store last N radar events",
+ "func": "//events_recent_radar should show the last N events where payload.entered_zones CONTAINS zone_radar\n\nvar myEvents = flow.get(\"events_recent_radar\") || [];\n//Keep only last X elements\nvar myArrLength = 5;\n\n//invert array so OLDEST IS FIRST, for functions\nmyEvents.reverse();\n\nif (myEvents.length >= myArrLength) {\n //remove first element (oldest event)\n myEvents.shift();\n}\n\n//add current event to end of array\nmyEvents.push(msg.payload);\n\n\n//invert array so NEWEST IS FIRST, for display\nmyEvents.reverse();\n\nflow.set(\"events_recent_radar\", myEvents);\n\nmsg.payload = myEvents;\n\nreturn msg;",
+ "outputs": 1,
+ "timeout": 0,
+ "noerr": 0,
+ "initialize": "// Code added here will be run once\n// whenever the node is started.\n\nif (flow.get(\"events_recent_radar\") === undefined) {\n flow.set(\"events_recent_radar\", [])\n}\n",
+ "finalize": "",
+ "libs": [],
+ "x": 760,
+ "y": 1900,
+ "wires": [
+ [
+ "c36c71706e494b5e",
+ "3214e8cd3ea79630"
+ ]
+ ]
+ },
+ {
+ "id": "5ec2d3ba52f944f5",
+ "type": "switch",
+ "z": "28627559bebdc324",
+ "g": "9b9e4fc50b744fc3",
+ "name": "only use radar cam",
+ "property": "payload.camera",
+ "propertyType": "msg",
+ "rules": [
+ {
+ "t": "eq",
+ "v": "VAR_RADAR_CAMERA",
+ "vt": "env"
+ }
+ ],
+ "checkall": "true",
+ "repair": false,
+ "outputs": 1,
+ "x": 340,
+ "y": 1620,
+ "wires": [
+ [
+ "2e680914d7da5c94"
+ ]
+ ]
+ },
+ {
+ "id": "c36c71706e494b5e",
+ "type": "ui_template",
+ "z": "28627559bebdc324",
+ "g": "9b9e4fc50b744fc3",
+ "group": "7866c2aa313ab8b9",
+ "name": "last N radar events",
+ "order": 2,
+ "width": 0,
+ "height": 0,
+ "format": "
last N zone_radar events for radar_camera
\n\n \n  | \n \n id: {{payload.id}} \n label: {{payload.label}} \n top_score: {{payload.top_score}} \n frame_time: {{payload.frame_time_datestring}} \n direction: {{payload.direction_calc}} \n speed: {{payload.speed_calc}}\n | \n
\n
",
+ "storeOutMessages": true,
+ "fwdInMessages": true,
+ "resendOnRefresh": true,
+ "templateScope": "local",
+ "className": "",
+ "x": 1060,
+ "y": 1900,
+ "wires": [
+ []
+ ]
+ },
+ {
+ "id": "82bc0c11adb825f8",
+ "type": "debug",
+ "z": "28627559bebdc324",
+ "g": "9b9e4fc50b744fc3",
+ "name": "debug: event payload in",
+ "active": true,
+ "tosidebar": true,
+ "console": false,
+ "tostatus": false,
+ "complete": "payload",
+ "targetType": "msg",
+ "statusVal": "",
+ "statusType": "auto",
+ "x": 360,
+ "y": 1580,
+ "wires": []
+ },
+ {
+ "id": "4abe0507c83f87a2",
+ "type": "catch",
+ "z": "28627559bebdc324",
+ "name": "",
+ "scope": null,
+ "uncaught": false,
+ "x": 80,
+ "y": 40,
+ "wires": [
+ [
+ "a309589b69eb07e1"
+ ]
+ ]
+ },
+ {
+ "id": "a309589b69eb07e1",
+ "type": "debug",
+ "z": "28627559bebdc324",
+ "name": "catch: all - dashboard",
+ "active": true,
+ "tosidebar": true,
+ "console": false,
+ "tostatus": false,
+ "complete": "true",
+ "targetType": "full",
+ "statusVal": "",
+ "statusType": "auto",
+ "x": 270,
+ "y": 40,
+ "wires": []
+ },
+ {
+ "id": "02469f2425072f7b",
+ "type": "ui_chart",
+ "z": "28627559bebdc324",
+ "g": "5173f4b3ac03407a",
+ "name": "",
+ "group": "06dde4be9a9a6b27",
+ "order": 2,
+ "width": 0,
+ "height": 0,
+ "label": "events by object (60-min) for last 24-hours",
+ "chartType": "line",
+ "legend": "true",
+ "xformat": "HH:mm:ss",
+ "interpolate": "linear",
+ "nodata": "",
+ "dot": true,
+ "ymin": "",
+ "ymax": "",
+ "removeOlder": "24",
+ "removeOlderPoints": "",
+ "removeOlderUnit": "3600",
+ "cutout": 0,
+ "useOneColor": false,
+ "useUTC": false,
+ "colors": [
+ "#1f77b4",
+ "#aec7e8",
+ "#ff7f0e",
+ "#2ca02c",
+ "#98df8a",
+ "#d62728",
+ "#ff9896",
+ "#9467bd",
+ "#c5b0d5"
+ ],
+ "outputs": 1,
+ "useDifferentColor": false,
+ "className": "",
+ "x": 880,
+ "y": 740,
+ "wires": [
+ []
+ ]
+ },
+ {
+ "id": "15797ab24727f84d",
+ "type": "inject",
+ "z": "28627559bebdc324",
+ "g": "76417db2b472ef4f",
+ "name": "trigger Event query every 5-min",
+ "props": [
+ {
+ "p": "payload"
+ },
+ {
+ "p": "topic",
+ "vt": "str"
+ }
+ ],
+ "repeat": "300",
+ "crontab": "",
+ "once": true,
+ "onceDelay": "1",
+ "topic": "query",
+ "payload": "",
+ "payloadType": "date",
+ "x": 200,
+ "y": 880,
+ "wires": [
+ [
+ "158e6edae533bfdc",
+ "79900a566af02159"
+ ]
+ ]
+ },
+ {
+ "id": "736d1e21a49f446b",
+ "type": "function",
+ "z": "28627559bebdc324",
+ "g": "9b9e4fc50b744fc3",
+ "name": "store last N any frigate events",
+ "func": "//events_recent_radar should show the last N events where payload.entered_zones CONTAINS zone_radar\n\nvar myEvents = flow.get(\"events_all\") || [];\n//Keep only last X elements\nvar myArrLength = 10;\n\n//invert array so OLDEST IS FIRST, for functions\nmyEvents.reverse();\n\nif (myEvents.length >= myArrLength) {\n //remove first element (oldest event)\n myEvents.shift();\n}\n\n//keep only specific elements\nconst newObj = {\n id: msg.payload.id, \n label: msg.payload.label, \n direction_calc: msg.payload.direction_calc, \n speed_calc: msg.payload.speed_calc, \n };\n\n//add current event to end of array\nmyEvents.push(newObj);\n\n//invert array so NEWEST IS FIRST, for display\nmyEvents.reverse();\n\nflow.set(\"events_all\", myEvents);\n\nmsg.payload = myEvents;\n\nreturn msg;",
+ "outputs": 1,
+ "timeout": 0,
+ "noerr": 0,
+ "initialize": "// Code added here will be run once\n// whenever the node is started.\n\nif (flow.get(\"events_recent_radar\") === undefined) {\n flow.set(\"events_recent_radar\", [])\n}\n",
+ "finalize": "",
+ "libs": [],
+ "x": 400,
+ "y": 2040,
+ "wires": [
+ [
+ "5b307e65106f3540"
+ ]
+ ]
+ },
+ {
+ "id": "5b307e65106f3540",
+ "type": "ui_text",
+ "z": "28627559bebdc324",
+ "g": "9b9e4fc50b744fc3",
+ "group": "7866c2aa313ab8b9",
+ "order": 4,
+ "width": 12,
+ "height": 5,
+ "name": "",
+ "label": "last N events, text output",
+ "format": "{{msg.payload}}",
+ "layout": "row-spread",
+ "className": "",
+ "style": true,
+ "font": "Courier,monospace",
+ "fontSize": "10",
+ "color": "#000000",
+ "x": 1070,
+ "y": 2040,
+ "wires": []
+ },
+ {
+ "id": "4c087723a1d698e9",
+ "type": "ui_template",
"z": "28627559bebdc324",
- "g": "5173f4b3ac03407a",
- "name": "trigger Event query every 60-min",
- "props": [
- {
- "p": "payload"
- },
- {
- "p": "topic",
- "vt": "str"
- }
- ],
- "repeat": "3600",
- "crontab": "",
- "once": true,
- "onceDelay": "2",
- "topic": "query",
- "payload": "",
- "payloadType": "date",
- "x": 200,
- "y": 600,
+ "g": "9b9e4fc50b744fc3",
+ "group": "7866c2aa313ab8b9",
+ "name": "last N radar speeding events",
+ "order": 3,
+ "width": 0,
+ "height": 0,
+ "format": "last N zone_radar speeding events for radar_camera (>20-mph)
\n\n \n  | \n \n id: {{payload.id}} \n label: {{payload.label}} \n top_score: {{payload.top_score}} \n frame_time: {{payload.frame_time_datestring}} \n direction: {{payload.direction_calc}} \n speed: {{payload.speed_calc}}\n | \n
\n
",
+ "storeOutMessages": true,
+ "fwdInMessages": true,
+ "resendOnRefresh": true,
+ "templateScope": "local",
+ "className": "",
+ "x": 1090,
+ "y": 1980,
"wires": [
- [
- "928b71f25ce6e7b6"
- ]
+ []
]
},
{
- "id": "08d030ffc3fe6adb",
+ "id": "11fa2826769befc7",
"type": "ui_chart",
"z": "28627559bebdc324",
- "g": "5aac1262472b0205",
- "name": "frigate summary daily, objects",
+ "g": "0e1614cf2e5f9942",
+ "name": "",
"group": "06dde4be9a9a6b27",
- "order": 3,
- "width": 6,
- "height": 7,
- "label": "frigate api/events/summary daily object count for the last 10-days",
+ "order": 7,
+ "width": 0,
+ "height": 0,
+ "label": "Events in zone_radar (5-min) for last 60-min",
"chartType": "line",
"legend": "true",
- "xformat": "Y-M-D",
+ "xformat": "HH:mm",
"interpolate": "linear",
"nodata": "",
- "dot": true,
+ "dot": false,
"ymin": "",
"ymax": "",
- "removeOlder": "10",
- "removeOlderPoints": "10000",
- "removeOlderUnit": "86400",
+ "removeOlder": "60",
+ "removeOlderPoints": "",
+ "removeOlderUnit": "60",
"cutout": 0,
"useOneColor": false,
"useUTC": false,
@@ -2172,85 +3163,104 @@
"outputs": 1,
"useDifferentColor": false,
"className": "",
- "x": 710,
- "y": 240,
+ "x": 970,
+ "y": 1280,
"wires": [
[]
]
},
{
- "id": "b241a0ef89fd7ce4",
- "type": "http request",
+ "id": "6d738ed81fefbedc",
+ "type": "ui_chart",
"z": "28627559bebdc324",
- "g": "5aac1262472b0205",
- "name": "frigate api/events/summary - Daily summary",
- "method": "GET",
- "ret": "obj",
- "paytoqs": "ignore",
- "url": "http://frigate:5000/api/events/summary",
- "tls": "",
- "persist": false,
- "proxy": "",
- "insecureHTTPParser": false,
- "authType": "",
- "senderr": false,
- "headers": [],
- "x": 310,
- "y": 180,
- "wires": [
- [
- "eb140f61419c6a08"
- ]
+ "g": "453513c49e4b1b60",
+ "name": "",
+ "group": "7866c2aa313ab8b9",
+ "order": 1,
+ "width": 0,
+ "height": 0,
+ "label": "cumulative events by object since 0400",
+ "chartType": "horizontalBar",
+ "legend": "true",
+ "xformat": "HH:mm:ss",
+ "interpolate": "linear",
+ "nodata": "",
+ "dot": false,
+ "ymin": "",
+ "ymax": "",
+ "removeOlder": 1,
+ "removeOlderPoints": "",
+ "removeOlderUnit": "3600",
+ "cutout": 0,
+ "useOneColor": false,
+ "useUTC": false,
+ "colors": [
+ "#1f77b4",
+ "#aec7e8",
+ "#ff7f0e",
+ "#2ca02c",
+ "#98df8a",
+ "#d62728",
+ "#ff9896",
+ "#9467bd",
+ "#c5b0d5"
],
- "info": "`{\"camera\":\"picam_gs_h264\",\n\"count\":83,\"day\":\"2024-03-21\",\n\"label\":\"bicycle\",\n\"sub_label\":null,\n\"zones\":[]}`"
+ "outputs": 1,
+ "useDifferentColor": false,
+ "className": "",
+ "x": 1140,
+ "y": 2380,
+ "wires": [
+ []
+ ]
},
{
- "id": "91d3f8965f62f4b0",
- "type": "inject",
+ "id": "d856c68660eb2202",
+ "type": "mqtt out",
"z": "28627559bebdc324",
- "g": "5aac1262472b0205",
- "name": "trigger summary Event query every 2-hours",
- "props": [],
- "repeat": "7200",
- "crontab": "",
- "once": true,
- "onceDelay": "5",
- "topic": "",
- "x": 230,
- "y": 120,
- "wires": [
- [
- "b241a0ef89fd7ce4"
- ]
- ]
+ "g": "453513c49e4b1b60",
+ "name": "",
+ "topic": "tm/events",
+ "qos": "1",
+ "retain": "true",
+ "respTopic": "",
+ "contentType": "",
+ "userProps": "",
+ "correl": "",
+ "expiry": "",
+ "broker": "a5d65dd0e3566daa",
+ "x": 1040,
+ "y": 2420,
+ "wires": []
},
{
- "id": "eb140f61419c6a08",
+ "id": "0f65ceafe3f7c069",
"type": "function",
"z": "28627559bebdc324",
- "g": "5aac1262472b0205",
- "name": "structure frigate api/summary",
- "func": "var newMsg = [{}];\nnewMsg[0].series = [];\nnewMsg[0].data = [];\nnewMsg[0].label = [];\n\nmsg.payload.forEach((myItem) => {\n\n //only do this for the radar camera and 10 days or less ago\n if (myItem.camera == env.get(\"VAR_RADAR_CAMERA\") && new Date(myItem.day).getTime() >= Math.floor((Date.now() - 86400000 * 10))) {\n //if label doesn't exist, push it\n if (newMsg[0].series.indexOf(myItem.label) < 0) {\n newMsg[0].series.push(myItem.label);\n //create new data array element that matches the series index\n newMsg[0].data[newMsg[0].series.indexOf(myItem.label)] = [];\n }\n\n //Check if it's a new date or existing in data[0][0].x\n //datapoint for date \n let xIndex = newMsg[0].data[newMsg[0].series.indexOf(myItem.label)].findIndex((element) => element.x == String(new Date(myItem.day)));\n if (xIndex < 0) {\n //new date\n let thisDataPoint = {};\n thisDataPoint.x = new Date(myItem.day);\n thisDataPoint.y = myItem.count;\n newMsg[0].data[newMsg[0].series.indexOf(myItem.label)].push(thisDataPoint);\n }\n else {\n //date exists, sum counts\n newMsg[0].data[newMsg[0].series.indexOf(myItem.label)][xIndex].y += myItem.count;\n }\n\n };\n \n});\n\nmsg.payload = newMsg;\n\nreturn msg;",
+ "g": "9b9e4fc50b744fc3",
+ "name": "format last N radar event for output",
+ "func": "\n\nconst newMsg = {};\nnewMsg.payload = {}; // contain everything going into a DB record, single record\n\nnewMsg.payload.id = msg.frigate_event.id;\nnewMsg.payload.camera = msg.frigate_event.camera;\nnewMsg.payload.label = msg.frigate_event.label;\nnewMsg.payload.sub_label = msg.frigate_event.sub_label;\nnewMsg.payload.top_score = msg.frigate_event.top_score;\n\nnewMsg.payload.frame_time_datestring = new Date(msg.frigate_event.frame_time * 1000).toLocaleString();\nnewMsg.payload.frame_time = msg.frigate_event.frame_time;\nnewMsg.payload.start_time = msg.frigate_event.start_time;\nnewMsg.payload.end_time = msg.frigate_event.end_time;\n\nnewMsg.payload.entered_zones = msg.frigate_event.entered_zones; //array\nnewMsg.payload.direction_calc = msg.frigate_event.direction_calc;\nnewMsg.payload.speed_calc = msg.frigate_event.speed_calc;\n\nnewMsg.payload.thumbnail_base64jpg = msg.frigate_event_api_thumbnail;\n\nnewMsg.payload.location = msg.frigate_event.location;\n\nreturn newMsg;\n\n\nreturn msg;",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
- "x": 400,
- "y": 240,
+ "x": 470,
+ "y": 1900,
"wires": [
[
- "08d030ffc3fe6adb"
+ "e5391514131a2b5a",
+ "d66541089b01306e"
]
]
},
{
- "id": "404ac097795a2da0",
+ "id": "c90aed37b7a31d9e",
"type": "inject",
"z": "28627559bebdc324",
- "g": "0a6e123f5e53c029",
- "name": "trigger Event query every 2-hours",
+ "g": "1bd1f21fa0390c69",
+ "name": "trigger Event query every 5-min",
"props": [
{
"p": "payload"
@@ -2260,1014 +3270,834 @@
"vt": "str"
}
],
- "repeat": "7200",
+ "repeat": "300",
"crontab": "",
"once": true,
- "onceDelay": "5",
+ "onceDelay": "1",
"topic": "query",
- "payload": "",
- "payloadType": "date",
- "x": 200,
- "y": 360,
- "wires": [
- [
- "5f3716d2176c3ab4"
- ]
- ]
- },
- {
- "id": "b65e1877b1e04881",
- "type": "ui_chart",
- "z": "28627559bebdc324",
- "g": "0a6e123f5e53c029",
- "name": "events summary daily, objects",
- "group": "06dde4be9a9a6b27",
- "order": 4,
- "width": 6,
- "height": 7,
- "label": "events daily object count for the last 10-days",
- "chartType": "line",
- "legend": "true",
- "xformat": "Y-M-D",
- "interpolate": "linear",
- "nodata": "",
- "dot": true,
- "ymin": "",
- "ymax": "",
- "removeOlder": "10",
- "removeOlderPoints": "10000",
- "removeOlderUnit": "86400",
- "cutout": 0,
- "useOneColor": false,
- "useUTC": false,
- "colors": [
- "#1f77b4",
- "#aec7e8",
- "#ff7f0e",
- "#2ca02c",
- "#98df8a",
- "#d62728",
- "#ff9896",
- "#9467bd",
- "#c5b0d5"
- ],
- "outputs": 1,
- "useDifferentColor": false,
- "className": "",
- "x": 710,
- "y": 480,
- "wires": [
- []
- ]
- },
- {
- "id": "c249329109ac17d5",
- "type": "link in",
- "z": "28627559bebdc324",
- "name": "from mongo event capture",
- "links": [
- "d9a2cc1e81161549",
- "274f87c31437c2d7"
- ],
- "x": 165,
- "y": 1580,
+ "payload": "",
+ "payloadType": "date",
+ "x": 240,
+ "y": 2560,
"wires": [
[
- "5ec2d3ba52f944f5",
- "82bc0c11adb825f8",
- "736d1e21a49f446b",
- "f57e08e6fb9c0d09"
+ "584504e6c8935eaf"
]
]
},
{
- "id": "d66541089b01306e",
- "type": "switch",
+ "id": "5417aae0d14fa661",
+ "type": "ui_template",
"z": "28627559bebdc324",
- "g": "9b9e4fc50b744fc3",
- "name": "only event with speed",
- "property": "$abs(payload.speed_calc)",
- "propertyType": "jsonata",
- "rules": [
- {
- "t": "gt",
- "v": "20",
- "vt": "num"
- }
- ],
- "checkall": "true",
- "repair": false,
- "outputs": 1,
- "x": 750,
- "y": 1940,
+ "g": "1bd1f21fa0390c69",
+ "group": "06dde4be9a9a6b27",
+ "name": "car speed stats for today, since 0400",
+ "order": 1,
+ "width": 0,
+ "height": 0,
+ "format": "car speed stats for today, since 0400
\n\n \n {{key}}: | \n {{value}} | \n
\n
",
+ "storeOutMessages": true,
+ "fwdInMessages": true,
+ "resendOnRefresh": true,
+ "templateScope": "local",
+ "className": "",
+ "x": 1130,
+ "y": 2720,
"wires": [
- [
- "c788d632f5e93a73"
- ]
+ []
]
},
{
- "id": "2e680914d7da5c94",
+ "id": "f57e08e6fb9c0d09",
"type": "switch",
"z": "28627559bebdc324",
- "g": "9b9e4fc50b744fc3",
- "name": "only zone_radar",
+ "g": "453513c49e4b1b60",
+ "name": "only for zone_capture",
"property": "payload.entered_zones",
"propertyType": "msg",
"rules": [
{
"t": "cont",
- "v": "zone_radar",
+ "v": "zone_capture",
"vt": "str"
}
],
"checkall": "true",
"repair": false,
"outputs": 1,
- "x": 390,
- "y": 1660,
+ "x": 400,
+ "y": 2180,
"wires": [
[
- "c2270f3050bf35ab"
+ "d23be15251ed6d73"
]
]
},
{
- "id": "c788d632f5e93a73",
- "type": "function",
+ "id": "d23be15251ed6d73",
+ "type": "change",
"z": "28627559bebdc324",
- "g": "9b9e4fc50b744fc3",
- "name": "store last N speed events",
- "func": "//events_recent_radar should show the last N events where payload.entered_zones CONTAINS zone_radar\n\nvar myEvents = flow.get(\"events_recent_speed\") || [];\n//Keep only last X elements\nvar myArrLength = 3;\n\n//invert array so OLDEST IS FIRST, for functions\nmyEvents.reverse();\n\nif (myEvents.length >= myArrLength) {\n //remove first element (oldest event)\n myEvents.shift();\n}\n\n//add current event to end of array\nmyEvents.push(msg.payload);\n\n//invert array so NEWEST IS FIRST, for display\nmyEvents.reverse();\n\nflow.set(\"events_recent_speed\", myEvents);\n\nmsg.payload = myEvents;\n\nreturn msg;",
- "outputs": 1,
- "timeout": 0,
- "noerr": 0,
- "initialize": "// Code added here will be run once\n// whenever the node is started.\n\nif (flow.get(\"events_recent_radar\") === undefined) {\n flow.set(\"events_recent_radar\", [])\n}\n",
- "finalize": "",
- "libs": [],
- "x": 800,
- "y": 1980,
+ "g": "453513c49e4b1b60",
+ "name": "set flow.event_latest",
+ "rules": [
+ {
+ "t": "set",
+ "p": "event_latest",
+ "pt": "flow",
+ "to": "payload.label",
+ "tot": "msg"
+ }
+ ],
+ "action": "",
+ "property": "",
+ "from": "",
+ "to": "",
+ "reg": false,
+ "x": 460,
+ "y": 2240,
"wires": [
[
- "4c087723a1d698e9"
+ "170ddffb726db9e0"
]
]
},
{
- "id": "e5391514131a2b5a",
- "type": "function",
+ "id": "4760bed60a7f392a",
+ "type": "inject",
"z": "28627559bebdc324",
- "g": "9b9e4fc50b744fc3",
- "name": "store last N radar events",
- "func": "//events_recent_radar should show the last N events where payload.entered_zones CONTAINS zone_radar\n\nvar myEvents = flow.get(\"events_recent_radar\") || [];\n//Keep only last X elements\nvar myArrLength = 5;\n\n//invert array so OLDEST IS FIRST, for functions\nmyEvents.reverse();\n\nif (myEvents.length >= myArrLength) {\n //remove first element (oldest event)\n myEvents.shift();\n}\n\n//add current event to end of array\nmyEvents.push(msg.payload);\n\n\n//invert array so NEWEST IS FIRST, for display\nmyEvents.reverse();\n\nflow.set(\"events_recent_radar\", myEvents);\n\nmsg.payload = myEvents;\n\nreturn msg;",
- "outputs": 1,
- "timeout": 0,
- "noerr": 0,
- "initialize": "// Code added here will be run once\n// whenever the node is started.\n\nif (flow.get(\"events_recent_radar\") === undefined) {\n flow.set(\"events_recent_radar\", [])\n}\n",
- "finalize": "",
- "libs": [],
- "x": 760,
- "y": 1900,
+ "g": "453513c49e4b1b60",
+ "name": "",
+ "props": [],
+ "repeat": "",
+ "crontab": "",
+ "once": false,
+ "onceDelay": 0.1,
+ "topic": "",
+ "x": 250,
+ "y": 2280,
"wires": [
[
- "c36c71706e494b5e",
- "3214e8cd3ea79630"
+ "170ddffb726db9e0"
]
]
},
{
- "id": "5ec2d3ba52f944f5",
- "type": "switch",
+ "id": "09f99c931e5535bf",
+ "type": "http request",
"z": "28627559bebdc324",
- "g": "9b9e4fc50b744fc3",
- "name": "only use radar cam",
- "property": "payload.camera",
- "propertyType": "msg",
- "rules": [
- {
- "t": "eq",
- "v": "VAR_RADAR_CAMERA",
- "vt": "env"
- }
- ],
- "checkall": "true",
- "repair": false,
- "outputs": 1,
- "x": 340,
- "y": 1620,
+ "g": "f5d2d92d50d18ce2",
+ "name": "frigate http api for thumbnail",
+ "method": "GET",
+ "ret": "bin",
+ "paytoqs": "ignore",
+ "url": "http://frigate:5000//api/events/{{{frigate_event.id}}}/thumbnail.jpg",
+ "tls": "",
+ "persist": false,
+ "proxy": "",
+ "insecureHTTPParser": false,
+ "authType": "",
+ "senderr": false,
+ "headers": [],
+ "x": 450,
+ "y": 1780,
"wires": [
[
- "2e680914d7da5c94"
+ "9226865e3385eb56",
+ "aa0afb5180297e2b"
]
]
},
{
- "id": "c36c71706e494b5e",
- "type": "ui_template",
- "z": "28627559bebdc324",
- "g": "9b9e4fc50b744fc3",
- "group": "7866c2aa313ab8b9",
- "name": "last N radar events",
- "order": 2,
- "width": 0,
- "height": 0,
- "format": "last N zone_radar events for radar_camera
\n\n \n  | \n \n id: {{payload.id}} \n label: {{payload.label}} \n top_score: {{payload.top_score}} \n frame_time: {{payload.frame_time_datestring}} \n direction: {{payload.direction_calc}} \n speed: {{payload.speed_calc}}\n | \n
\n
",
- "storeOutMessages": true,
- "fwdInMessages": true,
- "resendOnRefresh": true,
- "templateScope": "local",
- "className": "",
- "x": 1060,
- "y": 1900,
- "wires": [
- []
- ]
- },
- {
- "id": "82bc0c11adb825f8",
- "type": "debug",
- "z": "28627559bebdc324",
- "g": "9b9e4fc50b744fc3",
- "name": "debug: event payload in",
- "active": true,
- "tosidebar": true,
- "console": false,
- "tostatus": false,
- "complete": "payload",
- "targetType": "msg",
- "statusVal": "",
- "statusType": "auto",
- "x": 360,
- "y": 1580,
- "wires": []
- },
- {
- "id": "4abe0507c83f87a2",
- "type": "catch",
+ "id": "08121a31488784bc",
+ "type": "change",
"z": "28627559bebdc324",
- "name": "",
- "scope": null,
- "uncaught": false,
- "x": 80,
- "y": 40,
+ "g": "f5d2d92d50d18ce2",
+ "name": "set frigate_event_api_thumbnail",
+ "rules": [
+ {
+ "t": "set",
+ "p": "frigate_event_api_thumbnail",
+ "pt": "msg",
+ "to": "payload",
+ "tot": "msg"
+ }
+ ],
+ "action": "",
+ "property": "",
+ "from": "",
+ "to": "",
+ "reg": false,
+ "x": 760,
+ "y": 1820,
"wires": [
[
- "a309589b69eb07e1"
+ "0f65ceafe3f7c069"
]
]
},
{
- "id": "a309589b69eb07e1",
- "type": "debug",
+ "id": "9226865e3385eb56",
+ "type": "image",
"z": "28627559bebdc324",
- "name": "catch: all - dashboard",
- "active": true,
- "tosidebar": true,
- "console": false,
- "tostatus": false,
- "complete": "true",
- "targetType": "full",
- "statusVal": "",
- "statusType": "auto",
- "x": 270,
- "y": 40,
+ "g": "f5d2d92d50d18ce2",
+ "name": "",
+ "width": "175",
+ "data": "payload",
+ "dataType": "msg",
+ "thumbnail": false,
+ "active": false,
+ "pass": false,
+ "outputs": 0,
+ "x": 710,
+ "y": 1780,
"wires": []
},
{
- "id": "02469f2425072f7b",
- "type": "ui_chart",
+ "id": "aa0afb5180297e2b",
+ "type": "base64",
"z": "28627559bebdc324",
- "g": "5173f4b3ac03407a",
+ "g": "f5d2d92d50d18ce2",
"name": "",
- "group": "06dde4be9a9a6b27",
- "order": 2,
- "width": 0,
- "height": 0,
- "label": "events by object (60-min) for last 24-hours",
- "chartType": "line",
- "legend": "true",
- "xformat": "HH:mm:ss",
- "interpolate": "linear",
- "nodata": "",
- "dot": true,
- "ymin": "",
- "ymax": "",
- "removeOlder": "24",
- "removeOlderPoints": "",
- "removeOlderUnit": "3600",
- "cutout": 0,
- "useOneColor": false,
- "useUTC": false,
- "colors": [
- "#1f77b4",
- "#aec7e8",
- "#ff7f0e",
- "#2ca02c",
- "#98df8a",
- "#d62728",
- "#ff9896",
- "#9467bd",
- "#c5b0d5"
- ],
- "outputs": 1,
- "useDifferentColor": false,
- "className": "",
- "x": 880,
- "y": 740,
+ "action": "",
+ "property": "payload",
+ "x": 550,
+ "y": 1820,
"wires": [
- []
+ [
+ "08121a31488784bc"
+ ]
]
},
{
- "id": "15797ab24727f84d",
- "type": "inject",
+ "id": "c2270f3050bf35ab",
+ "type": "change",
"z": "28627559bebdc324",
- "g": "76417db2b472ef4f",
- "name": "trigger Event query every 5-min",
- "props": [
- {
- "p": "payload"
- },
+ "g": "9b9e4fc50b744fc3",
+ "name": "set frigate_event from payload",
+ "rules": [
{
- "p": "topic",
- "vt": "str"
+ "t": "set",
+ "p": "frigate_event",
+ "pt": "msg",
+ "to": "payload",
+ "tot": "msg"
}
],
- "repeat": "300",
- "crontab": "",
- "once": true,
- "onceDelay": "1",
- "topic": "query",
- "payload": "",
- "payloadType": "date",
- "x": 200,
- "y": 880,
+ "action": "",
+ "property": "",
+ "from": "",
+ "to": "",
+ "reg": false,
+ "x": 440,
+ "y": 1700,
"wires": [
[
- "6a422507b2a5bbca",
- "dd294de96fa60d7d",
- "158e6edae533bfdc"
+ "09f99c931e5535bf"
]
]
},
{
- "id": "6a422507b2a5bbca",
+ "id": "3214e8cd3ea79630",
+ "type": "debug",
+ "z": "28627559bebdc324",
+ "g": "9b9e4fc50b744fc3",
+ "name": "debug: last N radar events",
+ "active": false,
+ "tosidebar": true,
+ "console": false,
+ "tostatus": false,
+ "complete": "true",
+ "targetType": "full",
+ "statusVal": "",
+ "statusType": "auto",
+ "x": 1080,
+ "y": 1840,
+ "wires": []
+ },
+ {
+ "id": "5f3716d2176c3ab4",
"type": "function",
"z": "28627559bebdc324",
- "g": "76417db2b472ef4f",
- "name": "create influxdb query for TimedSpeedCounts.counts (5-min) for last 60-min",
- "func": "//Want TimedSpeedCounts.counts (expected every 5-min) for last 1 hour\n\nvar query = \"\";\n\nquery += \"from(bucket: \\\"\" + env.get(\"VAR_INFLUXDB_BUCKET\") +\"\\\")\\n\";\nquery += \" |> range(start: \" + Math.floor((msg.payload - (60 * 60 * 1000))/1000) +\", stop: \" + Math.ceil((msg.payload)/1000) + \")\\n\";\n// OR |> range(start:-1h)\nquery += \" |> filter(fn: (r) => r[\\\"_measurement\\\"] == \\\"TimedSpeedCounts\\\")\\n\";\nquery += \" |> filter(fn: (r) => r[\\\"_field\\\"] == \\\"count\\\")\";\nquery += \" |> filter(fn: (r) => r[\\\"direction\\\"] == \\\"inbound\\\" or r[\\\"direction\\\"] == \\\"outbound\\\")\";\nquery += \" |> filter(fn: (r) => r[\\\"location\\\"] == \\\"\" + env.get(\"VAR_LOCATION\") + \"\\\")\\n\";\nquery += \" |> filter(fn: (r) => r[\\\"speed_units\\\"] == \\\"mph\\\")\"; \nquery += \" |> filter(fn: (r) => r[\\\"speed_units\\\"] == \\\"mph\\\")\"; \nquery += \" |> sort(columns: [\\\"_time\\\"])\"; \n\n\nmsg.query = query;\nreturn msg;\n\n\n// from(bucket: \"influxdb_bucket\")\n// \t|> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n// |> filter(fn: (r) => r[\"_measurement\"] == \"TimedSpeedCounts\")\n// |> filter(fn: (r) => r[\"_field\"] == \"speed_average\" or r[\"_field\"] == \"count\")\n// |> filter(fn: (r) => r[\"direction\"] == \"inbound\" or r[\"direction\"] == \"outbound\")\n// |> filter(fn: (r) => r[\"location\"] == \"ne26th-wasco-sb-01\")\n// |> filter(fn: (r) => r[\"speed_units\"] == \"mph\")",
+ "g": "0a6e123f5e53c029",
+ "name": "create sqlite query, daily summary in zone_capture",
+ "func": "//frame_time is already in seconds\n\nconst query = `\nSELECT\n date(frame_time, 'unixepoch') as day,\n label,\n camera,\n COUNT(*) as count\nFROM\n events\nWHERE\n frame_time > (unixepoch('now') - (86400 * 10))\n AND camera = '${env.get(\"VAR_RADAR_CAMERA\")}'\n AND entered_zones LIKE '%zone_capture%'\nGROUP BY\n label, date(frame_time, 'unixepoch'), camera\nORDER BY\n label, day, camera;\n`;\n\nmsg.topic = query;\nreturn msg;",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
- "x": 320,
- "y": 940,
+ "x": 250,
+ "y": 400,
"wires": [
[
- "e256c1d68cf20f43"
+ "bdb4b259d648b1f0"
]
]
},
{
- "id": "e256c1d68cf20f43",
- "type": "influxdb in",
+ "id": "bdb4b259d648b1f0",
+ "type": "sqlite",
"z": "28627559bebdc324",
- "g": "76417db2b472ef4f",
- "influxdb": "73598328fc95017b",
- "name": "query, TimedSpeedCounts.counts",
- "query": "",
- "rawOutput": false,
- "precision": "",
- "retentionPolicy": "",
- "org": "taffic_monitor_01",
- "x": 440,
- "y": 1000,
+ "g": "0a6e123f5e53c029",
+ "mydb": "2f60c1ab30a6fc8f",
+ "sqlquery": "msg.topic",
+ "sql": "",
+ "name": "",
+ "x": 360,
+ "y": 440,
"wires": [
[
- "a432e760cc77e6cb"
+ "ec7a0e0b1c62e91d"
]
]
},
{
- "id": "dd294de96fa60d7d",
+ "id": "ec7a0e0b1c62e91d",
"type": "function",
"z": "28627559bebdc324",
- "g": "76417db2b472ef4f",
- "name": "create influxdb query for TimedSpeedCounts.speed_average (5-min) for last 60-min",
- "func": "//Want TimedSpeedCounts.speed_average (expected every 5-min) for last 1 hour\n\nvar query = \"\";\n\nquery += \"from(bucket: \\\"\" + env.get(\"VAR_INFLUXDB_BUCKET\") +\"\\\")\\n\";\nquery += \" |> range(start: \" + Math.floor((msg.payload - (60 * 60 * 1000))/1000) +\", stop: \" + Math.ceil((msg.payload)/1000) + \")\\n\";\n// OR |> range(start:-1h)\nquery += \" |> filter(fn: (r) => r[\\\"_measurement\\\"] == \\\"TimedSpeedCounts\\\")\\n\";\nquery += \" |> filter(fn: (r) => r[\\\"_field\\\"] == \\\"speed_average\\\")\";\nquery += \" |> filter(fn: (r) => r[\\\"direction\\\"] == \\\"inbound\\\" or r[\\\"direction\\\"] == \\\"outbound\\\")\";\nquery += \" |> filter(fn: (r) => r[\\\"location\\\"] == \\\"\" + env.get(\"VAR_LOCATION\") + \"\\\")\\n\";\nquery += \" |> filter(fn: (r) => r[\\\"speed_units\\\"] == \\\"mph\\\")\"; \nquery += \" |> sort(columns: [\\\"_time\\\"])\"; \n\nmsg.query = query;\nreturn msg;\n\n\n// from(bucket: \"influxdb_bucket\")\n// \t|> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n// |> filter(fn: (r) => r[\"_measurement\"] == \"TimedSpeedCounts\")\n// |> filter(fn: (r) => r[\"_field\"] == \"speed_average\" or r[\"_field\"] == \"count\")\n// |> filter(fn: (r) => r[\"direction\"] == \"inbound\" or r[\"direction\"] == \"outbound\")\n// |> filter(fn: (r) => r[\"location\"] == \"ne26th-wasco-sb-01\")\n// |> filter(fn: (r) => r[\"speed_units\"] == \"mph\")",
+ "g": "0a6e123f5e53c029",
+ "name": "structure daily summary payload",
+ "func": "//https://github.com/node-red/node-red-dashboard/blob/master/Charts.md\n//Array of Object with keys of series, data=x:ts,y:count, labels\n\nvar newMsg = [{}];\nnewMsg[0].series = [];\nnewMsg[0].data = [];\nnewMsg[0].label = [];\n\nmsg.payload.forEach((myItem) => {\n\n //if label doesn't exist, push it\n if (newMsg[0].series.indexOf(myItem.label) < 0) {\n newMsg[0].series.push(myItem.label);\n //create new data array element that matches the series index\n newMsg[0].data[newMsg[0].series.indexOf(myItem.label)] = [];\n }\n\n //Check if it's a new date or existing in data[0][0].x\n //datapoint for date \n let xIndex = newMsg[0].data[newMsg[0].series.indexOf(myItem.label)].findIndex((element) => element.x == String(new Date(myItem.day)));\n if (xIndex < 0) {\n //new date\n let thisDataPoint = {};\n thisDataPoint.x = new Date(myItem.day);\n thisDataPoint.y = myItem.count;\n newMsg[0].data[newMsg[0].series.indexOf(myItem.label)].push(thisDataPoint);\n }\n else {\n //date exists, sum counts\n newMsg[0].data[newMsg[0].series.indexOf(myItem.label)][xIndex].y += myItem.count;\n }\n\n});\n\nmsg.payload = newMsg;\n\nreturn msg;",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
- "x": 350,
- "y": 1120,
+ "x": 330,
+ "y": 480,
"wires": [
[
- "319859b48b6eebad"
+ "b65e1877b1e04881"
]
]
},
{
- "id": "319859b48b6eebad",
- "type": "influxdb in",
+ "id": "928b71f25ce6e7b6",
+ "type": "function",
"z": "28627559bebdc324",
- "g": "76417db2b472ef4f",
- "influxdb": "73598328fc95017b",
- "name": "query, TimedSpeedCounts.speed_average",
- "query": "",
- "rawOutput": false,
- "precision": "",
- "retentionPolicy": "",
- "org": "taffic_monitor_01",
- "x": 470,
- "y": 1180,
+ "g": "5173f4b3ac03407a",
+ "name": "create sqlite query, 1-hour counts last day in zone_capture",
+ "func": "//frame_time is already in seconds\n\nconst query = `\nSELECT\n strftime('%FT%H:00:00.000Z', frame_time, 'unixepoch') as hour,\n label,\n camera,\n COUNT(*) as count\nFROM\n events\nWHERE\n frame_time > (unixepoch('now') - (86400 * 1))\n AND camera = '${env.get(\"VAR_RADAR_CAMERA\")}'\n AND entered_zones LIKE '%zone_capture%'\nGROUP BY\n label, strftime('%F %H', frame_time, 'unixepoch'), camera\nORDER BY\n label, hour, camera;\n`;\n\nmsg.topic = query;\nreturn msg;",
+ "outputs": 1,
+ "timeout": 0,
+ "noerr": 0,
+ "initialize": "",
+ "finalize": "",
+ "libs": [],
+ "x": 290,
+ "y": 660,
"wires": [
[
- "b2b5e83db3663f9e"
+ "c03516d1eb65598d"
]
]
},
{
- "id": "1b7c2967fd6a85a4",
- "type": "ui_chart",
+ "id": "c03516d1eb65598d",
+ "type": "sqlite",
"z": "28627559bebdc324",
- "g": "76417db2b472ef4f",
+ "g": "5173f4b3ac03407a",
+ "mydb": "2f60c1ab30a6fc8f",
+ "sqlquery": "msg.topic",
+ "sql": "",
"name": "",
- "group": "06dde4be9a9a6b27",
- "order": 6,
- "width": 0,
- "height": 0,
- "label": "TimedSpeedCounts.speed_average (5-min) for last 60-min",
- "chartType": "line",
- "legend": "true",
- "xformat": "HH:mm",
- "interpolate": "linear",
- "nodata": "",
- "dot": false,
- "ymin": "",
- "ymax": "",
- "removeOlder": "60",
- "removeOlderPoints": "",
- "removeOlderUnit": "60",
- "cutout": 0,
- "useOneColor": false,
- "useUTC": false,
- "colors": [
- "#1f77b4",
- "#aec7e8",
- "#ff7f0e",
- "#2ca02c",
- "#98df8a",
- "#d62728",
- "#ff9896",
- "#9467bd",
- "#c5b0d5"
- ],
- "outputs": 1,
- "useDifferentColor": false,
- "className": "",
- "x": 1000,
- "y": 1240,
+ "x": 420,
+ "y": 700,
"wires": [
- []
+ [
+ "4f84bcb60e4be762"
+ ]
]
},
{
- "id": "537d771bb5b1eff5",
- "type": "ui_chart",
+ "id": "4f84bcb60e4be762",
+ "type": "function",
"z": "28627559bebdc324",
- "g": "76417db2b472ef4f",
- "name": "",
- "group": "06dde4be9a9a6b27",
- "order": 5,
- "width": 0,
- "height": 0,
- "label": "TimedSpeedCounts.counts (5-min) for last 60-min",
- "chartType": "line",
- "legend": "true",
- "xformat": "HH:mm",
- "interpolate": "linear",
- "nodata": "",
- "dot": false,
- "ymin": "",
- "ymax": "",
- "removeOlder": "60",
- "removeOlderPoints": "",
- "removeOlderUnit": "60",
- "cutout": 0,
- "useOneColor": false,
- "useUTC": false,
- "colors": [
- "#1f77b4",
- "#aec7e8",
- "#ff7f0e",
- "#2ca02c",
- "#98df8a",
- "#d62728",
- "#ff9896",
- "#9467bd",
- "#c5b0d5"
- ],
+ "g": "5173f4b3ac03407a",
+ "name": "structure 1-hour counts last day",
+ "func": "//https://github.com/node-red/node-red-dashboard/blob/master/Charts.md\n//Array of Object with keys of series, data=x:ts,y:count, labels\n\nvar newMsg = [{}];\nnewMsg[0].series = [];\nnewMsg[0].data = [];\nnewMsg[0].label = [];\n\nmsg.payload.forEach((myItem) => {\n\n //if label doesn't exist, push it\n if (newMsg[0].series.indexOf(myItem.label) < 0) {\n newMsg[0].series.push(myItem.label);\n //create new data array element that matches the series index\n newMsg[0].data[newMsg[0].series.indexOf(myItem.label)] = [];\n }\n\n //Check if it's a new date or existing in data[0][0].x\n //datapoint for date \n let xIndex = newMsg[0].data[newMsg[0].series.indexOf(myItem.label)].findIndex((element) => element.x == String(new Date(myItem.hour)));\n if (xIndex < 0) {\n //new date\n let thisDataPoint = {};\n thisDataPoint.x = new Date(myItem.hour);\n thisDataPoint.y = myItem.count;\n newMsg[0].data[newMsg[0].series.indexOf(myItem.label)].push(thisDataPoint);\n }\n else {\n //date exists, sum counts\n newMsg[0].data[newMsg[0].series.indexOf(myItem.label)][xIndex].y += myItem.count;\n }\n\n});\n\nmsg.payload = newMsg;\n\nreturn msg;",
"outputs": 1,
- "useDifferentColor": false,
- "className": "",
- "x": 970,
- "y": 1060,
+ "timeout": 0,
+ "noerr": 0,
+ "initialize": "",
+ "finalize": "",
+ "libs": [],
+ "x": 410,
+ "y": 740,
"wires": [
- []
+ [
+ "02469f2425072f7b"
+ ]
]
},
{
- "id": "b2b5e83db3663f9e",
+ "id": "158e6edae533bfdc",
"type": "function",
"z": "28627559bebdc324",
- "g": "76417db2b472ef4f",
- "name": "structure influx TimedSpeedCounts.speed_average",
- "func": "//https://github.com/node-red/node-red-dashboard/blob/master/Charts.md\n//Array of Object with keys of series, data=x:ts,y:count, directions\n\nvar newMsg = [{}];\nnewMsg[0].series = [];\nnewMsg[0].data = [];\nnewMsg[0].direction = [];\n\n// _time\n// _value\n// direction\n\n\nmsg.payload.forEach((myItem) => {\n\n // use absolute value of _value, bc speeds outbound will be negative\n myItem._value = Math.abs(myItem._value)\n\n //if direction doesn't exist, push it\n if (newMsg[0].series.indexOf(myItem.direction) < 0) {\n newMsg[0].series.push(myItem.direction);\n //create new data array element that matches the series index\n newMsg[0].data[newMsg[0].series.indexOf(myItem.direction)] = [];\n }\n\n //Check if it's a new date or existing in data[0][0].x\n //datapoint for date \n let xIndex = newMsg[0].data[newMsg[0].series.indexOf(myItem.direction)].findIndex((element) => element.x == String(new Date(myItem._time)));\n if (xIndex < 0) {\n //new date\n let thisDataPoint = {};\n thisDataPoint.x = new Date(myItem._time);\n thisDataPoint.y = myItem._value;\n newMsg[0].data[newMsg[0].series.indexOf(myItem.direction)].push(thisDataPoint);\n }\n else {\n //date exists, sum counts\n newMsg[0].data[newMsg[0].series.indexOf(myItem.direction)][xIndex].y += myItem._value;\n };\n\n});\n\nmsg.payload = newMsg;\n\nreturn msg;",
+ "g": "0e1614cf2e5f9942",
+ "name": "create sqlite query, 1-hour counts last day in zone_radar",
+ "func": "//frame_time is already in seconds\n//frame_time as 5-minute intervals, rounded up\n\nconst query = `\nSELECT\n strftime('%Y-%m-%d %H:%M:00', (frame_time + 299), 'unixepoch', '-' || ((frame_time + 299) % 300) || ' seconds', 'localtime') AS bin_time,\n label,\n camera,\n COUNT(*) as count\nFROM\n events\nWHERE\n frame_time > (unixepoch('now') - (3600))\n AND camera = '${env.get(\"VAR_RADAR_CAMERA\")}'\n AND entered_zones LIKE '%zone_radar%'\nGROUP BY\n label, strftime('%Y-%m-%d %H:%M:00', (frame_time + 299), 'unixepoch', '-' || ((frame_time + 299) % 300) || ' seconds', 'localtime'), camera\nORDER BY\n label, bin_time, camera;\n`;\n\nmsg.topic = query;\nreturn msg;",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
- "x": 530,
+ "x": 290,
+ "y": 1200,
+ "wires": [
+ [
+ "eff2193c8246a9d2"
+ ]
+ ]
+ },
+ {
+ "id": "eff2193c8246a9d2",
+ "type": "sqlite",
+ "z": "28627559bebdc324",
+ "g": "0e1614cf2e5f9942",
+ "mydb": "2f60c1ab30a6fc8f",
+ "sqlquery": "msg.topic",
+ "sql": "",
+ "name": "",
+ "x": 420,
"y": 1240,
"wires": [
[
- "1b7c2967fd6a85a4"
+ "57fa6ca2b7d290e3"
]
]
},
{
- "id": "a432e760cc77e6cb",
+ "id": "57fa6ca2b7d290e3",
"type": "function",
"z": "28627559bebdc324",
- "g": "76417db2b472ef4f",
- "name": "structure influx TimedSpeedCounts.counts",
- "func": "//https://github.com/node-red/node-red-dashboard/blob/master/Charts.md\n//Array of Object with keys of series, data=x:ts,y:count, directions\n\nvar newMsg = [{}];\nnewMsg[0].series = [];\nnewMsg[0].data = [];\nnewMsg[0].direction = [];\n\n// _time\n// _value\n// direction\n\n\nmsg.payload.forEach((myItem) => {\n\n //if direction doesn't exist, push it\n if (newMsg[0].series.indexOf(myItem.direction) < 0) {\n newMsg[0].series.push(myItem.direction);\n //create new data array element that matches the series index\n newMsg[0].data[newMsg[0].series.indexOf(myItem.direction)] = [];\n }\n\n //Check if it's a new date or existing in data[0][0].x\n //datapoint for date \n let xIndex = newMsg[0].data[newMsg[0].series.indexOf(myItem.direction)].findIndex((element) => element.x == String(new Date(myItem._time)));\n if (xIndex < 0) {\n //new date\n let thisDataPoint = {};\n thisDataPoint.x = new Date(myItem._time);\n thisDataPoint.y = myItem._value;\n newMsg[0].data[newMsg[0].series.indexOf(myItem.direction)].push(thisDataPoint);\n }\n else {\n //date exists, sum counts\n newMsg[0].data[newMsg[0].series.indexOf(myItem.direction)][xIndex].y += myItem._value;\n };\n\n});\n\nmsg.payload = newMsg;\n\nreturn msg;",
+ "g": "0e1614cf2e5f9942",
+ "name": "structure 1-hour counts last day",
+ "func": "//https://github.com/node-red/node-red-dashboard/blob/master/Charts.md\n//Array of Object with keys of series, data=x:ts,y:count, labels\n\nvar newMsg = [{}];\nnewMsg[0].series = [];\nnewMsg[0].data = [];\nnewMsg[0].label = [];\n\nmsg.payload.forEach((myItem) => {\n\n //if label doesn't exist, push it\n if (newMsg[0].series.indexOf(myItem.label) < 0) {\n newMsg[0].series.push(myItem.label);\n //create new data array element that matches the series index\n newMsg[0].data[newMsg[0].series.indexOf(myItem.label)] = [];\n }\n\n //Check if it's a new date or existing in data[0][0].x\n //datapoint for date \n let xIndex = newMsg[0].data[newMsg[0].series.indexOf(myItem.label)].findIndex((element) => element.x == String(new Date(myItem.bin_time)));\n if (xIndex < 0) {\n //new date\n let thisDataPoint = {};\n thisDataPoint.x = new Date(myItem.bin_time);\n thisDataPoint.y = myItem.count;\n newMsg[0].data[newMsg[0].series.indexOf(myItem.label)].push(thisDataPoint);\n }\n else {\n //date exists, sum counts\n newMsg[0].data[newMsg[0].series.indexOf(myItem.label)][xIndex].y += myItem.count;\n }\n\n});\n\nmsg.payload = newMsg;\n\nreturn msg;",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
- "x": 500,
- "y": 1060,
+ "x": 410,
+ "y": 1280,
"wires": [
[
- "537d771bb5b1eff5"
+ "11fa2826769befc7"
]
]
},
{
- "id": "736d1e21a49f446b",
+ "id": "170ddffb726db9e0",
"type": "function",
"z": "28627559bebdc324",
- "g": "9b9e4fc50b744fc3",
- "name": "store last N any frigate events",
- "func": "//events_recent_radar should show the last N events where payload.entered_zones CONTAINS zone_radar\n\nvar myEvents = flow.get(\"events_all\") || [];\n//Keep only last X elements\nvar myArrLength = 10;\n\n//invert array so OLDEST IS FIRST, for functions\nmyEvents.reverse();\n\nif (myEvents.length >= myArrLength) {\n //remove first element (oldest event)\n myEvents.shift();\n}\n\n//keep only specific elements\nconst newObj = {\n id: msg.payload.id, \n label: msg.payload.label, \n direction_calc: msg.payload.direction_calc, \n speed_calc: msg.payload.speed_calc, \n };\n\n//add current event to end of array\nmyEvents.push(newObj);\n\n//invert array so NEWEST IS FIRST, for display\nmyEvents.reverse();\n\nflow.set(\"events_all\", myEvents);\n\nmsg.payload = myEvents;\n\nreturn msg;",
+ "g": "453513c49e4b1b60",
+ "name": "create sqlite query, daily cumulative counts in zone_capture",
+ "func": "//frame_time is already in seconds\n\nconst query = `\nSELECT\n label,\n COUNT(*) as count\nFROM\n events\nWHERE\n frame_time >= unixepoch(strftime('%Y-%m-%dT04:00','now', 'localtime'),'utc')\n AND camera = '${env.get(\"VAR_RADAR_CAMERA\")}'\n AND entered_zones LIKE '%zone_capture%'\nGROUP BY \n label\nORDER BY\n label;\n`;\n\nmsg.topic = query;\nreturn msg;",
"outputs": 1,
"timeout": 0,
"noerr": 0,
- "initialize": "// Code added here will be run once\n// whenever the node is started.\n\nif (flow.get(\"events_recent_radar\") === undefined) {\n flow.set(\"events_recent_radar\", [])\n}\n",
+ "initialize": "",
"finalize": "",
"libs": [],
- "x": 400,
- "y": 2040,
+ "x": 600,
+ "y": 2280,
"wires": [
[
- "5b307e65106f3540"
+ "befe91e6862c72db"
]
]
},
{
- "id": "5b307e65106f3540",
- "type": "ui_text",
- "z": "28627559bebdc324",
- "g": "9b9e4fc50b744fc3",
- "group": "7866c2aa313ab8b9",
- "order": 4,
- "width": 12,
- "height": 5,
- "name": "",
- "label": "last N events, text output",
- "format": "{{msg.payload}}",
- "layout": "row-spread",
- "className": "",
- "style": true,
- "font": "Courier,monospace",
- "fontSize": "10",
- "color": "#000000",
- "x": 1070,
- "y": 2040,
- "wires": []
- },
- {
- "id": "4c087723a1d698e9",
- "type": "ui_template",
- "z": "28627559bebdc324",
- "g": "9b9e4fc50b744fc3",
- "group": "7866c2aa313ab8b9",
- "name": "last N radar speeding events",
- "order": 3,
- "width": 0,
- "height": 0,
- "format": "last N zone_radar speeding events for radar_camera (>20-mph)
\n\n \n  | \n \n id: {{payload.id}} \n label: {{payload.label}} \n top_score: {{payload.top_score}} \n frame_time: {{payload.frame_time_datestring}} \n direction: {{payload.direction_calc}} \n speed: {{payload.speed_calc}}\n | \n
\n
",
- "storeOutMessages": true,
- "fwdInMessages": true,
- "resendOnRefresh": true,
- "templateScope": "local",
- "className": "",
- "x": 1090,
- "y": 1980,
- "wires": [
- []
- ]
- },
- {
- "id": "11fa2826769befc7",
- "type": "ui_chart",
+ "id": "befe91e6862c72db",
+ "type": "sqlite",
"z": "28627559bebdc324",
- "g": "0e1614cf2e5f9942",
+ "g": "453513c49e4b1b60",
+ "mydb": "2f60c1ab30a6fc8f",
+ "sqlquery": "msg.topic",
+ "sql": "",
"name": "",
- "group": "06dde4be9a9a6b27",
- "order": 7,
- "width": 0,
- "height": 0,
- "label": "Events in zone_radar (5-min) for last 60-min",
- "chartType": "line",
- "legend": "true",
- "xformat": "HH:mm",
- "interpolate": "linear",
- "nodata": "",
- "dot": false,
- "ymin": "",
- "ymax": "",
- "removeOlder": "60",
- "removeOlderPoints": "",
- "removeOlderUnit": "60",
- "cutout": 0,
- "useOneColor": false,
- "useUTC": false,
- "colors": [
- "#1f77b4",
- "#aec7e8",
- "#ff7f0e",
- "#2ca02c",
- "#98df8a",
- "#d62728",
- "#ff9896",
- "#9467bd",
- "#c5b0d5"
- ],
- "outputs": 1,
- "useDifferentColor": false,
- "className": "",
- "x": 970,
- "y": 1420,
+ "x": 740,
+ "y": 2320,
"wires": [
- []
+ [
+ "13a061996f9322f3",
+ "98571c77b9801a83"
+ ]
]
},
{
- "id": "6d738ed81fefbedc",
- "type": "ui_chart",
+ "id": "13a061996f9322f3",
+ "type": "function",
"z": "28627559bebdc324",
"g": "453513c49e4b1b60",
- "name": "",
- "group": "7866c2aa313ab8b9",
- "order": 1,
- "width": 0,
- "height": 0,
- "label": "cumulative events by object since 0400",
- "chartType": "horizontalBar",
- "legend": "true",
- "xformat": "HH:mm:ss",
- "interpolate": "linear",
- "nodata": "",
- "dot": false,
- "ymin": "",
- "ymax": "",
- "removeOlder": 1,
- "removeOlderPoints": "",
- "removeOlderUnit": "3600",
- "cutout": 0,
- "useOneColor": false,
- "useUTC": false,
- "colors": [
- "#1f77b4",
- "#aec7e8",
- "#ff7f0e",
- "#2ca02c",
- "#98df8a",
- "#d62728",
- "#ff9896",
- "#9467bd",
- "#c5b0d5"
- ],
+ "name": "structure daily object counts for chart",
+ "func": "//https://github.com/node-red/node-red-dashboard/blob/master/Charts.md\n//Array of Object with keys of series, data=x:ts,y:count, labels\n\n\n//create bicycle_adj to be bicycle+motorcycle\n//create person_adj to be person - bicycle_adj\n\nconst motorcycleCount = msg.payload.find(item => item.label === 'motorcycle')?.count || 0;\nconst bicycleCount = msg.payload.find(item => item.label === 'bicycle')?.count || 0;\nconst personCount = msg.payload.find(item => item.label === 'person')?.count || 0;\n\nconst formattedData = [{\n series: [...msg.payload.map(item => item.label), 'bicycle_adj', 'person_adj'],\n data: [\n ...(msg.payload.map(item => [item.count])),\n [bicycleCount + motorcycleCount],\n [personCount - (bicycleCount + motorcycleCount)]\n ],\n labels: [\"\"]\n}];\n\nmsg.payload = formattedData;\n\nreturn msg;",
"outputs": 1,
- "useDifferentColor": false,
- "className": "",
- "x": 1140,
+ "timeout": 0,
+ "noerr": 0,
+ "initialize": "",
+ "finalize": "",
+ "libs": [],
+ "x": 770,
"y": 2380,
"wires": [
- []
+ [
+ "6d738ed81fefbedc"
+ ]
]
},
{
- "id": "d856c68660eb2202",
- "type": "mqtt out",
- "z": "28627559bebdc324",
- "g": "453513c49e4b1b60",
- "name": "",
- "topic": "tm/events",
- "qos": "1",
- "retain": "true",
- "respTopic": "",
- "contentType": "",
- "userProps": "",
- "correl": "",
- "expiry": "",
- "broker": "a5d65dd0e3566daa",
- "x": 1040,
- "y": 2420,
- "wires": []
- },
- {
- "id": "0f65ceafe3f7c069",
+ "id": "98571c77b9801a83",
"type": "function",
"z": "28627559bebdc324",
- "g": "9b9e4fc50b744fc3",
- "name": "format last N radar event for output",
- "func": "\n\nconst newMsg = {};\nnewMsg.payload = {}; // contain everything going into a DB record, single record\n\nnewMsg.payload.id = msg.frigate_event.id;\nnewMsg.payload.camera = msg.frigate_event.camera;\nnewMsg.payload.label = msg.frigate_event.label;\nnewMsg.payload.sub_label = msg.frigate_event.sub_label;\nnewMsg.payload.top_score = msg.frigate_event.top_score;\n\nnewMsg.payload.frame_time_datestring = new Date(msg.frigate_event.frame_time * 1000).toLocaleString();\nnewMsg.payload.frame_time = msg.frigate_event.frame_time;\nnewMsg.payload.start_time = msg.frigate_event.start_time;\nnewMsg.payload.end_time = msg.frigate_event.end_time;\n\nnewMsg.payload.entered_zones = msg.frigate_event.entered_zones; //array\nnewMsg.payload.direction_calc = msg.frigate_event.direction_calc;\nnewMsg.payload.speed_calc = msg.frigate_event.speed_calc;\n\nnewMsg.payload.thumbnail_base64jpg = msg.frigate_event_api_thumbnail;\n\nnewMsg.payload.location = msg.frigate_event.location;\n\nreturn newMsg;\n\n\nreturn msg;",
+ "g": "453513c49e4b1b60",
+ "name": "structure daily object counts for tm/events",
+ "func": "//send as key:value pair for lable:count\n\n//create bicycle_adj to be bicycle+motorcycle\n//create person_adj to be person - bicycle_adj\n\n\n\nconst motorcycleCount = msg.payload.find(item => item.label === 'motorcycle')?.count || 0;\nconst bicycleCount = msg.payload.find(item => item.label === 'bicycle')?.count || 0;\nconst personCount = msg.payload.find(item => item.label === 'person')?.count || 0;\n\nconst formattedData = msg.payload.reduce((acc, curr) => {\n acc[curr.label] = curr.count;\n\n if (curr.label === 'bicycle') {\n acc['bicycle_adj'] = (bicycleCount + motorcycleCount);\n }\n\n if (curr.label === 'person') {\n acc['person_adj'] = (personCount - (bicycleCount + motorcycleCount));\n }\n\n return acc;\n}, {});\n\nformattedData['event_latest'] = flow.get(\"event_latest\");\n\nmsg.payload = formattedData;\n\nreturn msg;",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
- "x": 470,
- "y": 1900,
+ "x": 780,
+ "y": 2420,
"wires": [
[
- "e5391514131a2b5a",
- "d66541089b01306e"
+ "d856c68660eb2202"
]
]
},
{
- "id": "c90aed37b7a31d9e",
- "type": "inject",
+ "id": "584504e6c8935eaf",
+ "type": "function",
"z": "28627559bebdc324",
"g": "1bd1f21fa0390c69",
- "name": "trigger Event query every 5-min",
- "props": [
- {
- "p": "payload"
- },
- {
- "p": "topic",
- "vt": "str"
- }
- ],
- "repeat": "300",
- "crontab": "",
- "once": true,
- "onceDelay": "1",
- "topic": "query",
- "payload": "",
- "payloadType": "date",
- "x": 240,
- "y": 2560,
+ "name": "create sqlite query, daily cumulative CAR counts in zone_capture + zone_radar that HAVE valid speed_calc",
+ "func": "//frame_time is already in seconds\n//cars with speeds in zone_radar AND zone_capture since 0400 today\n\nconst query = `\nWITH results AS (\n SELECT \n COUNT(*) AS count,\n AVG(ABS(speed_calc)) AS mean_speed,\n MAX(CASE WHEN ntile = 5 THEN ABS(speed_calc) ELSE NULL END) AS p25_speed,\n MAX(CASE WHEN ntile = 10 THEN ABS(speed_calc) ELSE NULL END) AS p50_speed,\n MAX(CASE WHEN ntile = 15 THEN ABS(speed_calc) ELSE NULL END) AS p75_speed,\n MAX(CASE WHEN ntile = 17 THEN ABS(speed_calc) ELSE NULL END) AS p85_speed,\n MAX(ABS(speed_calc)) AS max_speed,\n SUM(CASE WHEN ABS(speed_calc) > 25 THEN 1 ELSE 0 END) AS count_over_25,\n JSON_GROUP_ARRAY(speed_calc) AS speeds\n FROM \n (SELECT \n ABS(speed_calc) as speed_calc,\n NTILE(20) OVER (ORDER BY ABS(speed_calc)) AS ntile\n FROM \n events\n WHERE \n frame_time >= unixepoch(strftime('%Y-%m-%dT04:00','now', 'localtime'),'utc') AND\n label = 'car' AND\n entered_zones LIKE '%zone_radar%' AND\n entered_zones LIKE '%zone_capture%' AND\n ABS(speed_calc) NOT NULL AND\n camera = '${env.get(\"VAR_RADAR_CAMERA\")}'\n )\n)\nSELECT \n *, \n p75_speed + 1.5 * (p75_speed - p25_speed) AS iqr_upper,\n (SELECT COUNT(*) FROM json_each(results.speeds) WHERE json_each.value > p75_speed + 1.5 * (p75_speed - p25_speed)) AS iqr_upper_freq\nFROM \n results;\n`;\n\nmsg.topic = query;\nreturn msg;",
+ "outputs": 1,
+ "timeout": 0,
+ "noerr": 0,
+ "initialize": "",
+ "finalize": "",
+ "libs": [],
+ "x": 470,
+ "y": 2620,
"wires": [
[
- "584504e6c8935eaf"
+ "9cf49f0891d25df1"
]
]
},
{
- "id": "5417aae0d14fa661",
- "type": "ui_template",
+ "id": "9cf49f0891d25df1",
+ "type": "sqlite",
"z": "28627559bebdc324",
"g": "1bd1f21fa0390c69",
- "group": "06dde4be9a9a6b27",
- "name": "car speed stats for today, since 0400",
- "order": 1,
- "width": 0,
- "height": 0,
- "format": "car speed stats for today, since 0400
\n\n \n {{key}}: | \n {{value}} | \n
\n
",
- "storeOutMessages": true,
- "fwdInMessages": true,
- "resendOnRefresh": true,
- "templateScope": "local",
- "className": "",
- "x": 1130,
- "y": 2720,
+ "mydb": "2f60c1ab30a6fc8f",
+ "sqlquery": "msg.topic",
+ "sql": "",
+ "name": "",
+ "x": 760,
+ "y": 2660,
"wires": [
- []
+ [
+ "6d81c8e3c89b68f6"
+ ]
]
},
{
- "id": "f57e08e6fb9c0d09",
- "type": "switch",
+ "id": "432a378bcc3e7a73",
+ "type": "comment",
"z": "28627559bebdc324",
- "g": "453513c49e4b1b60",
- "name": "only for zone_capture",
- "property": "payload.entered_zones",
- "propertyType": "msg",
- "rules": [
- {
- "t": "cont",
- "v": "zone_capture",
- "vt": "str"
- }
- ],
- "checkall": "true",
- "repair": false,
+ "name": "TODO: show cars w NULL speed_calc, ...",
+ "info": "",
+ "x": 220,
+ "y": 2900,
+ "wires": []
+ },
+ {
+ "id": "6d81c8e3c89b68f6",
+ "type": "function",
+ "z": "28627559bebdc324",
+ "g": "1bd1f21fa0390c69",
+ "name": "format payload for car speed daily",
+ "func": "\nconst originalPayload = msg.payload;\n\nconst convertedPayload = Object.keys(originalPayload[0])\n .filter(key => key !== \"speeds\")\n .map(key => {\n const value = originalPayload[0][key];\n return { [key]: typeof value === \"number\" ? Math.round(value) : value };\n });\n\nmsg.payload = convertedPayload;\n\nreturn msg;",
"outputs": 1,
- "x": 400,
- "y": 2180,
+ "timeout": 0,
+ "noerr": 0,
+ "initialize": "",
+ "finalize": "",
+ "libs": [],
+ "x": 740,
+ "y": 2720,
"wires": [
[
- "d23be15251ed6d73"
+ "5417aae0d14fa661"
]
]
},
{
- "id": "d23be15251ed6d73",
- "type": "change",
+ "id": "7cc031e5a7d773a4",
+ "type": "sqlite",
"z": "28627559bebdc324",
- "g": "453513c49e4b1b60",
- "name": "set flow.event_latest",
- "rules": [
- {
- "t": "set",
- "p": "event_latest",
- "pt": "flow",
- "to": "payload.label",
- "tot": "msg"
- }
- ],
- "action": "",
- "property": "",
- "from": "",
- "to": "",
- "reg": false,
- "x": 460,
- "y": 2240,
+ "g": "76417db2b472ef4f",
+ "mydb": "1d8d8c9a28569355",
+ "sqlquery": "msg.topic",
+ "sql": "",
+ "name": "",
+ "x": 340,
+ "y": 980,
"wires": [
[
- "170ddffb726db9e0"
+ "39d895a16ca6f6f1",
+ "62be7d38b991716c"
]
]
},
{
- "id": "4760bed60a7f392a",
- "type": "inject",
+ "id": "79900a566af02159",
+ "type": "function",
"z": "28627559bebdc324",
- "g": "453513c49e4b1b60",
- "name": "",
- "props": [],
- "repeat": "",
- "crontab": "",
- "once": false,
- "onceDelay": 0.1,
- "topic": "",
- "x": 250,
- "y": 2280,
+ "g": "76417db2b472ef4f",
+ "name": "query TimedSpeedCounts for last 60-min",
+ "func": "//time is already in seconds\n//get for last 60-minutes, 3600 seconds\n\nconst query = `\nSELECT\n strftime('%Y-%m-%d %H:%M:00', datetime(time, 'unixepoch', 'localtime'), '+0 minutes') AS time,\n direction,\n count,\n ABS(average) as speed\nFROM\n radar_timed_speed_counts\nWHERE\n time > (unixepoch('now') - (3600))\nORDER BY\n time;\n`;\n\nmsg.topic = query;\nreturn msg;",
+ "outputs": 1,
+ "timeout": 0,
+ "noerr": 0,
+ "initialize": "",
+ "finalize": "",
+ "libs": [],
+ "x": 220,
+ "y": 940,
"wires": [
[
- "170ddffb726db9e0"
+ "7cc031e5a7d773a4"
]
]
},
{
- "id": "09f99c931e5535bf",
- "type": "http request",
+ "id": "39d895a16ca6f6f1",
+ "type": "function",
"z": "28627559bebdc324",
- "g": "f5d2d92d50d18ce2",
- "name": "frigate http api for thumbnail",
- "method": "GET",
- "ret": "bin",
- "paytoqs": "ignore",
- "url": "http://frigate:5000//api/events/{{{frigate_event.id}}}/thumbnail.jpg",
- "tls": "",
- "persist": false,
- "proxy": "",
- "insecureHTTPParser": false,
- "authType": "",
- "senderr": false,
- "headers": [],
- "x": 450,
- "y": 1780,
+ "g": "76417db2b472ef4f",
+ "name": "structure SQLite TimedSpeedCounts.counts",
+ "func": "//https://github.com/node-red/node-red-dashboard/blob/master/Charts.md\n//Array of Object with keys of series, data=x:ts,y:count, directions\n\nvar newMsg = [{}];\nnewMsg[0].series = [];\nnewMsg[0].data = [];\nnewMsg[0].direction = [];\n\n// time\n// count\n// direction\n\n\nmsg.payload.forEach((myItem) => {\n\n //if direction doesn't exist, push it\n if (newMsg[0].series.indexOf(myItem.direction) < 0) {\n newMsg[0].series.push(myItem.direction);\n //create new data array element that matches the series index\n newMsg[0].data[newMsg[0].series.indexOf(myItem.direction)] = [];\n }\n\n //Check if it's a new date or existing in data[0][0].x\n //datapoint for date \n let xIndex = newMsg[0].data[newMsg[0].series.indexOf(myItem.direction)].findIndex((element) => element.x == String(new Date(myItem.time)));\n if (xIndex < 0) {\n //new date\n let thisDataPoint = {};\n thisDataPoint.x = new Date(myItem.time);\n thisDataPoint.y = myItem.count;\n newMsg[0].data[newMsg[0].series.indexOf(myItem.direction)].push(thisDataPoint);\n }\n else {\n //date exists, sum counts\n newMsg[0].data[newMsg[0].series.indexOf(myItem.direction)][xIndex].y += myItem.count;\n };\n\n});\n\nmsg.payload = newMsg;\n\nreturn msg;",
+ "outputs": 1,
+ "timeout": 0,
+ "noerr": 0,
+ "initialize": "",
+ "finalize": "",
+ "libs": [],
+ "x": 630,
+ "y": 980,
"wires": [
[
- "9226865e3385eb56",
- "aa0afb5180297e2b"
+ "cbb3b02ca505a55b"
]
]
},
{
- "id": "08121a31488784bc",
- "type": "change",
+ "id": "62be7d38b991716c",
+ "type": "function",
"z": "28627559bebdc324",
- "g": "f5d2d92d50d18ce2",
- "name": "set frigate_event_api_thumbnail",
- "rules": [
- {
- "t": "set",
- "p": "frigate_event_api_thumbnail",
- "pt": "msg",
- "to": "payload",
- "tot": "msg"
- }
- ],
- "action": "",
- "property": "",
- "from": "",
- "to": "",
- "reg": false,
- "x": 760,
- "y": 1820,
+ "g": "76417db2b472ef4f",
+ "name": "structure sqlite TimedSpeedCounts.speed_average",
+ "func": "//https://github.com/node-red/node-red-dashboard/blob/master/Charts.md\n//Array of Object with keys of series, data=x:ts,y:count, directions\n\nvar newMsg = [{}];\nnewMsg[0].series = [];\nnewMsg[0].data = [];\nnewMsg[0].direction = [];\n\n// time\n// speed\n// direction\n\n\nmsg.payload.forEach((myItem) => {\n\n // use absolute value of speed, bc speeds outbound will be negative\n myItem.speed = Math.abs(myItem.speed)\n\n //if direction doesn't exist, push it\n if (newMsg[0].series.indexOf(myItem.direction) < 0) {\n newMsg[0].series.push(myItem.direction);\n //create new data array element that matches the series index\n newMsg[0].data[newMsg[0].series.indexOf(myItem.direction)] = [];\n }\n\n //Check if it's a new date or existing in data[0][0].x\n //datapoint for date \n let xIndex = newMsg[0].data[newMsg[0].series.indexOf(myItem.direction)].findIndex((element) => element.x == String(new Date(myItem.time)));\n if (xIndex < 0) {\n //new date\n let thisDataPoint = {};\n thisDataPoint.x = new Date(myItem.time);\n thisDataPoint.y = myItem.speed;\n newMsg[0].data[newMsg[0].series.indexOf(myItem.direction)].push(thisDataPoint);\n }\n else {\n //date exists, sum counts\n newMsg[0].data[newMsg[0].series.indexOf(myItem.direction)][xIndex].y += myItem.speed;\n };\n\n});\n\nmsg.payload = newMsg;\n\nreturn msg;",
+ "outputs": 1,
+ "timeout": 0,
+ "noerr": 0,
+ "initialize": "",
+ "finalize": "",
+ "libs": [],
+ "x": 650,
+ "y": 1060,
"wires": [
[
- "0f65ceafe3f7c069"
+ "7db4b197df9eb075"
]
]
},
{
- "id": "9226865e3385eb56",
- "type": "image",
+ "id": "cbb3b02ca505a55b",
+ "type": "ui_chart",
"z": "28627559bebdc324",
- "g": "f5d2d92d50d18ce2",
+ "g": "76417db2b472ef4f",
"name": "",
- "width": "175",
- "data": "payload",
- "dataType": "msg",
- "thumbnail": false,
- "active": false,
- "pass": false,
- "outputs": 0,
- "x": 710,
- "y": 1780,
- "wires": []
+ "group": "06dde4be9a9a6b27",
+ "order": 5,
+ "width": 0,
+ "height": 0,
+ "label": "SQLite TimedSpeedCounts.counts (5-min) for last 60-min",
+ "chartType": "line",
+ "legend": "true",
+ "xformat": "HH:mm",
+ "interpolate": "linear",
+ "nodata": "",
+ "dot": false,
+ "ymin": "",
+ "ymax": "",
+ "removeOlder": "60",
+ "removeOlderPoints": "",
+ "removeOlderUnit": "60",
+ "cutout": 0,
+ "useOneColor": false,
+ "useUTC": false,
+ "colors": [
+ "#1f77b4",
+ "#aec7e8",
+ "#ff7f0e",
+ "#2ca02c",
+ "#98df8a",
+ "#d62728",
+ "#ff9896",
+ "#9467bd",
+ "#c5b0d5"
+ ],
+ "outputs": 1,
+ "useDifferentColor": false,
+ "className": "",
+ "x": 690,
+ "y": 1020,
+ "wires": [
+ []
+ ]
},
{
- "id": "aa0afb5180297e2b",
- "type": "base64",
+ "id": "7db4b197df9eb075",
+ "type": "ui_chart",
"z": "28627559bebdc324",
- "g": "f5d2d92d50d18ce2",
+ "g": "76417db2b472ef4f",
"name": "",
- "action": "",
- "property": "payload",
- "x": 550,
- "y": 1820,
+ "group": "06dde4be9a9a6b27",
+ "order": 6,
+ "width": 0,
+ "height": 0,
+ "label": "SQLite TimedSpeedCounts.speed_average (5-min) for last 60-min",
+ "chartType": "line",
+ "legend": "true",
+ "xformat": "HH:mm",
+ "interpolate": "linear",
+ "nodata": "",
+ "dot": false,
+ "ymin": "",
+ "ymax": "",
+ "removeOlder": "60",
+ "removeOlderPoints": "",
+ "removeOlderUnit": "60",
+ "cutout": 0,
+ "useOneColor": false,
+ "useUTC": false,
+ "colors": [
+ "#1f77b4",
+ "#aec7e8",
+ "#ff7f0e",
+ "#2ca02c",
+ "#98df8a",
+ "#d62728",
+ "#ff9896",
+ "#9467bd",
+ "#c5b0d5"
+ ],
+ "outputs": 1,
+ "useDifferentColor": false,
+ "className": "",
+ "x": 720,
+ "y": 1100,
"wires": [
- [
- "08121a31488784bc"
- ]
+ []
]
},
{
- "id": "c2270f3050bf35ab",
- "type": "change",
- "z": "28627559bebdc324",
- "g": "9b9e4fc50b744fc3",
- "name": "set frigate_event from payload",
- "rules": [
+ "id": "6a05187a692bed7c",
+ "type": "ui_form",
+ "z": "239d7b3ba410ad5e",
+ "g": "541d31d14bcd8b00",
+ "name": "",
+ "label": "Create new Comment",
+ "group": "d3f63882e39b03a6",
+ "order": 2,
+ "width": 0,
+ "height": 0,
+ "options": [
{
- "t": "set",
- "p": "frigate_event",
- "pt": "msg",
- "to": "payload",
- "tot": "msg"
+ "label": "Effective Date (start of comment period)",
+ "value": "effective_date",
+ "type": "date",
+ "required": false,
+ "rows": null
+ },
+ {
+ "label": "Effective Time",
+ "value": "effective_time",
+ "type": "time",
+ "required": false,
+ "rows": null
+ },
+ {
+ "label": "Expiration Date (end of comment period)",
+ "value": "expiration_date",
+ "type": "date",
+ "required": false,
+ "rows": null
+ },
+ {
+ "label": "Expiration Time",
+ "value": "expiration_time",
+ "type": "time",
+ "required": false,
+ "rows": null
+ },
+ {
+ "label": "Comment",
+ "value": "comment",
+ "type": "multiline",
+ "required": false,
+ "rows": 3
+ },
+ {
+ "label": "Commenter Name (or description)",
+ "value": "name",
+ "type": "text",
+ "required": false,
+ "rows": null
}
],
- "action": "",
- "property": "",
- "from": "",
- "to": "",
- "reg": false,
- "x": 440,
- "y": 1700,
+ "formValue": {
+ "effective_date": "",
+ "effective_time": "",
+ "expiration_date": "",
+ "expiration_time": "",
+ "comment": "",
+ "name": ""
+ },
+ "payload": "",
+ "submit": "submit",
+ "cancel": "clear",
+ "topic": "topic",
+ "topicType": "msg",
+ "splitLayout": "",
+ "className": "",
+ "x": 140,
+ "y": 60,
"wires": [
[
- "09f99c931e5535bf"
+ "fee2d22032a11056",
+ "8d65b604e8d9e7f9"
]
]
},
{
- "id": "3214e8cd3ea79630",
+ "id": "fee2d22032a11056",
"type": "debug",
- "z": "28627559bebdc324",
- "g": "9b9e4fc50b744fc3",
- "name": "debug: last N radar events",
- "active": false,
+ "z": "239d7b3ba410ad5e",
+ "g": "541d31d14bcd8b00",
+ "name": "debug: comment form input",
+ "active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
@@ -3275,399 +4105,533 @@
"targetType": "full",
"statusVal": "",
"statusType": "auto",
- "x": 1080,
- "y": 1840,
+ "x": 1020,
+ "y": 60,
"wires": []
},
{
- "id": "5f3716d2176c3ab4",
- "type": "function",
- "z": "28627559bebdc324",
- "g": "0a6e123f5e53c029",
- "name": "create sqlite query, daily summary in zone_capture",
- "func": "//frame_time is already in seconds\n\nconst query = `\nSELECT\n date(frame_time, 'unixepoch') as day,\n label,\n camera,\n COUNT(*) as count\nFROM\n events\nWHERE\n frame_time > (unixepoch('now') - (86400 * 10))\n AND camera = '${env.get(\"VAR_RADAR_CAMERA\")}'\n AND entered_zones LIKE '%zone_capture%'\nGROUP BY\n label, date(frame_time, 'unixepoch'), camera\nORDER BY\n label, day, camera;\n`;\n\nmsg.topic = query;\nreturn msg;",
- "outputs": 1,
- "timeout": 0,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 250,
- "y": 400,
- "wires": [
- [
- "bdb4b259d648b1f0"
- ]
- ]
- },
- {
- "id": "bdb4b259d648b1f0",
+ "id": "f27b6d01ae7836d6",
"type": "sqlite",
- "z": "28627559bebdc324",
- "g": "0a6e123f5e53c029",
+ "z": "239d7b3ba410ad5e",
+ "g": "541d31d14bcd8b00",
"mydb": "2f60c1ab30a6fc8f",
"sqlquery": "msg.topic",
"sql": "",
"name": "",
- "x": 360,
- "y": 440,
- "wires": [
- [
- "ec7a0e0b1c62e91d"
- ]
- ]
- },
- {
- "id": "ec7a0e0b1c62e91d",
- "type": "function",
- "z": "28627559bebdc324",
- "g": "0a6e123f5e53c029",
- "name": "structure daily summary payload",
- "func": "//https://github.com/node-red/node-red-dashboard/blob/master/Charts.md\n//Array of Object with keys of series, data=x:ts,y:count, labels\n\nvar newMsg = [{}];\nnewMsg[0].series = [];\nnewMsg[0].data = [];\nnewMsg[0].label = [];\n\nmsg.payload.forEach((myItem) => {\n\n //if label doesn't exist, push it\n if (newMsg[0].series.indexOf(myItem.label) < 0) {\n newMsg[0].series.push(myItem.label);\n //create new data array element that matches the series index\n newMsg[0].data[newMsg[0].series.indexOf(myItem.label)] = [];\n }\n\n //Check if it's a new date or existing in data[0][0].x\n //datapoint for date \n let xIndex = newMsg[0].data[newMsg[0].series.indexOf(myItem.label)].findIndex((element) => element.x == String(new Date(myItem.day)));\n if (xIndex < 0) {\n //new date\n let thisDataPoint = {};\n thisDataPoint.x = new Date(myItem.day);\n thisDataPoint.y = myItem.count;\n newMsg[0].data[newMsg[0].series.indexOf(myItem.label)].push(thisDataPoint);\n }\n else {\n //date exists, sum counts\n newMsg[0].data[newMsg[0].series.indexOf(myItem.label)][xIndex].y += myItem.count;\n }\n\n});\n\nmsg.payload = newMsg;\n\nreturn msg;",
- "outputs": 1,
- "timeout": 0,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 330,
- "y": 480,
+ "x": 600,
+ "y": 160,
"wires": [
[
- "b65e1877b1e04881"
+ "840802d34d143ded"
]
]
},
{
- "id": "928b71f25ce6e7b6",
- "type": "function",
- "z": "28627559bebdc324",
- "g": "5173f4b3ac03407a",
- "name": "create sqlite query, 1-hour counts last day in zone_capture",
- "func": "//frame_time is already in seconds\n\nconst query = `\nSELECT\n strftime('%FT%H:00:00.000Z', frame_time, 'unixepoch') as hour,\n label,\n camera,\n COUNT(*) as count\nFROM\n events\nWHERE\n frame_time > (unixepoch('now') - (86400 * 1))\n AND camera = '${env.get(\"VAR_RADAR_CAMERA\")}'\n AND entered_zones LIKE '%zone_capture%'\nGROUP BY\n label, strftime('%F %H', frame_time, 'unixepoch'), camera\nORDER BY\n label, hour, camera;\n`;\n\nmsg.topic = query;\nreturn msg;",
- "outputs": 1,
- "timeout": 0,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 290,
- "y": 660,
+ "id": "8f0bcaf04756da4f",
+ "type": "inject",
+ "z": "239d7b3ba410ad5e",
+ "g": "541d31d14bcd8b00",
+ "name": "create table comments",
+ "props": [
+ {
+ "p": "topic",
+ "vt": "str"
+ }
+ ],
+ "repeat": "",
+ "crontab": "",
+ "once": true,
+ "onceDelay": 0.1,
+ "topic": "CREATE TABLE IF NOT EXISTS comments (id TEXT PRIMARY KEY, effectiveDateTime TIMESTAMP, expirationDateTime TIMESTAMP, entryDateTime TIMESTAMP, comment TEXT, commenter_name TEXT);",
+ "x": 380,
+ "y": 160,
"wires": [
[
- "c03516d1eb65598d"
+ "f27b6d01ae7836d6"
]
]
},
{
- "id": "c03516d1eb65598d",
- "type": "sqlite",
- "z": "28627559bebdc324",
- "g": "5173f4b3ac03407a",
- "mydb": "2f60c1ab30a6fc8f",
- "sqlquery": "msg.topic",
- "sql": "",
- "name": "",
- "x": 420,
- "y": 700,
+ "id": "e8b8e45c4bc045d8",
+ "type": "inject",
+ "z": "239d7b3ba410ad5e",
+ "g": "541d31d14bcd8b00",
+ "name": "select latest 5 rows from comments",
+ "props": [
+ {
+ "p": "topic",
+ "vt": "str"
+ }
+ ],
+ "repeat": "",
+ "crontab": "",
+ "once": false,
+ "onceDelay": 0.1,
+ "topic": "SELECT * FROM comments ORDER BY entryDateTime DESC LIMIT 5;",
+ "x": 340,
+ "y": 200,
"wires": [
[
- "4f84bcb60e4be762"
+ "f27b6d01ae7836d6"
]
]
},
{
- "id": "4f84bcb60e4be762",
- "type": "function",
- "z": "28627559bebdc324",
- "g": "5173f4b3ac03407a",
- "name": "structure 1-hour counts last day",
- "func": "//https://github.com/node-red/node-red-dashboard/blob/master/Charts.md\n//Array of Object with keys of series, data=x:ts,y:count, labels\n\nvar newMsg = [{}];\nnewMsg[0].series = [];\nnewMsg[0].data = [];\nnewMsg[0].label = [];\n\nmsg.payload.forEach((myItem) => {\n\n //if label doesn't exist, push it\n if (newMsg[0].series.indexOf(myItem.label) < 0) {\n newMsg[0].series.push(myItem.label);\n //create new data array element that matches the series index\n newMsg[0].data[newMsg[0].series.indexOf(myItem.label)] = [];\n }\n\n //Check if it's a new date or existing in data[0][0].x\n //datapoint for date \n let xIndex = newMsg[0].data[newMsg[0].series.indexOf(myItem.label)].findIndex((element) => element.x == String(new Date(myItem.hour)));\n if (xIndex < 0) {\n //new date\n let thisDataPoint = {};\n thisDataPoint.x = new Date(myItem.hour);\n thisDataPoint.y = myItem.count;\n newMsg[0].data[newMsg[0].series.indexOf(myItem.label)].push(thisDataPoint);\n }\n else {\n //date exists, sum counts\n newMsg[0].data[newMsg[0].series.indexOf(myItem.label)][xIndex].y += myItem.count;\n }\n\n});\n\nmsg.payload = newMsg;\n\nreturn msg;",
- "outputs": 1,
- "timeout": 0,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 410,
- "y": 740,
- "wires": [
- [
- "02469f2425072f7b"
- ]
- ]
+ "id": "840802d34d143ded",
+ "type": "debug",
+ "z": "239d7b3ba410ad5e",
+ "g": "541d31d14bcd8b00",
+ "name": "sqlite select last 5 comments",
+ "active": true,
+ "tosidebar": true,
+ "console": false,
+ "tostatus": false,
+ "complete": "payload",
+ "targetType": "msg",
+ "statusVal": "",
+ "statusType": "auto",
+ "x": 1040,
+ "y": 160,
+ "wires": []
},
{
- "id": "158e6edae533bfdc",
+ "id": "8d65b604e8d9e7f9",
"type": "function",
- "z": "28627559bebdc324",
- "g": "0e1614cf2e5f9942",
- "name": "create sqlite query, 1-hour counts last day in zone_radar",
- "func": "//frame_time is already in seconds\n//frame_time as 5-minute intervals, rounded up\n\nconst query = `\nSELECT\n strftime('%Y-%m-%d %H:%M:00', (frame_time + 299), 'unixepoch', '-' || ((frame_time + 299) % 300) || ' seconds', 'localtime') AS bin_time,\n label,\n camera,\n COUNT(*) as count\nFROM\n events\nWHERE\n frame_time > (unixepoch('now') - (3600))\n AND camera = '${env.get(\"VAR_RADAR_CAMERA\")}'\n AND entered_zones LIKE '%zone_radar%'\nGROUP BY\n label, strftime('%Y-%m-%d %H:%M:00', (frame_time + 299), 'unixepoch', '-' || ((frame_time + 299) % 300) || ' seconds', 'localtime'), camera\nORDER BY\n label, bin_time, camera;\n`;\n\nmsg.topic = query;\nreturn msg;",
+ "z": "239d7b3ba410ad5e",
+ "g": "541d31d14bcd8b00",
+ "name": "create comment payload",
+ "func": "const newMsg = {};\nnewMsg.payload = {}; // contain everything going into a DB record, single record\n\n//create effectiveDateTime, if no date, use current date, if no time, leave as default\nconst effectiveDateTime = (msg.payload.effective_date) ? new Date(msg.payload.effective_date) : new Date();\nif (msg.payload.effective_time) {\n const effectiveTime = new Date(msg.payload.effective_time);\n \n effectiveDateTime.setTime(effectiveTime.getTime());\n}\n\n//create expirationDateTime, if no date, leave undefined\nconst expirationDateTime = (msg.payload.expiration_date) ? new Date(msg.payload.expiration_date) : undefined;\nif (msg.payload.expiration_time) {\n const expirationTime = new Date(msg.payload.expiration_time);\n\n expirationDateTime.setTime(expirationTime.getTime());\n}\n\n//create entryDateTime\nconst entryDateTime = new Date();\n\nnewMsg.payload.id = entryDateTime.getTime() + '-' + Math.floor(Math.random() * 0xFFFFFFFF).toString(16).padStart(8, '0');\nnewMsg.payload.effectiveDateTime = effectiveDateTime;\nnewMsg.payload.expirationDateTime = expirationDateTime;\nnewMsg.payload.entryDateTime = entryDateTime;\nnewMsg.payload.comment = msg.payload.comment;\nnewMsg.payload.commenter_name = msg.payload.name;\n\nconst obj = newMsg.payload;\n\nconst keyedObj = Object.keys(obj).reduce((acc, key) => {\n acc[`$${key}`] = obj[key];\n return acc;\n}, {});\n\nnewMsg.params = keyedObj;\n\nreturn newMsg;\n",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
- "x": 290,
- "y": 1340,
+ "x": 390,
+ "y": 100,
"wires": [
[
- "eff2193c8246a9d2"
+ "db1f35650c8d6448"
]
- ]
+ ],
+ "info": "//to do each array item\n\nfor (const i in msg.payload.query_return_nonagg) {\n newMsg.payload.radar.push({\n type: \"DetectedObjectVelocity_nonagg_nodir\",\n result: msg.payload.query_return_nonagg[i]\n }\n );\n}"
},
{
- "id": "eff2193c8246a9d2",
+ "id": "db1f35650c8d6448",
"type": "sqlite",
- "z": "28627559bebdc324",
- "g": "0e1614cf2e5f9942",
+ "z": "239d7b3ba410ad5e",
+ "g": "541d31d14bcd8b00",
"mydb": "2f60c1ab30a6fc8f",
- "sqlquery": "msg.topic",
- "sql": "",
+ "sqlquery": "prepared",
+ "sql": "INSERT INTO comments (id, effectiveDateTime, expirationDateTime, entryDateTime, comment, commenter_name)\nVALUES ($id, $effectiveDateTime, $expirationDateTime, $entryDateTime, $comment, $commenter_name);\n",
+ "name": "tmdb.comments, Prepared Statement",
+ "x": 710,
+ "y": 100,
+ "wires": [
+ []
+ ]
+ },
+ {
+ "id": "f43a276d3a899fe8",
+ "type": "ui_form",
+ "z": "239d7b3ba410ad5e",
+ "g": "0e3b2be7bcc3d3b8",
"name": "",
- "x": 420,
- "y": 1380,
+ "label": "Generate Events JSON",
+ "group": "eab37b30ecd3f935",
+ "order": 1,
+ "width": 0,
+ "height": 0,
+ "options": [
+ {
+ "label": "Event start date (default 7-days ago)",
+ "value": "start_date",
+ "type": "date",
+ "required": false,
+ "rows": null
+ },
+ {
+ "label": "Event start time",
+ "value": "start_time",
+ "type": "time",
+ "required": false,
+ "rows": null
+ },
+ {
+ "label": "Event end date (default now)",
+ "value": "end_date",
+ "type": "date",
+ "required": false,
+ "rows": null
+ },
+ {
+ "label": "Event end time",
+ "value": "end_time",
+ "type": "time",
+ "required": false,
+ "rows": null
+ }
+ ],
+ "formValue": {
+ "start_date": "",
+ "start_time": "",
+ "end_date": "",
+ "end_time": ""
+ },
+ "payload": "",
+ "submit": "submit",
+ "cancel": "clear",
+ "topic": "topic",
+ "topicType": "msg",
+ "splitLayout": "",
+ "className": "",
+ "x": 170,
+ "y": 660,
"wires": [
[
- "57fa6ca2b7d290e3"
+ "c45589c369c843a5",
+ "c25ade7ddaeca697"
]
]
},
{
- "id": "57fa6ca2b7d290e3",
+ "id": "c25ade7ddaeca697",
+ "type": "debug",
+ "z": "239d7b3ba410ad5e",
+ "g": "0e3b2be7bcc3d3b8",
+ "name": "debug: JSON events form input",
+ "active": false,
+ "tosidebar": true,
+ "console": false,
+ "tostatus": false,
+ "complete": "true",
+ "targetType": "full",
+ "statusVal": "",
+ "statusType": "auto",
+ "x": 1090,
+ "y": 660,
+ "wires": []
+ },
+ {
+ "id": "c45589c369c843a5",
"type": "function",
- "z": "28627559bebdc324",
- "g": "0e1614cf2e5f9942",
- "name": "structure 1-hour counts last day",
- "func": "//https://github.com/node-red/node-red-dashboard/blob/master/Charts.md\n//Array of Object with keys of series, data=x:ts,y:count, labels\n\nvar newMsg = [{}];\nnewMsg[0].series = [];\nnewMsg[0].data = [];\nnewMsg[0].label = [];\n\nmsg.payload.forEach((myItem) => {\n\n //if label doesn't exist, push it\n if (newMsg[0].series.indexOf(myItem.label) < 0) {\n newMsg[0].series.push(myItem.label);\n //create new data array element that matches the series index\n newMsg[0].data[newMsg[0].series.indexOf(myItem.label)] = [];\n }\n\n //Check if it's a new date or existing in data[0][0].x\n //datapoint for date \n let xIndex = newMsg[0].data[newMsg[0].series.indexOf(myItem.label)].findIndex((element) => element.x == String(new Date(myItem.bin_time)));\n if (xIndex < 0) {\n //new date\n let thisDataPoint = {};\n thisDataPoint.x = new Date(myItem.bin_time);\n thisDataPoint.y = myItem.count;\n newMsg[0].data[newMsg[0].series.indexOf(myItem.label)].push(thisDataPoint);\n }\n else {\n //date exists, sum counts\n newMsg[0].data[newMsg[0].series.indexOf(myItem.label)][xIndex].y += myItem.count;\n }\n\n});\n\nmsg.payload = newMsg;\n\nreturn msg;",
+ "z": "239d7b3ba410ad5e",
+ "g": "0e3b2be7bcc3d3b8",
+ "name": "create events query",
+ "func": "const newMsg = {};\nnewMsg.payload = {}; // contain everything going into a DB record, single record\n\n//create startDateTime, if no date, use 7 days ago, if no time, leave as default\nconst startDateTime = (msg.payload.start_date) ? new Date(msg.payload.start_date) : new Date(new Date().setDate(new Date().getDate() - 7));\nif (msg.payload.start_time) {\n const startTime = new Date(msg.payload.start_time);\n \n startDateTime.setTime(startTime.getTime());\n}\n\n//create endDateTime, if no date, use current date, if no time, leave as default\nconst endDateTime = (msg.payload.end_date) ? new Date(msg.payload.end_date) : new Date();\nif (msg.payload.end_time) {\n const endTime = new Date(msg.payload.end_time);\n\n endDateTime.setTime(endTime.getTime());\n}\n\nnewMsg.payload.startDateTime = startDateTime.getTime()/1000;\nnewMsg.payload.endDateTime = endDateTime.getTime()/1000;\n\nnewMsg.topic = \"SELECT * FROM events WHERE start_time >= '\"+ newMsg.payload.startDateTime +\"' AND end_time <= '\"+ newMsg.payload.endDateTime +\"';\";\n\nlet formatstartDateTime = new Date(newMsg.payload.startDateTime * 1000).toISOString();\nlet formatendDateTime = new Date(newMsg.payload.endDateTime * 1000).toISOString();\n\nnewMsg.template = `\n Generated Events JSON
\n Last generated:\n \n \n Start: | \n ${formatstartDateTime} | \n
\n \n End: | \n ${formatendDateTime} | \n
\n
\n \n`;\n\nreturn newMsg;\n",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
- "x": 410,
- "y": 1420,
+ "x": 590,
+ "y": 700,
"wires": [
[
- "11fa2826769befc7"
+ "44f3b2f2c2ae88fe"
]
- ]
+ ],
+ "info": "//to do each array item\n\nfor (const i in msg.payload.query_return_nonagg) {\n newMsg.payload.radar.push({\n type: \"DetectedObjectVelocity_nonagg_nodir\",\n result: msg.payload.query_return_nonagg[i]\n }\n );\n}"
},
{
- "id": "170ddffb726db9e0",
+ "id": "f31a598d.9fd2c8",
"type": "function",
- "z": "28627559bebdc324",
- "g": "453513c49e4b1b60",
- "name": "create sqlite query, daily cumulative counts in zone_capture",
- "func": "//frame_time is already in seconds\n\nconst query = `\nSELECT\n label,\n COUNT(*) as count\nFROM\n events\nWHERE\n frame_time >= unixepoch(strftime('%Y-%m-%dT04:00','now', 'localtime'),'utc')\n AND camera = '${env.get(\"VAR_RADAR_CAMERA\")}'\n AND entered_zones LIKE '%zone_capture%'\nGROUP BY \n label\nORDER BY\n label;\n`;\n\nmsg.topic = query;\nreturn msg;",
- "outputs": 1,
- "timeout": 0,
+ "z": "239d7b3ba410ad5e",
+ "g": "81c973dcdca1a4f0",
+ "name": "Set base path",
+ "func": "//restrict to c:\\temp\\\nvar basePath = \"/db/\";\nvar filename = msg.req.params.fn;\n\n\nif(filename.includes(\"..\\\\\")){\n msg.payload = \"Illegal file path\";\n msg.statusCode = 405;//not allowed\n return [null, msg];//fire output 2\n} else if(filename.includes(\"../\")){\n msg.payload = \"Illegal file path\";\n msg.statusCode = 405;//not allowed\n return [null, msg];//fire output 2\n} \n//TODO: add more checks\n\nmsg.filename = basePath + filename;\nreturn [msg, null];//fire output 1\n\n\n",
+ "outputs": 2,
+ "timeout": "",
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
- "x": 600,
- "y": 2280,
+ "x": 280,
+ "y": 360,
"wires": [
[
- "befe91e6862c72db"
+ "34dc99e5.495466"
+ ],
+ [
+ "98261154.3006"
]
]
},
{
- "id": "befe91e6862c72db",
- "type": "sqlite",
- "z": "28627559bebdc324",
- "g": "453513c49e4b1b60",
- "mydb": "2f60c1ab30a6fc8f",
- "sqlquery": "msg.topic",
- "sql": "",
+ "id": "98261154.3006",
+ "type": "http response",
+ "z": "239d7b3ba410ad5e",
+ "g": "81c973dcdca1a4f0",
"name": "",
- "x": 740,
- "y": 2320,
+ "statusCode": "",
+ "headers": {},
+ "x": 630,
+ "y": 400,
+ "wires": []
+ },
+ {
+ "id": "34dc99e5.495466",
+ "type": "file in",
+ "z": "239d7b3ba410ad5e",
+ "g": "81c973dcdca1a4f0",
+ "name": "",
+ "filename": "filename",
+ "filenameType": "msg",
+ "format": "",
+ "chunk": false,
+ "sendError": false,
+ "encoding": "none",
+ "x": 470,
+ "y": 340,
"wires": [
[
- "13a061996f9322f3",
- "98571c77b9801a83"
+ "98261154.3006"
]
]
},
{
- "id": "13a061996f9322f3",
- "type": "function",
- "z": "28627559bebdc324",
- "g": "453513c49e4b1b60",
- "name": "structure daily object counts for chart",
- "func": "//https://github.com/node-red/node-red-dashboard/blob/master/Charts.md\n//Array of Object with keys of series, data=x:ts,y:count, labels\n\n\n//create bicycle_adj to be bicycle+motorcycle\n//create person_adj to be person - bicycle_adj\n\nconst motorcycleCount = msg.payload.find(item => item.label === 'motorcycle')?.count || 0;\nconst bicycleCount = msg.payload.find(item => item.label === 'bicycle')?.count || 0;\nconst personCount = msg.payload.find(item => item.label === 'person')?.count || 0;\n\nconst formattedData = [{\n series: [...msg.payload.map(item => item.label), 'bicycle_adj', 'person_adj'],\n data: [\n ...(msg.payload.map(item => [item.count])),\n [bicycleCount + motorcycleCount],\n [personCount - (bicycleCount + motorcycleCount)]\n ],\n labels: [\"\"]\n}];\n\nmsg.payload = formattedData;\n\nreturn msg;",
- "outputs": 1,
- "timeout": 0,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 770,
- "y": 2380,
+ "id": "38d65d59.1d8aa2",
+ "type": "catch",
+ "z": "239d7b3ba410ad5e",
+ "g": "81c973dcdca1a4f0",
+ "name": "",
+ "scope": null,
+ "uncaught": false,
+ "x": 100,
+ "y": 440,
"wires": [
[
- "6d738ed81fefbedc"
+ "3b8014a.86ad8ec",
+ "5b18a8e7.fb8da8"
]
]
},
{
- "id": "98571c77b9801a83",
+ "id": "3b8014a.86ad8ec",
"type": "function",
- "z": "28627559bebdc324",
- "g": "453513c49e4b1b60",
- "name": "structure daily object counts for tm/events",
- "func": "//send as key:value pair for lable:count\n\n//create bicycle_adj to be bicycle+motorcycle\n//create person_adj to be person - bicycle_adj\n\n\n\nconst motorcycleCount = msg.payload.find(item => item.label === 'motorcycle')?.count || 0;\nconst bicycleCount = msg.payload.find(item => item.label === 'bicycle')?.count || 0;\nconst personCount = msg.payload.find(item => item.label === 'person')?.count || 0;\n\nconst formattedData = msg.payload.reduce((acc, curr) => {\n acc[curr.label] = curr.count;\n\n if (curr.label === 'bicycle') {\n acc['bicycle_adj'] = (bicycleCount + motorcycleCount);\n }\n\n if (curr.label === 'person') {\n acc['person_adj'] = (personCount - (bicycleCount + motorcycleCount));\n }\n\n return acc;\n}, {});\n\nformattedData['event_latest'] = flow.get(\"event_latest\");\n\nmsg.payload = formattedData;\n\nreturn msg;",
+ "z": "239d7b3ba410ad5e",
+ "g": "81c973dcdca1a4f0",
+ "name": "Set 404",
+ "func": "msg.payload = msg.error;\nmsg.statusCode = 404;//resource not found\nreturn msg;",
"outputs": 1,
- "timeout": 0,
"noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 780,
- "y": 2420,
+ "x": 480,
+ "y": 440,
"wires": [
[
- "d856c68660eb2202"
+ "98261154.3006"
]
]
},
{
- "id": "584504e6c8935eaf",
- "type": "function",
- "z": "28627559bebdc324",
- "g": "1bd1f21fa0390c69",
- "name": "create sqlite query, daily cumulative CAR counts in zone_capture + zone_radar that HAVE valid speed_calc",
- "func": "//frame_time is already in seconds\n//cars with speeds in zone_radar AND zone_capture since 0400 today\n\nconst query = `\nWITH results AS (\n SELECT \n COUNT(*) AS count,\n AVG(ABS(speed_calc)) AS mean_speed,\n MAX(CASE WHEN ntile = 5 THEN ABS(speed_calc) ELSE NULL END) AS p25_speed,\n MAX(CASE WHEN ntile = 10 THEN ABS(speed_calc) ELSE NULL END) AS p50_speed,\n MAX(CASE WHEN ntile = 15 THEN ABS(speed_calc) ELSE NULL END) AS p75_speed,\n MAX(CASE WHEN ntile = 17 THEN ABS(speed_calc) ELSE NULL END) AS p85_speed,\n MAX(ABS(speed_calc)) AS max_speed,\n SUM(CASE WHEN ABS(speed_calc) > 25 THEN 1 ELSE 0 END) AS count_over_25,\n JSON_GROUP_ARRAY(speed_calc) AS speeds\n FROM \n (SELECT \n ABS(speed_calc) as speed_calc,\n NTILE(20) OVER (ORDER BY ABS(speed_calc)) AS ntile\n FROM \n events\n WHERE \n frame_time >= unixepoch(strftime('%Y-%m-%dT04:00','now', 'localtime'),'utc') AND\n label = 'car' AND\n entered_zones LIKE '%zone_radar%' AND\n entered_zones LIKE '%zone_capture%' AND\n ABS(speed_calc) NOT NULL AND\n camera = '${env.get(\"VAR_RADAR_CAMERA\")}'\n )\n)\nSELECT \n *, \n p75_speed + 1.5 * (p75_speed - p25_speed) AS iqr_upper,\n (SELECT COUNT(*) FROM json_each(results.speeds) WHERE json_each.value > p75_speed + 1.5 * (p75_speed - p25_speed)) AS iqr_upper_freq\nFROM \n results;\n`;\n\nmsg.topic = query;\nreturn msg;",
- "outputs": 1,
- "timeout": 0,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 470,
- "y": 2620,
+ "id": "5b18a8e7.fb8da8",
+ "type": "debug",
+ "z": "239d7b3ba410ad5e",
+ "g": "81c973dcdca1a4f0",
+ "name": "",
+ "active": true,
+ "tosidebar": true,
+ "console": false,
+ "tostatus": false,
+ "complete": "true",
+ "targetType": "full",
+ "x": 130,
+ "y": 480,
+ "wires": []
+ },
+ {
+ "id": "5de7cbb4.fa21a4",
+ "type": "comment",
+ "z": "239d7b3ba410ad5e",
+ "g": "81c973dcdca1a4f0",
+ "name": "Create http endpoint /files/xxx where xxx is the file name to download",
+ "info": "",
+ "x": 320,
+ "y": 300,
+ "wires": []
+ },
+ {
+ "id": "67ecfa7f.3f0e24",
+ "type": "http in",
+ "z": "239d7b3ba410ad5e",
+ "g": "81c973dcdca1a4f0",
+ "name": "",
+ "url": "/files/:fn",
+ "method": "get",
+ "upload": false,
+ "swaggerDoc": "",
+ "x": 110,
+ "y": 360,
"wires": [
[
- "9cf49f0891d25df1"
+ "f31a598d.9fd2c8"
]
]
},
{
- "id": "9cf49f0891d25df1",
+ "id": "7050ed881890ce4d",
+ "type": "comment",
+ "z": "239d7b3ba410ad5e",
+ "g": "0e3b2be7bcc3d3b8",
+ "name": "enable download link",
+ "info": "",
+ "x": 360,
+ "y": 740,
+ "wires": []
+ },
+ {
+ "id": "f2bd56710ba03238",
"type": "sqlite",
- "z": "28627559bebdc324",
- "g": "1bd1f21fa0390c69",
+ "z": "239d7b3ba410ad5e",
+ "g": "0e3b2be7bcc3d3b8",
"mydb": "2f60c1ab30a6fc8f",
"sqlquery": "msg.topic",
"sql": "",
"name": "",
- "x": 760,
- "y": 2660,
+ "x": 860,
+ "y": 840,
"wires": [
[
- "6d81c8e3c89b68f6"
+ "b4e0b45a7bedd728"
]
]
},
{
- "id": "432a378bcc3e7a73",
- "type": "comment",
- "z": "28627559bebdc324",
- "name": "TODO: show cars w NULL speed_calc, ...",
- "info": "",
- "x": 220,
- "y": 2900,
+ "id": "ecb0810a22dc4a5c",
+ "type": "inject",
+ "z": "239d7b3ba410ad5e",
+ "g": "0e3b2be7bcc3d3b8",
+ "name": "",
+ "props": [
+ {
+ "p": "payload"
+ },
+ {
+ "p": "topic",
+ "vt": "str"
+ }
+ ],
+ "repeat": "",
+ "crontab": "",
+ "once": false,
+ "onceDelay": 0.1,
+ "topic": "",
+ "payload": "",
+ "payloadType": "date",
+ "x": 120,
+ "y": 740,
+ "wires": [
+ [
+ "c45589c369c843a5"
+ ]
+ ]
+ },
+ {
+ "id": "b4e0b45a7bedd728",
+ "type": "file",
+ "z": "239d7b3ba410ad5e",
+ "g": "0e3b2be7bcc3d3b8",
+ "name": "",
+ "filename": "/db/events.json",
+ "filenameType": "str",
+ "appendNewline": false,
+ "createDir": false,
+ "overwriteFile": "true",
+ "encoding": "none",
+ "x": 1020,
+ "y": 840,
+ "wires": [
+ []
+ ]
+ },
+ {
+ "id": "5124f45846b94ef0",
+ "type": "ui_toast",
+ "z": "239d7b3ba410ad5e",
+ "g": "0e3b2be7bcc3d3b8",
+ "position": "top right",
+ "displayTime": "5",
+ "highlight": "",
+ "sendall": false,
+ "outputs": 0,
+ "ok": "OK",
+ "cancel": "",
+ "raw": true,
+ "className": "",
+ "topic": "Events JSON output created (download available)",
+ "name": "",
+ "x": 1180,
+ "y": 780,
"wires": []
},
{
- "id": "6d81c8e3c89b68f6",
+ "id": "82073a9c3e0f504f",
"type": "function",
- "z": "28627559bebdc324",
- "g": "1bd1f21fa0390c69",
- "name": "format payload for car speed daily",
- "func": "\nconst originalPayload = msg.payload;\n\nconst convertedPayload = Object.keys(originalPayload[0])\n .filter(key => key !== \"speeds\")\n .map(key => {\n const value = originalPayload[0][key];\n return { [key]: typeof value === \"number\" ? Math.round(value) : value };\n });\n\nmsg.payload = convertedPayload;\n\nreturn msg;",
+ "z": "239d7b3ba410ad5e",
+ "g": "0e3b2be7bcc3d3b8",
+ "name": "format events creation notification",
+ "func": "const newMsg = {};\nnewMsg.payload = {}; // contain everything going into a DB record, single record\n\nlet startDateTime = new Date(msg.payload.startDateTime * 1000).toISOString();\nlet endDateTime = new Date(msg.payload.endDateTime * 1000).toISOString();\n\nnewMsg.topic = \"Created events.json withing DateTimes
\"\nnewMsg.payload = \"Start: \" + startDateTime + \"
End: \" + endDateTime +\"
\";\n\nreturn newMsg;",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
- "x": 740,
- "y": 2720,
+ "x": 940,
+ "y": 780,
"wires": [
[
- "5417aae0d14fa661"
+ "5124f45846b94ef0"
]
]
},
{
- "id": "6a05187a692bed7c",
+ "id": "38b44ecb9288caf2",
"type": "ui_form",
"z": "239d7b3ba410ad5e",
- "g": "541d31d14bcd8b00",
+ "g": "1bfaaf118f38aee0",
"name": "",
- "label": "Create date-sensitive comments about the Traffic Monitor status, deployment, location, conditions, construction, etc.",
- "group": "d3f63882e39b03a6",
+ "label": "Generate Radar JSON",
+ "group": "f0ca9c7dffb5ae3c",
"order": 1,
"width": 0,
"height": 0,
"options": [
{
- "label": "Effective Date (start of comment period)",
- "value": "effective_date",
+ "label": "Radar start date (default 7-days ago)",
+ "value": "start_date",
"type": "date",
"required": false,
"rows": null
},
{
- "label": "Effective Time",
- "value": "effective_time",
+ "label": "Radar start time",
+ "value": "start_time",
"type": "time",
"required": false,
"rows": null
},
{
- "label": "Expiration Date (end of comment period)",
- "value": "expiration_date",
+ "label": "Radar end date (default now)",
+ "value": "end_date",
"type": "date",
"required": false,
"rows": null
},
{
- "label": "Expiration Time",
- "value": "expiration_time",
+ "label": "Radar end time",
+ "value": "end_time",
"type": "time",
"required": false,
"rows": null
- },
- {
- "label": "Comment",
- "value": "comment",
- "type": "multiline",
- "required": false,
- "rows": 3
- },
- {
- "label": "Commenter Name (or description)",
- "value": "name",
- "type": "text",
- "required": false,
- "rows": null
}
],
"formValue": {
- "effective_date": "",
- "effective_time": "",
- "expiration_date": "",
- "expiration_time": "",
- "comment": "",
- "name": ""
+ "start_date": "",
+ "start_time": "",
+ "end_date": "",
+ "end_time": ""
},
"payload": "",
"submit": "submit",
@@ -3676,22 +4640,22 @@
"topicType": "msg",
"splitLayout": "",
"className": "",
- "x": 430,
- "y": 60,
+ "x": 160,
+ "y": 960,
"wires": [
[
- "fee2d22032a11056",
- "8d65b604e8d9e7f9"
+ "91cae91e61fcea38",
+ "55b8ab3b2b7af294"
]
]
},
{
- "id": "fee2d22032a11056",
+ "id": "55b8ab3b2b7af294",
"type": "debug",
"z": "239d7b3ba410ad5e",
- "g": "541d31d14bcd8b00",
- "name": "debug: comment form input",
- "active": true,
+ "g": "1bfaaf118f38aee0",
+ "name": "debug: JSON radar form input",
+ "active": false,
"tosidebar": true,
"console": false,
"tostatus": false,
@@ -3699,34 +4663,59 @@
"targetType": "full",
"statusVal": "",
"statusType": "auto",
- "x": 1020,
- "y": 60,
+ "x": 1050,
+ "y": 960,
"wires": []
},
{
- "id": "f27b6d01ae7836d6",
+ "id": "790a89794204c383",
+ "type": "function",
+ "z": "239d7b3ba410ad5e",
+ "g": "1bfaaf118f38aee0",
+ "name": "create radar_dov query",
+ "func": "msg.topic = \"SELECT * FROM radar_dov WHERE time >= '\"+ msg.payload.startDateTime +\"' AND time <= '\"+ msg.payload.endDateTime +\"';\";\n\nreturn msg;\n",
+ "outputs": 1,
+ "timeout": 0,
+ "noerr": 0,
+ "initialize": "",
+ "finalize": "",
+ "libs": [],
+ "x": 590,
+ "y": 1140,
+ "wires": [
+ [
+ "314a302b5d86fb5a"
+ ]
+ ],
+ "info": "//to do each array item\n\nfor (const i in msg.payload.query_return_nonagg) {\n newMsg.payload.radar.push({\n type: \"DetectedObjectVelocity_nonagg_nodir\",\n result: msg.payload.query_return_nonagg[i]\n }\n );\n}"
+ },
+ {
+ "id": "314a302b5d86fb5a",
"type": "sqlite",
"z": "239d7b3ba410ad5e",
- "g": "541d31d14bcd8b00",
- "mydb": "2f60c1ab30a6fc8f",
+ "g": "1bfaaf118f38aee0",
+ "mydb": "1d8d8c9a28569355",
"sqlquery": "msg.topic",
"sql": "",
"name": "",
- "x": 580,
- "y": 180,
+ "x": 960,
+ "y": 1140,
"wires": [
[
- "840802d34d143ded"
+ "7dba386e57337c72"
]
]
},
{
- "id": "8f0bcaf04756da4f",
+ "id": "b00e6ad2a4612cad",
"type": "inject",
"z": "239d7b3ba410ad5e",
- "g": "541d31d14bcd8b00",
- "name": "create table comments",
+ "g": "1bfaaf118f38aee0",
+ "name": "",
"props": [
+ {
+ "p": "payload"
+ },
{
"p": "topic",
"vt": "str"
@@ -3734,391 +4723,488 @@
],
"repeat": "",
"crontab": "",
- "once": true,
+ "once": false,
"onceDelay": 0.1,
- "topic": "CREATE TABLE IF NOT EXISTS comments (effectiveDateTime TIMESTAMP, expirationDateTime TIMESTAMP, entryDateTime TIMESTAMP, comment TEXT, commenter_name TEXT);",
- "x": 360,
- "y": 180,
+ "topic": "",
+ "payload": "",
+ "payloadType": "date",
+ "x": 120,
+ "y": 1040,
"wires": [
[
- "f27b6d01ae7836d6"
+ "91cae91e61fcea38"
]
]
},
{
- "id": "e8b8e45c4bc045d8",
- "type": "inject",
+ "id": "7dba386e57337c72",
+ "type": "file",
+ "z": "239d7b3ba410ad5e",
+ "g": "1bfaaf118f38aee0",
+ "name": "",
+ "filename": "/db/radar_dov.json",
+ "filenameType": "str",
+ "appendNewline": false,
+ "createDir": false,
+ "overwriteFile": "true",
+ "encoding": "none",
+ "x": 1130,
+ "y": 1140,
+ "wires": [
+ []
+ ]
+ },
+ {
+ "id": "04df9cb8c0753abb",
+ "type": "ui_toast",
+ "z": "239d7b3ba410ad5e",
+ "g": "1bfaaf118f38aee0",
+ "position": "top right",
+ "displayTime": "5",
+ "highlight": "",
+ "sendall": false,
+ "outputs": 0,
+ "ok": "OK",
+ "cancel": "",
+ "raw": true,
+ "className": "",
+ "topic": "Events JSON output created (download available)",
+ "name": "",
+ "x": 1140,
+ "y": 1080,
+ "wires": []
+ },
+ {
+ "id": "3557178575375eb6",
+ "type": "comment",
"z": "239d7b3ba410ad5e",
- "g": "541d31d14bcd8b00",
- "name": "select latest 5 rows from comments",
- "props": [
- {
- "p": "topic",
- "vt": "str"
- }
- ],
- "repeat": "",
- "crontab": "",
- "once": false,
- "onceDelay": 0.1,
- "topic": "SELECT * FROM comments ORDER BY entryDateTime DESC LIMIT 5;",
- "x": 320,
- "y": 220,
+ "g": "1bfaaf118f38aee0",
+ "name": "enable download link when generated",
+ "info": "",
+ "x": 210,
+ "y": 1080,
+ "wires": []
+ },
+ {
+ "id": "29583ca6de66fedf",
+ "type": "function",
+ "z": "239d7b3ba410ad5e",
+ "g": "1bfaaf118f38aee0",
+ "name": "format radar creation notification",
+ "func": "const newMsg = {};\nnewMsg.payload = {}; // contain everything going into a DB record, single record\n\nlet startDateTime = new Date(msg.payload.startDateTime * 1000).toISOString();\nlet endDateTime = new Date(msg.payload.endDateTime * 1000).toISOString();\n\nnewMsg.topic = \"Created radar.json withing DateTimes
\"\nnewMsg.payload = \"Start: \" + startDateTime + \"
End: \" + endDateTime +\"
\";\n\nreturn newMsg;",
+ "outputs": 1,
+ "timeout": 0,
+ "noerr": 0,
+ "initialize": "",
+ "finalize": "",
+ "libs": [],
+ "x": 910,
+ "y": 1080,
"wires": [
[
- "f27b6d01ae7836d6"
+ "04df9cb8c0753abb"
]
]
},
{
- "id": "840802d34d143ded",
- "type": "debug",
- "z": "239d7b3ba410ad5e",
- "g": "541d31d14bcd8b00",
- "name": "sqlite select last 5 comments",
- "active": true,
- "tosidebar": true,
- "console": false,
- "tostatus": false,
- "complete": "payload",
- "targetType": "msg",
- "statusVal": "",
- "statusType": "auto",
- "x": 1020,
- "y": 180,
- "wires": []
- },
- {
- "id": "8d65b604e8d9e7f9",
+ "id": "91cae91e61fcea38",
"type": "function",
"z": "239d7b3ba410ad5e",
- "g": "541d31d14bcd8b00",
- "name": "create comment payload",
- "func": "const newMsg = {};\nnewMsg.payload = {}; // contain everything going into a DB record, single record\n\n//create effectiveDateTime, if no date, use current date, if no time, leave as default\nconst effectiveDateTime = (msg.payload.effective_date) ? new Date(msg.payload.effective_date) : new Date();\nif (msg.payload.effective_time) {\n const effectiveTime = new Date(msg.payload.effective_time);\n \n effectiveDateTime.setTime(effectiveTime.getTime());\n}\n\n//create expirationDateTime, if no date, leave undefined\nconst expirationDateTime = (msg.payload.expiration_date) ? new Date(msg.payload.expiration_date) : undefined;\nif (msg.payload.expiration_time) {\n const expirationTime = new Date(msg.payload.expiration_time);\n\n expirationDateTime.setTime(expirationTime.getTime());\n}\n\n//create entryDateTime\nconst entryDateTime = new Date();\n\nnewMsg.payload.effectiveDateTime = effectiveDateTime;\nnewMsg.payload.expirationDateTime = expirationDateTime;\nnewMsg.payload.entryDateTime = entryDateTime;\nnewMsg.payload.comment = msg.payload.comment;\nnewMsg.payload.commenter_name = msg.payload.name;\n\n\nconst obj = newMsg.payload;\n\nconst keyedObj = Object.keys(obj).reduce((acc, key) => {\n acc[`$${key}`] = obj[key];\n return acc;\n}, {});\n\nnewMsg.params = keyedObj;\n\nreturn newMsg;\n",
+ "g": "1bfaaf118f38aee0",
+ "name": "create radar dates for query",
+ "func": "const newMsg = {};\nnewMsg.payload = {}; // contain everything going into a DB record, single record\n\n//create startDateTime, if no date, use 7 days ago, if no time, leave as default\nconst startDateTime = (msg.payload.start_date) ? new Date(msg.payload.start_date) : new Date(new Date().setDate(new Date().getDate() - 7));\nif (msg.payload.start_time) {\n const startTime = new Date(msg.payload.start_time);\n \n startDateTime.setTime(startTime.getTime());\n}\n\n//create endDateTime, if no date, use current date, if no time, leave as default\nconst endDateTime = (msg.payload.end_date) ? new Date(msg.payload.end_date) : new Date();\nif (msg.payload.end_time) {\n const endTime = new Date(msg.payload.end_time);\n\n endDateTime.setTime(endTime.getTime());\n}\n\nnewMsg.payload.startDateTime = startDateTime.getTime()/1000;\nnewMsg.payload.endDateTime = endDateTime.getTime() / 1000;\n\nlet formatstartDateTime = new Date(newMsg.payload.startDateTime * 1000).toISOString();\nlet formatendDateTime = new Date(newMsg.payload.endDateTime * 1000).toISOString();\n\nnewMsg.template = `\n Generated Radar JSON
\n Last generated:\n \n \n Start: | \n ${formatstartDateTime} | \n
\n \n End: | \n ${formatendDateTime} | \n
\n
\n \n`;\n\nreturn newMsg;\n",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
- "x": 350,
- "y": 120,
+ "x": 500,
+ "y": 1000,
"wires": [
[
- "db1f35650c8d6448"
+ "c00796fd5642dae0"
]
],
"info": "//to do each array item\n\nfor (const i in msg.payload.query_return_nonagg) {\n newMsg.payload.radar.push({\n type: \"DetectedObjectVelocity_nonagg_nodir\",\n result: msg.payload.query_return_nonagg[i]\n }\n );\n}"
},
{
- "id": "db1f35650c8d6448",
- "type": "sqlite",
+ "id": "68fecdfda8e4e774",
+ "type": "function",
"z": "239d7b3ba410ad5e",
- "g": "541d31d14bcd8b00",
- "mydb": "2f60c1ab30a6fc8f",
- "sqlquery": "prepared",
- "sql": "INSERT INTO comments (effectiveDateTime, expirationDateTime, entryDateTime, comment, commenter_name)\nVALUES ($effectiveDateTime, $expirationDateTime, $entryDateTime, $comment, $commenter_name);\n",
- "name": "tmdb.comments, Prepared Statement",
- "x": 670,
- "y": 120,
+ "g": "1bfaaf118f38aee0",
+ "name": "create radar_timed_speed_counts query",
+ "func": "msg.topic = \"SELECT * FROM radar_timed_speed_counts WHERE time >= '\"+ msg.payload.startDateTime +\"' AND time <= '\"+ msg.payload.endDateTime +\"';\";\n\nreturn msg;\n",
+ "outputs": 1,
+ "timeout": 0,
+ "noerr": 0,
+ "initialize": "",
+ "finalize": "",
+ "libs": [],
+ "x": 640,
+ "y": 1200,
"wires": [
- []
- ]
+ [
+ "8c660460752a27b2"
+ ]
+ ],
+ "info": "//to do each array item\n\nfor (const i in msg.payload.query_return_nonagg) {\n newMsg.payload.radar.push({\n type: \"DetectedObjectVelocity_nonagg_nodir\",\n result: msg.payload.query_return_nonagg[i]\n }\n );\n}"
},
{
- "id": "f43a276d3a899fe8",
- "type": "ui_form",
+ "id": "8c660460752a27b2",
+ "type": "sqlite",
"z": "239d7b3ba410ad5e",
- "g": "0e3b2be7bcc3d3b8",
+ "g": "1bfaaf118f38aee0",
+ "mydb": "1d8d8c9a28569355",
+ "sqlquery": "msg.topic",
+ "sql": "",
"name": "",
- "label": "Generate Events (as JSON) between dates (default 7 days ago to now)",
- "group": "c0886ba4111fbfae",
- "order": 2,
- "width": 0,
- "height": 0,
- "options": [
- {
- "label": "Event start date",
- "value": "start_date",
- "type": "date",
- "required": false,
- "rows": null
- },
- {
- "label": "Event start time",
- "value": "start_time",
- "type": "time",
- "required": false,
- "rows": null
- },
- {
- "label": "Event end date",
- "value": "end_date",
- "type": "date",
- "required": false,
- "rows": null
- },
- {
- "label": "Event end time",
- "value": "end_time",
- "type": "time",
- "required": false,
- "rows": null
- }
- ],
- "formValue": {
- "start_date": "",
- "start_time": "",
- "end_date": "",
- "end_time": ""
- },
- "payload": "",
- "submit": "submit",
- "cancel": "clear",
- "topic": "topic",
- "topicType": "msg",
- "splitLayout": "",
- "className": "",
- "x": 310,
- "y": 340,
+ "x": 960,
+ "y": 1200,
"wires": [
[
- "c25ade7ddaeca697",
- "c45589c369c843a5"
+ "d50d86038fe1af32"
]
]
},
{
- "id": "c25ade7ddaeca697",
- "type": "debug",
+ "id": "d50d86038fe1af32",
+ "type": "file",
"z": "239d7b3ba410ad5e",
- "g": "0e3b2be7bcc3d3b8",
- "name": "debug: JSON events form input",
- "active": false,
- "tosidebar": true,
- "console": false,
- "tostatus": false,
- "complete": "true",
- "targetType": "full",
- "statusVal": "",
- "statusType": "auto",
- "x": 1050,
- "y": 340,
- "wires": []
+ "g": "1bfaaf118f38aee0",
+ "name": "",
+ "filename": "/db/radar_timed_speed_counts.json",
+ "filenameType": "str",
+ "appendNewline": false,
+ "createDir": false,
+ "overwriteFile": "true",
+ "encoding": "none",
+ "x": 1180,
+ "y": 1200,
+ "wires": [
+ []
+ ]
},
{
- "id": "c45589c369c843a5",
+ "id": "b5e099e92ce27bf6",
"type": "function",
"z": "239d7b3ba410ad5e",
- "g": "0e3b2be7bcc3d3b8",
- "name": "create events query",
- "func": "const newMsg = {};\nnewMsg.payload = {}; // contain everything going into a DB record, single record\n\n//create startDateTime, if no date, use 7 days ago, if no time, leave as default\nconst startDateTime = (msg.payload.start_date) ? new Date(msg.payload.start_date) : new Date(new Date().setDate(new Date().getDate() - 7));\nif (msg.payload.start_time) {\n const startTime = new Date(msg.payload.start_time);\n \n startDateTime.setTime(startTime.getTime());\n}\n\n//create endDateTime, if no date, use current date, if no time, leave as default\nconst endDateTime = (msg.payload.end_date) ? new Date(msg.payload.end_date) : new Date();\nif (msg.payload.end_time) {\n const endTime = new Date(msg.payload.end_time);\n\n endDateTime.setTime(endTime.getTime());\n}\n\nnewMsg.payload.startDateTime = startDateTime.getTime()/1000;\nnewMsg.payload.endDateTime = endDateTime.getTime()/1000;\n\nnewMsg.topic = \"SELECT * FROM events WHERE start_time >= '\"+ newMsg.payload.startDateTime +\"' AND end_time <= '\"+ newMsg.payload.endDateTime +\"';\";\n\nreturn newMsg;\n",
+ "g": "1bfaaf118f38aee0",
+ "name": "create radar_raw_speed_magnitude query",
+ "func": "msg.topic = \"SELECT * FROM radar_raw_speed_magnitude WHERE time >= '\"+ msg.payload.startDateTime +\"' AND time <= '\"+ msg.payload.endDateTime +\"';\";\n\nreturn msg;\n",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
- "x": 390,
- "y": 380,
+ "x": 650,
+ "y": 1260,
"wires": [
[
- "f2bd56710ba03238",
- "82073a9c3e0f504f"
+ "f77b0f12f5047d25"
]
],
"info": "//to do each array item\n\nfor (const i in msg.payload.query_return_nonagg) {\n newMsg.payload.radar.push({\n type: \"DetectedObjectVelocity_nonagg_nodir\",\n result: msg.payload.query_return_nonagg[i]\n }\n );\n}"
},
{
- "id": "f31a598d.9fd2c8",
+ "id": "f77b0f12f5047d25",
+ "type": "sqlite",
+ "z": "239d7b3ba410ad5e",
+ "g": "1bfaaf118f38aee0",
+ "mydb": "1d8d8c9a28569355",
+ "sqlquery": "msg.topic",
+ "sql": "",
+ "name": "",
+ "x": 960,
+ "y": 1260,
+ "wires": [
+ [
+ "fbf290de9b7b858f"
+ ]
+ ],
+ "info": "//to do each array item\n\nfor (const i in msg.payload.query_return_nonagg) {\n newMsg.payload.radar.push({\n type: \"DetectedObjectVelocity_nonagg_nodir\",\n result: msg.payload.query_return_nonagg[i]\n }\n );\n}"
+ },
+ {
+ "id": "fbf290de9b7b858f",
+ "type": "file",
+ "z": "239d7b3ba410ad5e",
+ "g": "1bfaaf118f38aee0",
+ "name": "",
+ "filename": "/db/radar_raw_speed_magnitude.json",
+ "filenameType": "str",
+ "appendNewline": false,
+ "createDir": false,
+ "overwriteFile": "true",
+ "encoding": "none",
+ "x": 1190,
+ "y": 1260,
+ "wires": [
+ []
+ ]
+ },
+ {
+ "id": "35dd409613d47a60",
"type": "function",
"z": "239d7b3ba410ad5e",
- "g": "3a9bb6ed1306eb1c",
- "name": "Set base path",
- "func": "//restrict to c:\\temp\\\nvar basePath = \"/db/\";\nvar filename = msg.req.params.fn;\n\n\nif(filename.includes(\"..\\\\\")){\n msg.payload = \"Illegal file path\";\n msg.statusCode = 405;//not allowed\n return [null, msg];//fire output 2\n} else if(filename.includes(\"../\")){\n msg.payload = \"Illegal file path\";\n msg.statusCode = 405;//not allowed\n return [null, msg];//fire output 2\n} \n//TODO: add more checks\n\nmsg.filename = basePath + filename;\nreturn [msg, null];//fire output 1\n\n\n",
- "outputs": 2,
- "timeout": "",
+ "g": "1bfaaf118f38aee0",
+ "name": "create radar_raw_speed_magnitude_single query",
+ "func": "msg.topic = \"SELECT * FROM radar_raw_speed_magnitude_single WHERE time >= '\"+ msg.payload.startDateTime +\"' AND time <= '\"+ msg.payload.endDateTime +\"';\";\n\nreturn msg;\n",
+ "outputs": 1,
+ "timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
- "x": 520,
- "y": 680,
+ "x": 670,
+ "y": 1320,
"wires": [
[
- "34dc99e5.495466"
- ],
- [
- "98261154.3006"
+ "729b953264ce47aa"
]
- ]
+ ],
+ "info": "//to do each array item\n\nfor (const i in msg.payload.query_return_nonagg) {\n newMsg.payload.radar.push({\n type: \"DetectedObjectVelocity_nonagg_nodir\",\n result: msg.payload.query_return_nonagg[i]\n }\n );\n}"
},
{
- "id": "98261154.3006",
- "type": "http response",
+ "id": "729b953264ce47aa",
+ "type": "sqlite",
"z": "239d7b3ba410ad5e",
- "g": "3a9bb6ed1306eb1c",
+ "g": "1bfaaf118f38aee0",
+ "mydb": "1d8d8c9a28569355",
+ "sqlquery": "msg.topic",
+ "sql": "",
"name": "",
- "statusCode": "",
- "headers": {},
- "x": 870,
- "y": 720,
- "wires": []
+ "x": 960,
+ "y": 1320,
+ "wires": [
+ [
+ "23b1ba527419b29b"
+ ]
+ ]
},
{
- "id": "34dc99e5.495466",
- "type": "file in",
+ "id": "23b1ba527419b29b",
+ "type": "file",
"z": "239d7b3ba410ad5e",
- "g": "3a9bb6ed1306eb1c",
+ "g": "1bfaaf118f38aee0",
"name": "",
- "filename": "filename",
- "filenameType": "msg",
- "format": "",
- "chunk": false,
- "sendError": false,
+ "filename": "/db/radar_raw_speed_magnitude_single.json",
+ "filenameType": "str",
+ "appendNewline": false,
+ "createDir": false,
+ "overwriteFile": "true",
"encoding": "none",
- "x": 710,
- "y": 660,
+ "x": 1210,
+ "y": 1320,
"wires": [
- [
- "98261154.3006"
- ]
+ []
]
},
{
- "id": "38d65d59.1d8aa2",
- "type": "catch",
+ "id": "b519f0927284d44a",
+ "type": "function",
"z": "239d7b3ba410ad5e",
- "g": "3a9bb6ed1306eb1c",
- "name": "",
- "scope": null,
- "uncaught": false,
- "x": 340,
- "y": 760,
+ "g": "1bfaaf118f38aee0",
+ "name": "create radar_oc_payload query",
+ "func": "msg.topic = \"SELECT * FROM radar_oc_payload WHERE start_time >= '\"+ msg.payload.startDateTime +\"' AND end_time <= '\"+ msg.payload.endDateTime +\"';\";\n\nreturn msg;\n",
+ "outputs": 1,
+ "timeout": 0,
+ "noerr": 0,
+ "initialize": "",
+ "finalize": "",
+ "libs": [],
+ "x": 610,
+ "y": 1380,
"wires": [
[
- "3b8014a.86ad8ec",
- "5b18a8e7.fb8da8"
+ "2f3cc99c3c41ab90"
]
- ]
+ ],
+ "info": "//to do each array item\n\nfor (const i in msg.payload.query_return_nonagg) {\n newMsg.payload.radar.push({\n type: \"DetectedObjectVelocity_nonagg_nodir\",\n result: msg.payload.query_return_nonagg[i]\n }\n );\n}"
},
{
- "id": "3b8014a.86ad8ec",
- "type": "function",
+ "id": "2f3cc99c3c41ab90",
+ "type": "sqlite",
"z": "239d7b3ba410ad5e",
- "g": "3a9bb6ed1306eb1c",
- "name": "Set 404",
- "func": "msg.payload = msg.error;\nmsg.statusCode = 404;//resource not found\nreturn msg;",
- "outputs": 1,
- "noerr": 0,
- "x": 720,
- "y": 760,
+ "g": "1bfaaf118f38aee0",
+ "mydb": "1d8d8c9a28569355",
+ "sqlquery": "msg.topic",
+ "sql": "",
+ "name": "",
+ "x": 960,
+ "y": 1380,
"wires": [
[
- "98261154.3006"
+ "62e90c91d0238273"
]
]
},
{
- "id": "5b18a8e7.fb8da8",
- "type": "debug",
+ "id": "62e90c91d0238273",
+ "type": "file",
"z": "239d7b3ba410ad5e",
- "g": "3a9bb6ed1306eb1c",
+ "g": "1bfaaf118f38aee0",
"name": "",
- "active": true,
- "tosidebar": true,
- "console": false,
- "tostatus": false,
- "complete": "true",
- "targetType": "full",
- "x": 370,
- "y": 800,
- "wires": []
+ "filename": "/db/radar_oc_payload.json",
+ "filenameType": "str",
+ "appendNewline": false,
+ "createDir": false,
+ "overwriteFile": "true",
+ "encoding": "none",
+ "x": 1160,
+ "y": 1380,
+ "wires": [
+ []
+ ]
},
{
- "id": "a8c2985e.d23ad8",
+ "id": "6e2a152aecd929d3",
"type": "ui_template",
"z": "239d7b3ba410ad5e",
- "g": "3a9bb6ed1306eb1c",
- "group": "c0886ba4111fbfae",
- "name": "ui_temlplate - present download links on dashboard",
- "order": 0,
+ "g": "541d31d14bcd8b00",
+ "group": "d3f63882e39b03a6",
+ "name": "comments instructions",
+ "order": 1,
"width": 0,
"height": 0,
- "format": "Database Download Links
\n",
- "storeOutMessages": true,
- "fwdInMessages": true,
+ "format": " Create Comments
\nComments are date-sensitive entries about the Traffic Monitor status, deployment, location, conditions, construction, etc.\n
\n These comments do not directly impact any display or counts but may be used for downstream analysis. Do not include any personally identifiable information.\n
",
+ "storeOutMessages": false,
+ "fwdInMessages": false,
"resendOnRefresh": false,
"templateScope": "local",
"className": "",
- "x": 710,
- "y": 840,
+ "x": 140,
+ "y": 100,
"wires": [
[]
]
},
{
- "id": "5de7cbb4.fa21a4",
- "type": "comment",
+ "id": "c00796fd5642dae0",
+ "type": "ui_template",
"z": "239d7b3ba410ad5e",
- "g": "3a9bb6ed1306eb1c",
- "name": "Create http endpoint /files/xxx where xxx is the file name to download",
- "info": "",
+ "g": "1bfaaf118f38aee0",
+ "group": "f0ca9c7dffb5ae3c",
+ "name": "download Radar JSON",
+ "order": 2,
+ "width": 0,
+ "height": 0,
+ "format": "",
+ "storeOutMessages": true,
+ "fwdInMessages": true,
+ "resendOnRefresh": true,
+ "templateScope": "local",
+ "className": "",
"x": 560,
- "y": 620,
- "wires": []
+ "y": 1080,
+ "wires": [
+ [
+ "29583ca6de66fedf",
+ "790a89794204c383",
+ "68fecdfda8e4e774",
+ "b5e099e92ce27bf6",
+ "35dd409613d47a60",
+ "b519f0927284d44a"
+ ]
+ ]
},
{
- "id": "67ecfa7f.3f0e24",
- "type": "http in",
+ "id": "b43ee265985f0f56",
+ "type": "ui_ui_control",
"z": "239d7b3ba410ad5e",
- "g": "3a9bb6ed1306eb1c",
- "name": "",
- "url": "/files/:fn",
- "method": "get",
- "upload": false,
- "swaggerDoc": "",
- "x": 350,
- "y": 680,
+ "name": "control JSON download groups",
+ "events": "change",
+ "x": 1110,
+ "y": 460,
+ "wires": [
+ []
+ ]
+ },
+ {
+ "id": "44f3b2f2c2ae88fe",
+ "type": "ui_template",
+ "z": "239d7b3ba410ad5e",
+ "g": "0e3b2be7bcc3d3b8",
+ "group": "eab37b30ecd3f935",
+ "name": "download Events JSON",
+ "order": 2,
+ "width": 0,
+ "height": 0,
+ "format": "",
+ "storeOutMessages": true,
+ "fwdInMessages": true,
+ "resendOnRefresh": true,
+ "templateScope": "local",
+ "className": "",
+ "x": 630,
+ "y": 780,
"wires": [
[
- "f31a598d.9fd2c8"
+ "f2bd56710ba03238",
+ "82073a9c3e0f504f"
]
]
},
{
- "id": "7050ed881890ce4d",
- "type": "comment",
+ "id": "60bbb02aeab1379c",
+ "type": "ui_button",
"z": "239d7b3ba410ad5e",
- "g": "0e3b2be7bcc3d3b8",
- "name": "enable download link",
- "info": "",
- "x": 360,
- "y": 540,
- "wires": []
+ "name": "show events_json",
+ "group": "c0886ba4111fbfae",
+ "order": 5,
+ "width": 0,
+ "height": 0,
+ "passthru": false,
+ "label": "Generate Events JSON",
+ "tooltip": "",
+ "color": "",
+ "bgcolor": "",
+ "className": "",
+ "icon": "",
+ "payload": "{\"group\":{\"show\":[\"Database_Tab_Events_JSON_Generator\"]}}",
+ "payloadType": "json",
+ "topic": "",
+ "topicType": "str",
+ "x": 830,
+ "y": 460,
+ "wires": [
+ [
+ "b43ee265985f0f56"
+ ]
+ ]
},
{
- "id": "f2bd56710ba03238",
- "type": "sqlite",
+ "id": "0a1c47e427d83c4b",
+ "type": "ui_button",
"z": "239d7b3ba410ad5e",
- "g": "0e3b2be7bcc3d3b8",
- "mydb": "2f60c1ab30a6fc8f",
- "sqlquery": "msg.topic",
- "sql": "",
- "name": "",
- "x": 600,
- "y": 380,
+ "name": "show radar_json",
+ "group": "c0886ba4111fbfae",
+ "order": 6,
+ "width": 0,
+ "height": 0,
+ "passthru": false,
+ "label": "Generate Radar JSON",
+ "tooltip": "",
+ "color": "",
+ "bgcolor": "",
+ "className": "",
+ "icon": "",
+ "payload": "{\"group\":{\"show\":[\"Database_Tab_Radar_JSON_Generator\"]}}",
+ "payloadType": "json",
+ "topic": "",
+ "topicType": "str",
+ "x": 840,
+ "y": 500,
"wires": [
[
- "b4e0b45a7bedd728"
+ "b43ee265985f0f56"
]
]
},
{
- "id": "ecb0810a22dc4a5c",
+ "id": "4611d2864ef75f3c",
"type": "inject",
"z": "239d7b3ba410ad5e",
- "g": "0e3b2be7bcc3d3b8",
"name": "",
"props": [
{
@@ -4134,96 +5220,126 @@
"once": false,
"onceDelay": 0.1,
"topic": "",
- "payload": "",
- "payloadType": "date",
- "x": 120,
- "y": 380,
+ "payload": "{\"group\":{\"hide\":[\"Database_Tab_Events_JSON_Generator\",\"Database_Tab_Radar_JSON_Generator\"]}}",
+ "payloadType": "json",
+ "x": 870,
+ "y": 420,
"wires": [
[
- "c45589c369c843a5"
+ "b43ee265985f0f56"
]
]
},
{
- "id": "b4e0b45a7bedd728",
- "type": "file",
+ "id": "9e38989f2e13e4d7",
+ "type": "ui_button",
"z": "239d7b3ba410ad5e",
- "g": "0e3b2be7bcc3d3b8",
- "name": "",
- "filename": "/db/events.json",
- "filenameType": "str",
- "appendNewline": false,
- "createDir": false,
- "overwriteFile": "true",
- "encoding": "none",
- "x": 800,
- "y": 380,
+ "name": "hide JSON",
+ "group": "c0886ba4111fbfae",
+ "order": 7,
+ "width": 0,
+ "height": 0,
+ "passthru": false,
+ "label": "Hide JSON generators",
+ "tooltip": "",
+ "color": "",
+ "bgcolor": "",
+ "className": "",
+ "icon": "",
+ "payload": "{\"group\":{\"hide\":[\"Database_Tab_Events_JSON_Generator\",\"Database_Tab_Radar_JSON_Generator\"]}}",
+ "payloadType": "json",
+ "topic": "",
+ "topicType": "str",
+ "x": 850,
+ "y": 540,
+ "wires": [
+ [
+ "b43ee265985f0f56"
+ ]
+ ]
+ },
+ {
+ "id": "7ec49429a06e3bbf",
+ "type": "ui_template",
+ "z": "239d7b3ba410ad5e",
+ "group": "c0886ba4111fbfae",
+ "name": "download Radar DB",
+ "order": 3,
+ "width": 0,
+ "height": 0,
+ "format": "Radar database and tables
\n\n
radar.sqlite (entire database)
\n
\n - radar_dov
\n - radar_timed_speed_counts
\n - radar_raw_speed_magnitude
\n - radar_raw_speed_magnitude_single
\n - radar_oc_payload
\n
\n
",
+ "storeOutMessages": true,
+ "fwdInMessages": true,
+ "resendOnRefresh": false,
+ "templateScope": "local",
+ "className": "",
+ "x": 820,
+ "y": 320,
"wires": [
[]
]
},
{
- "id": "7318af62aa1dadcc",
- "type": "ui_text",
+ "id": "a8c2985e.d23ad8",
+ "type": "ui_template",
"z": "239d7b3ba410ad5e",
- "g": "0e3b2be7bcc3d3b8",
"group": "c0886ba4111fbfae",
+ "name": "download Events DB",
"order": 2,
"width": 0,
"height": 0,
- "name": "",
- "label": "{{msg.topic}}",
- "format": "{{msg.payload}}",
- "layout": "col-center",
+ "format": "Events database and tables
\n",
+ "storeOutMessages": true,
+ "fwdInMessages": true,
+ "resendOnRefresh": false,
+ "templateScope": "local",
"className": "",
- "style": false,
- "font": "",
- "fontSize": 16,
- "color": "#000000",
- "x": 770,
- "y": 440,
- "wires": []
+ "x": 820,
+ "y": 280,
+ "wires": [
+ []
+ ]
},
{
- "id": "5124f45846b94ef0",
- "type": "ui_toast",
+ "id": "2b95a63a76f28f09",
+ "type": "ui_template",
"z": "239d7b3ba410ad5e",
- "g": "0e3b2be7bcc3d3b8",
- "position": "top right",
- "displayTime": "5",
- "highlight": "",
- "sendall": false,
- "outputs": 0,
- "ok": "OK",
- "cancel": "",
- "raw": true,
+ "group": "c0886ba4111fbfae",
+ "name": "download DB instructions",
+ "order": 1,
+ "width": 0,
+ "height": 0,
+ "format": "Download databases
\nThe links below will download the entire Traffic Monitor device events and/or radar SQLite database(s) to your current browser. \n Each database will include events and/or radar readings only from this device while the Traffic Monitor was deployed and running.
",
+ "storeOutMessages": true,
+ "fwdInMessages": true,
+ "resendOnRefresh": false,
+ "templateScope": "local",
"className": "",
- "topic": "Events JSON output created (download available)",
- "name": "",
- "x": 800,
- "y": 480,
- "wires": []
+ "x": 830,
+ "y": 360,
+ "wires": [
+ []
+ ]
},
{
- "id": "82073a9c3e0f504f",
- "type": "function",
+ "id": "c30220553ae11805",
+ "type": "ui_template",
"z": "239d7b3ba410ad5e",
- "g": "0e3b2be7bcc3d3b8",
- "name": "format events creation notification",
- "func": "const newMsg = {};\nnewMsg.payload = {}; // contain everything going into a DB record, single record\n\nlet startDateTime = new Date(msg.payload.startDateTime * 1000).toISOString();\nlet endDateTime = new Date(msg.payload.endDateTime * 1000).toISOString();\n\nnewMsg.topic = \"Created events.json withing DateTimes
\"\nnewMsg.payload = \"Start: \" + startDateTime + \"
End: \" + endDateTime +\"
\";\n\nreturn newMsg;",
- "outputs": 1,
- "timeout": 0,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 540,
- "y": 440,
+ "group": "c0886ba4111fbfae",
+ "name": "json button instructions",
+ "order": 4,
+ "width": 0,
+ "height": 0,
+ "format": "Generate JSON payloads
\nYou may also generate selectable DateTime-constrained JSON payloads from events and/or radar database tables using the respective below buttons.
",
+ "storeOutMessages": true,
+ "fwdInMessages": true,
+ "resendOnRefresh": false,
+ "templateScope": "local",
+ "className": "",
+ "x": 1080,
+ "y": 360,
"wires": [
- [
- "7318af62aa1dadcc",
- "5124f45846b94ef0"
- ]
+ []
]
}
]
\ No newline at end of file
diff --git a/node-red-project/flows_cred.json b/node-red-project/flows_cred.json
index c826dec..d0f3c5c 100644
--- a/node-red-project/flows_cred.json
+++ b/node-red-project/flows_cred.json
@@ -1,3 +1,3 @@
{
- "$": "7c14d226dfda5a44369c0d90330c8956dmOsmbiG/YgoMeqy3EUt70ssIauuVbz6ty7YwwZ6dHabmt+jcxaZ+gNtARSAzEdysa9lXxv25Yl1V+FKsYVvvfHGDowhr9k8TMRgdrtttMBRCmm/HwoqVynYZHDeFq5vQgoqC9HPjp540NfnjC5SdUG28xhxOPRx7X/NXQHxMg/cwyOZC3Dxnsqo"
+ "$": "56eab62ef47ce014414dbdf38c1f0121ZXIyjsFukXyvUaUF9u/HYMa7VTi0FspfQEwTUdpL82tzZULZxA0KBbfYrwIN0QCDMEVr7on+DLtFE2nnoZ5ufNHwu1iHifa4UC9e/EgMEWalQR4Bp94="
}
\ No newline at end of file
diff --git a/node-red-project/package.json b/node-red-project/package.json
index 3940042..578ea2e 100644
--- a/node-red-project/package.json
+++ b/node-red-project/package.json
@@ -5,7 +5,6 @@
"dependencies": {
"node-red-contrib-aedes": "~0.13.0",
"node-red-contrib-image-output": "~0.6.4",
- "node-red-contrib-influxdb": "~0.7.0",
"node-red-dashboard": "~3.6.5",
"node-red-node-serialport": "~2.0.2",
"node-red-node-sqlite": "1.1.0",
diff --git a/script/console b/script/console
index 70153d0..93f3959 100644
--- a/script/console
+++ b/script/console
@@ -18,9 +18,6 @@ if [ -n "$1" ]; then
elif [ "$1" = "nodered" ]; then
#staging env
docker exec -ti nodered /bin/bash
- elif [ "$1" = "influxdb" ]; then
- #staging env
- docker exec -ti influxdb /bin/bash
else
echo "Sorry, I don't know how to connect to the '$1' environment."
exit 1
diff --git a/script/server b/script/server
index 161d765..1e07bde 100644
--- a/script/server
+++ b/script/server
@@ -18,5 +18,4 @@ sudo systemctl enable go2rtc_server
docker compose -f ~/code/compose.yaml up --detach
# access frigate via http://[IP]:5000
-# access to influxdb via http://[IP]:8086
# access node-red via http://[IP]:1880
\ No newline at end of file
diff --git a/script/setup b/script/setup
index 7fe0d5f..f42d9e3 100644
--- a/script/setup
+++ b/script/setup
@@ -37,12 +37,6 @@ cp -rp node-red-project/* ~/code/nodered/data/
##-- /node-red
-##-- Add influxDB Dockerfile
-mkdir -p ~/code/influxdb/data
-mkdir -p ~/code/influxdb/config
-cp docker-influxdb/docker-compose-influxdb.yaml ~/code/influxdb/docker-compose-influxdb.yml
-##-- /influxdb
-
#create backup directory
mkdir -p ~/code/backup
diff --git a/utils/backup.sh b/utils/backup.sh
index 6fbf0d8..accc7e3 100644
--- a/utils/backup.sh
+++ b/utils/backup.sh
@@ -11,16 +11,10 @@ cd "$(dirname "$0")/.."
cd ~/code/backup
-#influx creates a directory of zipped files
-docker exec influxdb influx backup /home/influxdb/backup/influxdb_bak
-sudo tar -cvzf influxdb_$(date '+%Y-%m-%d_%H-%M').tar.gz influxdb_bak
-sudo rm -rf influxdb_bak
-
#backup events database
tar -cvpzf events_sqlite_$(date '+%Y-%m-%d_%H-%M').tar.gz ~/code/nodered/data/tmdb
# transfer databases to server
-# sudo rsync -azvv --progress -e ssh ~/code/backup/influxdb_2024-06-21_11-29.tar.gz NAME@SERVER:DB_DUMPS/
# sudo rsync -azvv --progress -e ssh ~/code/backup/events_sqlite_2024-06-03_08-40.tar.gz NAME@SERVER:DB_DUMPS/
#-- Images backup -- only do this attached locally (maximize data transfer)