-
-
Save Love4yzp/2fccdfa6a2d8e64e2740cd566b9b991c to your computer and use it in GitHub Desktop.
NodeRED-Jetson Gun Detection Alert
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| [ | |
| { | |
| "id": "827a3420678b76d2", | |
| "type": "tab", | |
| "label": "Frigate Gun Detection", | |
| "disabled": false, | |
| "info": "" | |
| }, | |
| { | |
| "id": "config_frigate_url", | |
| "type": "inject", | |
| "z": "827a3420678b76d2", | |
| "name": "Config Frigate URL", | |
| "props": [ | |
| { | |
| "p": "frigateUrl", | |
| "v": "http://192.168.101.126:5000", | |
| "vt": "str" | |
| } | |
| ], | |
| "repeat": "", | |
| "crontab": "", | |
| "once": true, | |
| "onceDelay": 0.1, | |
| "topic": "", | |
| "x": 130, | |
| "y": 120, | |
| "wires": [ | |
| [ | |
| "config_saver" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "config_wechat_webhook", | |
| "type": "inject", | |
| "z": "827a3420678b76d2", | |
| "name": "Config Webhook", | |
| "props": [ | |
| { | |
| "p": "webhookUrl", | |
| "v": "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxxx35b8-1198-486a-aaec-xxxxb122fd35", | |
| "vt": "str" | |
| } | |
| ], | |
| "repeat": "", | |
| "crontab": "", | |
| "once": true, | |
| "onceDelay": 0.1, | |
| "topic": "", | |
| "x": 130, | |
| "y": 160, | |
| "wires": [ | |
| [ | |
| "config_saver" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "config_saver", | |
| "type": "function", | |
| "z": "827a3420678b76d2", | |
| "name": "Save Config to Global", | |
| "func": "// 获取旧状态\nlet oldFrigate = global.get(\"frigateUrl\");\nlet oldwebhook = global.get(\"webhookUrl\");\n\n// 更新全局变量\nif (msg.frigateUrl) {\n global.set(\"frigateUrl\", msg.frigateUrl);\n}\nif (msg.webhookUrl) {\n global.set(\"webhookUrl\", msg.webhookUrl);\n}\n\n// 读取当前状态\nlet frigate = global.get(\"frigateUrl\");\nlet webhook = global.get(\"webhookUrl\");\n\n// 生成状态文本\nlet statusParts = [];\nif (frigate) statusParts.push(\"Frigate ✅\");\nelse statusParts.push(\"Frigate ❌\");\n\nif (webhook) statusParts.push(\"webhook ✅\");\nelse statusParts.push(\"webhook ❌\");\n\nlet statusText = statusParts.join(\" | \");\n\n// 更新节点状态(绿色:都OK;黄色:部分缺;红色:都没配)\nlet color = \"red\";\nif (frigate && webhook) color = \"green\";\nelse if (frigate || webhook) color = \"yellow\";\n\nnode.status({ fill: color, shape: \"dot\", text: statusText });\n\n// 方便下游查看\nmsg.frigateUrl = frigate;\nmsg.webhookUrl = webhook;\nmsg.statusText = statusText;\n\nreturn msg;", | |
| "outputs": 1, | |
| "timeout": "", | |
| "noerr": 0, | |
| "initialize": "", | |
| "finalize": "", | |
| "libs": [], | |
| "x": 420, | |
| "y": 140, | |
| "wires": [ | |
| [] | |
| ] | |
| }, | |
| { | |
| "id": "709efb48944e7b98", | |
| "type": "mqtt in", | |
| "z": "827a3420678b76d2", | |
| "name": "Frigate Reviews", | |
| "topic": "frigate/reviews", | |
| "qos": "0", | |
| "datatype": "auto-detect", | |
| "broker": "0f948328c1975515", | |
| "nl": false, | |
| "rap": false, | |
| "inputs": 0, | |
| "x": 80, | |
| "y": 240, | |
| "wires": [ | |
| [ | |
| "28fa2bd8baf1f87b", | |
| "c840be7a3c85bf4d", | |
| "fab3af49ea18453d" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "28fa2bd8baf1f87b", | |
| "type": "function", | |
| "z": "827a3420678b76d2", | |
| "name": "Extract Gun Event", | |
| "func": "let after = msg.payload.after;\n\nif (!after || !after.data || !after.data.objects.includes(\"gun\")) {\n return null;\n}\n\nconst frigateUrl = global.get(\"frigateUrl\") || \"http://172.17.0.1:5000\";\nnode.log(\"Using FrigateUrl: \"+frigateUrl);\nlet count = flow.get(\"gun_count\") || 0;\ncount++;\nflow.set(\"gun_count\", count);\n\nlet history = flow.get(\"gun_history\") || [];\nhistory.unshift({\n camera: after.camera,\n start: new Date(after.start_time * 1000).toLocaleString(),\n end: after.end_time ? new Date(after.end_time * 1000).toLocaleString() : \"---\",\n thumb: frigateUrl + after.thumb_path.replace(\"/media/frigate\", \"\")\n});\nhistory = history.slice(0, 10);\nflow.set(\"gun_history\", history);\n\nmsg.payload = {\n camera: after.camera,\n start_time: new Date(after.start_time * 1000).toLocaleString(),\n end_time: after.end_time ? new Date(after.end_time * 1000).toLocaleString() : \"---\",\n thumb: frigateUrl + after.thumb_path.replace(\"/media/frigate\", \"\"),\n url: frigateUrl + after.thumb_path.replace(\"/media/frigate\", \"\"),\n count: count,\n};\n\nreturn msg;", | |
| "outputs": 1, | |
| "timeout": "", | |
| "noerr": 0, | |
| "initialize": "", | |
| "finalize": "", | |
| "libs": [], | |
| "x": 330, | |
| "y": 300, | |
| "wires": [ | |
| [ | |
| "6861bbcee3c4a09f", | |
| "bc22b4eb2e47f012", | |
| "c05e97b33779bd4a" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "319c9221c9a18dfc", | |
| "type": "ui-template", | |
| "z": "827a3420678b76d2", | |
| "group": "g1h2i3j4k5l6m7n8", | |
| "page": "", | |
| "ui": "", | |
| "name": "Gun Event Card", | |
| "order": 2, | |
| "width": "0", | |
| "height": "0", | |
| "format": "<template>\n <div v-if=\"msg && msg.payload\">\n <div v-for=\"(cam, name) in msg.payload\" :key=\"name\" style=\"margin-bottom:16px; padding:12px; border-radius:12px; box-shadow:0 2px 8px rgba(0,0,0,0.1); background:#fff;\">\n <h3 style=\"color:#0094CE;\">摄像头:{{ name }} </h3>\n <p style=\"font-size:14px; margin:0;\">\n <strong>开始:</strong>{{ cam.start }}<br>\n <strong>结束:</strong>{{ cam.end }}\n </p>\n <div :href=\"cam.thumb\" target=\"_blank\">\n <img :src=\"cam.thumb\" style=\"max-width:100%; border-radius:8px; cursor: zoom-in;\" />\n </div>\n </div>\n </div>\n <div v-else>\n <p>等待枪支检测数据...</p>\n </div>\n</template>\n\n<script>\nexport default {\n props: ['msg']\n}\n</script>\n", | |
| "storeOutMessages": true, | |
| "passthru": true, | |
| "templateScope": "local", | |
| "className": "", | |
| "x": 1020, | |
| "y": 160, | |
| "wires": [ | |
| [] | |
| ] | |
| }, | |
| { | |
| "id": "824bcb218744ed40", | |
| "type": "ui-text", | |
| "z": "827a3420678b76d2", | |
| "group": "g1h2i3j4k5l6m7n8", | |
| "order": 3, | |
| "width": "0", | |
| "height": "0", | |
| "name": "Gun Count", | |
| "label": "枪支检测次数", | |
| "format": "<span style='background:#ff4d4f; color:#fff; padding:4px 12px; border-radius:12px; font-weight:bold;'>{{msg.payload.count}}</span>", | |
| "layout": "", | |
| "style": false, | |
| "font": "", | |
| "fontSize": "", | |
| "color": "#000000", | |
| "wrapText": false, | |
| "className": "", | |
| "x": 1010, | |
| "y": 240, | |
| "wires": [] | |
| }, | |
| { | |
| "id": "6861bbcee3c4a09f", | |
| "type": "function", | |
| "z": "827a3420678b76d2", | |
| "name": "Gun Count Pass", | |
| "func": "msg.payload = msg.payload.count;\nreturn msg;", | |
| "outputs": 1, | |
| "timeout": "", | |
| "noerr": 0, | |
| "initialize": "", | |
| "finalize": "", | |
| "libs": [], | |
| "x": 620, | |
| "y": 240, | |
| "wires": [ | |
| [ | |
| "824bcb218744ed40" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "ab0188e1c37351c1", | |
| "type": "ui-table", | |
| "z": "827a3420678b76d2", | |
| "group": "g1h2i3j4k5l6m7n8", | |
| "name": "History Table", | |
| "label": "", | |
| "order": 4, | |
| "width": "0", | |
| "height": "0", | |
| "maxrows": "5", | |
| "autocols": false, | |
| "showSearch": true, | |
| "deselect": true, | |
| "selectionType": "none", | |
| "columns": [ | |
| { | |
| "title": "摄像头", | |
| "key": "camera", | |
| "keyType": "key", | |
| "type": "text", | |
| "width": "" | |
| }, | |
| { | |
| "title": "开始", | |
| "key": "start", | |
| "keyType": "key", | |
| "type": "text", | |
| "width": "" | |
| }, | |
| { | |
| "title": "结束", | |
| "key": "end", | |
| "keyType": "key", | |
| "width": "" | |
| }, | |
| { | |
| "title": "截图", | |
| "key": "thumb", | |
| "keyType": "key", | |
| "type": "image", | |
| "width": "", | |
| "align": "start" | |
| } | |
| ], | |
| "mobileBreakpoint": "sm", | |
| "mobileBreakpointType": "defaults", | |
| "action": "append", | |
| "x": 1010, | |
| "y": 360, | |
| "wires": [ | |
| [] | |
| ] | |
| }, | |
| { | |
| "id": "bc22b4eb2e47f012", | |
| "type": "function", | |
| "z": "827a3420678b76d2", | |
| "name": "get history from flow", | |
| "func": "msg.payload = flow.get(\"gun_history\") || [];\nreturn msg;", | |
| "outputs": 1, | |
| "timeout": 0, | |
| "noerr": 0, | |
| "initialize": "", | |
| "finalize": "", | |
| "libs": [], | |
| "x": 640, | |
| "y": 360, | |
| "wires": [ | |
| [ | |
| "ab0188e1c37351c1" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "c05e97b33779bd4a", | |
| "type": "function", | |
| "z": "827a3420678b76d2", | |
| "name": "prepare msg for alert", | |
| "func": "msg.payload = {\n \"msgtype\": \"text\",\n \"text\": {\n \"content\": msg.payload.camera + \"检测到枪支\"\n }\n}\nreturn msg;", | |
| "outputs": 1, | |
| "timeout": 0, | |
| "noerr": 0, | |
| "initialize": "", | |
| "finalize": "", | |
| "libs": [], | |
| "x": 640, | |
| "y": 300, | |
| "wires": [ | |
| [ | |
| "568e88e840e7b711" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "c840be7a3c85bf4d", | |
| "type": "function", | |
| "z": "827a3420678b76d2", | |
| "name": "to cameras", | |
| "func": "let after = msg.payload.after;\nif (!after || !after.data || !after.data.objects.includes(\"gun\")) return null;\n\nconst frigateUrl = global.get(\"frigateUrl\") || \"http://172.17.0.1:5000\";\n\n// 读取全局摄像头数据\nlet cameras = flow.get(\"camera_data\") || {};\n\ncameras[after.camera] = {\n start: new Date(after.start_time*1000).toLocaleString(),\n end: after.end_time ? new Date(after.end_time*1000).toLocaleString() : \"---\",\n thumb: frigateUrl + after.thumb_path.replace(\"/media/frigate\",\"\")\n};\n\n// 存回 Flow\nflow.set(\"camera_data\", cameras);\n\n// 传给 UI 模板渲染\nmsg.payload = cameras;\nreturn msg;\n", | |
| "outputs": 1, | |
| "timeout": 0, | |
| "noerr": 0, | |
| "initialize": "", | |
| "finalize": "", | |
| "libs": [], | |
| "x": 610, | |
| "y": 160, | |
| "wires": [ | |
| [ | |
| "319c9221c9a18dfc" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "c2c2f98f485df73b", | |
| "type": "ui-button", | |
| "z": "827a3420678b76d2", | |
| "group": "g1h2i3j4k5l6m7n8", | |
| "name": "clear", | |
| "label": "Clear All Data", | |
| "order": 0, | |
| "width": 0, | |
| "height": 0, | |
| "emulateClick": false, | |
| "tooltip": "", | |
| "color": "", | |
| "bgcolor": "", | |
| "className": "", | |
| "icon": "", | |
| "iconPosition": "left", | |
| "payload": "{}", | |
| "payloadType": "str", | |
| "topic": "topic", | |
| "topicType": "msg", | |
| "buttonColor": "", | |
| "textColor": "", | |
| "iconColor": "", | |
| "enableClick": true, | |
| "enablePointerdown": false, | |
| "pointerdownPayload": "", | |
| "pointerdownPayloadType": "str", | |
| "enablePointerup": false, | |
| "pointerupPayload": "", | |
| "pointerupPayloadType": "str", | |
| "x": 110, | |
| "y": 480, | |
| "wires": [ | |
| [ | |
| "1f42f64aaa7aab78" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "1f42f64aaa7aab78", | |
| "type": "function", | |
| "z": "827a3420678b76d2", | |
| "name": "clean all data in flow", | |
| "func": "flow.set(\"camera_data\", {});\nflow.set(\"gun_count\", 0);\nflow.set(\"gun_history\", []);\nreturn msg;", | |
| "outputs": 1, | |
| "timeout": 0, | |
| "noerr": 0, | |
| "initialize": "", | |
| "finalize": "", | |
| "libs": [], | |
| "x": 320, | |
| "y": 480, | |
| "wires": [ | |
| [ | |
| "22afdedff5a7e7fd", | |
| "beabb7e2f483249f", | |
| "44568dce857793da" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "22afdedff5a7e7fd", | |
| "type": "function", | |
| "z": "827a3420678b76d2", | |
| "name": "clean history", | |
| "func": "msg.payload = []\nreturn msg;", | |
| "outputs": 1, | |
| "timeout": 0, | |
| "noerr": 0, | |
| "initialize": "", | |
| "finalize": "", | |
| "libs": [], | |
| "x": 610, | |
| "y": 520, | |
| "wires": [ | |
| [ | |
| "ab0188e1c37351c1" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "beabb7e2f483249f", | |
| "type": "function", | |
| "z": "827a3420678b76d2", | |
| "name": "clean counter", | |
| "func": "msg.payload = 0\nreturn msg;", | |
| "outputs": 1, | |
| "timeout": 0, | |
| "noerr": 0, | |
| "initialize": "", | |
| "finalize": "", | |
| "libs": [], | |
| "x": 620, | |
| "y": 480, | |
| "wires": [ | |
| [ | |
| "824bcb218744ed40" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "44568dce857793da", | |
| "type": "function", | |
| "z": "827a3420678b76d2", | |
| "name": "clean snapshot", | |
| "func": "msg.payload = {}\nreturn msg;", | |
| "outputs": 1, | |
| "timeout": 0, | |
| "noerr": 0, | |
| "initialize": "", | |
| "finalize": "", | |
| "libs": [], | |
| "x": 620, | |
| "y": 440, | |
| "wires": [ | |
| [ | |
| "319c9221c9a18dfc" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "568e88e840e7b711", | |
| "type": "function", | |
| "z": "827a3420678b76d2", | |
| "name": "Send to WeChat", | |
| "func": "const webhook = global.get(\"wechatWebhook\") || \"https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxxx35b8-1198-486a-aaec-xxxxb122fd35\";\n\nmsg.url = webhook;\nmsg.method = \"POST\";\nmsg.headers = {\n \"Content-Type\": \"application/json\"\n};\n\nreturn msg;", | |
| "outputs": 1, | |
| "noerr": 0, | |
| "initialize": "", | |
| "finalize": "", | |
| "libs": [], | |
| "x": 850, | |
| "y": 300, | |
| "wires": [ | |
| [ | |
| "http_request_node" | |
| ] | |
| ] | |
| }, | |
| { | |
| "id": "http_request_node", | |
| "type": "http request", | |
| "z": "827a3420678b76d2", | |
| "name": "HTTP Request", | |
| "method": "use", | |
| "ret": "txt", | |
| "paytoqs": "ignore", | |
| "url": "", | |
| "tls": "", | |
| "persist": false, | |
| "proxy": "", | |
| "insecureHTTPParser": false, | |
| "authType": "", | |
| "senderr": false, | |
| "x": 1050, | |
| "y": 300, | |
| "wires": [ | |
| [] | |
| ] | |
| }, | |
| { | |
| "id": "fab3af49ea18453d", | |
| "type": "debug", | |
| "z": "827a3420678b76d2", | |
| "name": "debug 1", | |
| "active": true, | |
| "tosidebar": true, | |
| "console": false, | |
| "tostatus": false, | |
| "complete": "false", | |
| "statusVal": "", | |
| "statusType": "auto", | |
| "x": 280, | |
| "y": 400, | |
| "wires": [] | |
| }, | |
| { | |
| "id": "0f948328c1975515", | |
| "type": "mqtt-broker", | |
| "name": "", | |
| "broker": "172.17.0.1", | |
| "port": "1883", | |
| "clientid": "", | |
| "autoConnect": true, | |
| "usetls": false, | |
| "protocolVersion": "4", | |
| "keepalive": "15", | |
| "cleansession": true, | |
| "autoUnsubscribe": true, | |
| "birthTopic": "", | |
| "birthQos": "0", | |
| "birthPayload": "", | |
| "birthMsg": {}, | |
| "closeTopic": "", | |
| "closePayload": "", | |
| "closeMsg": {}, | |
| "willTopic": "", | |
| "willQos": "0", | |
| "willPayload": "", | |
| "willMsg": {}, | |
| "userProps": "", | |
| "sessionExpiry": "" | |
| }, | |
| { | |
| "id": "g1h2i3j4k5l6m7n8", | |
| "type": "ui-group", | |
| "name": "Frigate Events", | |
| "page": "h1i2j3k4l5m6n7o8", | |
| "width": "10", | |
| "height": "17", | |
| "order": 1, | |
| "showTitle": true, | |
| "className": "", | |
| "visible": "true", | |
| "disabled": "false", | |
| "groupType": "default" | |
| }, | |
| { | |
| "id": "h1i2j3k4l5m6n7o8", | |
| "type": "ui-page", | |
| "name": "Frigate Page", | |
| "ui": "f121584d21d465f1", | |
| "path": "/frigate", | |
| "icon": "", | |
| "layout": "grid", | |
| "theme": "6666b6af5668e7b2", | |
| "breakpoints": [ | |
| { | |
| "name": "Default", | |
| "px": "0", | |
| "cols": "3" | |
| }, | |
| { | |
| "name": "Tablet", | |
| "px": "576", | |
| "cols": "6" | |
| }, | |
| { | |
| "name": "Small Desktop", | |
| "px": "768", | |
| "cols": "9" | |
| }, | |
| { | |
| "name": "Desktop", | |
| "px": "1024", | |
| "cols": "12" | |
| } | |
| ], | |
| "order": 1, | |
| "className": "", | |
| "visible": "true", | |
| "disabled": "false" | |
| }, | |
| { | |
| "id": "f121584d21d465f1", | |
| "type": "ui-base", | |
| "name": "My Dashboard", | |
| "path": "/dashboard", | |
| "headerContent": "page", | |
| "titleBarStyle": "default", | |
| "showReconnectNotification": true, | |
| "notificationDisplayTime": 5, | |
| "showDisconnectNotification": true, | |
| "allowInstall": true | |
| }, | |
| { | |
| "id": "6666b6af5668e7b2", | |
| "type": "ui-theme", | |
| "name": "Default Theme", | |
| "colors": { | |
| "surface": "#ffffff", | |
| "primary": "#0094CE", | |
| "bgPage": "#eeeeee", | |
| "groupBg": "#ffffff", | |
| "groupOutline": "#cccccc" | |
| }, | |
| "sizes": { | |
| "density": "default", | |
| "pagePadding": "12px", | |
| "groupGap": "12px", | |
| "groupBorderRadius": "4px", | |
| "widgetGap": "12px" | |
| } | |
| }, | |
| { | |
| "id": "43cb0335dbddd3e7", | |
| "type": "global-config", | |
| "env": [], | |
| "modules": { | |
| "@flowfuse/node-red-dashboard": "1.29.0" | |
| } | |
| } | |
| ] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment