Video device monitoring - typically wifi ip-cameras

I have a situation maybe familiar to other users of wifi connected ip-cameras. Sometimes the connection to one or more is lost for a shorter or longer period. For various network related reasons. At least this happens to me periodically.

So what-to-do? I decided to monitor the connection status for each of my cameras. Using to-me-known and available nodes, it ended up in the very complex looking flow seen below. It works as expected and what I targeted but I would really appriciate very much any suggestion how I can reduce the number of nodes involved

The functionality is as follows:

My video system detects & sends a message when a camera gets connected (Camera found) and when it disconnects (Camera lost). That's great anyway but...I want in addition

  1. When a camera is lost I want NR to put that information on hold for a defined time
  2. If the camera is found in the meantime nothing should happen, the information put on hold shall just be resetted
  3. If the camera is lost longer than the defined time period, the information (Camera lost) shall be sent further, typically to a messaging service (like Telegram in my case)
  4. Once it is back, the information (Camera found) shall be sent

Below the test flow that I would like to simplify, reducing the number of nodes involved. At the very end below, my complete flow monitoring 8 cameras

[{"id":"910288c9.5f9b48","type":"trigger","z":"a5703ff7.1af6a","op1":"","op2":"","op1type":"nul","op2type":"pay","duration":"30","extend":false,"units":"s","reset":"","bytopic":"all","name":"","x":570,"y":330,"wires":[["b191be66.bc6c"]]},{"id":"1885c4fd.04d80b","type":"change","z":"a5703ff7.1af6a","name":"","rules":[{"t":"set","p":"reset","pt":"msg","to":"true","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":580,"y":390,"wires":[["910288c9.5f9b48"]]},{"id":"96656c40.2e642","type":"delay","z":"a5703ff7.1af6a","name":"","pauseType":"delay","timeout":"1","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":560,"y":450,"wires":[["1885c4fd.04d80b","50fe2dbc.ec8624"]]},{"id":"50fe2dbc.ec8624","type":"switch","z":"a5703ff7.1af6a","name":"","property":"'42'","propertyType":"flow","rules":[{"t":"eq","v":"","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":840,"y":450,"wires":[["b191be66.bc6c"]]},{"id":"48c5371d.736648","type":"change","z":"a5703ff7.1af6a","name":"","rules":[{"t":"set","p":"'42'","pt":"flow","to":"status.text","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":820,"y":390,"wires":[[]]},{"id":"2f6b0c6f.70ca74","type":"status","z":"a5703ff7.1af6a","name":"","scope":["910288c9.5f9b48"],"x":810,"y":330,"wires":[["48c5371d.736648"]]},{"id":"b191be66.bc6c","type":"debug","z":"a5703ff7.1af6a","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":1030,"y":230,"wires":[]},{"id":"209344f.28672bc","type":"inject","z":"a5703ff7.1af6a","name":"","topic":"","payload":"Camera lost","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":310,"y":330,"wires":[["910288c9.5f9b48"]]},{"id":"ce0d26d7.9f5fd8","type":"inject","z":"a5703ff7.1af6a","name":"","topic":"","payload":"Camera found","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":310,"y":450,"wires":[["96656c40.2e642"]]}]

You can reduce the number of nodes by utilizing msg.topic

[{"id":"4fb13027.ccb4b","type":"trigger","z":"64541c74.805804","op1":"","op2":"","op1type":"nul","op2type":"pay","duration":"31","extend":false,"units":"s","reset":"","bytopic":"topic","name":"","x":520,"y":300,"wires":[["9e501572.8f36c"]]},{"id":"8f70ac68.746bf","type":"change","z":"64541c74.805804","name":"","rules":[{"t":"set","p":"reset","pt":"msg","to":"true","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":455,"y":450,"wires":[["4fb13027.ccb4b"]]},{"id":"9e501572.8f36c","type":"debug","z":"64541c74.805804","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":695,"y":300,"wires":[]},{"id":"bfb3c4cb.0b4fc8","type":"inject","z":"64541c74.805804","name":"","topic":"cameras/camera1","payload":"Camera1 lost","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":180,"y":275,"wires":[["4fb13027.ccb4b"]]},{"id":"cb5f7ad8.098f38","type":"inject","z":"64541c74.805804","name":"","topic":"cameras/camera1","payload":"Camera1 found","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":190,"y":425,"wires":[["8f70ac68.746bf"]]},{"id":"961cafb3.9da1c8","type":"inject","z":"64541c74.805804","name":"","topic":"cameras/camera2","payload":"Camera2 lost","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":180,"y":325,"wires":[["4fb13027.ccb4b"]]},{"id":"1c18d309.e68e35","type":"inject","z":"64541c74.805804","name":"","topic":"cameras/camera2","payload":"Camera2 found","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":190,"y":475,"wires":[["8f70ac68.746bf"]]}]

I am not sure what the purpose of the flow variable is together with the switch node, so i have removed that part.

  1. If the camera is lost longer than the defined time period, the information (Camera lost) shall be sent further, typically to a messaging service (like Telegram in my case)

Can you not set the "defined time period" to +1s ?

Thanks a lot for looking into this!

I am not sure what the purpose of the flow variable is together with the switch node, so i have removed that part.

In your flow sample, this part is missing, my requirement number 4) will therefore not be satisfied and executed. Without this kind of control, the message "Camera found" is never sent

I used a status node and a flow variable for this control. I could not figure out a simpler way to check if the trigger node currently was triggered (holding a message) or not. The output of the status node is used to set a flow variable that is used by the switch node to check if the "Camera found" message shall be sent further or not

Isn't that a matter of connecting an output (debug) directly to "found" ?

Even more simplified (for many cameras)

[{"id":"8f73bb60.c4c68","type":"trigger","z":"4baa980b.619b4","op1":"","op2":"","op1type":"nul","op2type":"pay","duration":"31","extend":false,"units":"s","reset":"","bytopic":"topic","name":"","x":645,"y":275,"wires":[["63bddc82.3a4b2c"]]},{"id":"c3d8c193.dc5a18","type":"change","z":"4baa980b.619b4","name":"","rules":[{"t":"set","p":"reset","pt":"msg","to":"true","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":555,"y":175,"wires":[["8f73bb60.c4c68"]]},{"id":"63bddc82.3a4b2c","type":"debug","z":"4baa980b.619b4","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":820,"y":225,"wires":[]},{"id":"6921bde0.793964","type":"inject","z":"4baa980b.619b4","name":"","topic":"cameras/camera1","payload":"lost","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":175,"y":150,"wires":[["724da845.408a4"]]},{"id":"4ff1f130.c9d5d","type":"inject","z":"4baa980b.619b4","name":"","topic":"cameras/camera1","payload":"found","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":160,"y":250,"wires":[["724da845.408a4"]]},{"id":"d854836c.299fd8","type":"inject","z":"4baa980b.619b4","name":"","topic":"cameras/camera2","payload":"lost","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":175,"y":200,"wires":[["724da845.408a4"]]},{"id":"90618c.53ed1e78","type":"inject","z":"4baa980b.619b4","name":"","topic":"cameras/camera2","payload":"found","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":160,"y":300,"wires":[["724da845.408a4"]]},{"id":"724da845.408a4","type":"switch","z":"4baa980b.619b4","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"found","vt":"str"},{"t":"eq","v":"lost","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":400,"y":225,"wires":[["c3d8c193.dc5a18","63bddc82.3a4b2c"],["8f73bb60.c4c68"]]}]

No, your sample is still not working fully :wink:
The "found" message shall not be sent while the trigger node is triggered by the "lost" message

You are trying to avoid "bouncing" messages ?
In that case you can use the "extend delay if new message arrives" checkbox.

If that is the goal I would reduce it even further.

[{"id":"f64a48d7.c2b9f8","type":"trigger","z":"65434e0b.ee5b8","op1":"","op2":"","op1type":"nul","op2type":"payl","duration":"30","extend":true,"units":"s","reset":"","bytopic":"topic","name":"","x":420,"y":300,"wires":[["555f1438.fe3be4"]]},{"id":"555f1438.fe3be4","type":"debug","z":"65434e0b.ee5b8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":595,"y":300,"wires":[]},{"id":"9407db85.eb5718","type":"inject","z":"65434e0b.ee5b8","name":"","topic":"cameras/camera1","payload":"lost","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":175,"y":225,"wires":[["f64a48d7.c2b9f8"]]},{"id":"60106440.f106dc","type":"inject","z":"65434e0b.ee5b8","name":"","topic":"cameras/camera1","payload":"found","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":160,"y":325,"wires":[["f64a48d7.c2b9f8"]]},{"id":"8cc28247.af87f","type":"inject","z":"65434e0b.ee5b8","name":"","topic":"cameras/camera2","payload":"lost","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":175,"y":275,"wires":[["f64a48d7.c2b9f8"]]},{"id":"f7b5fea7.3cb058","type":"inject","z":"65434e0b.ee5b8","name":"","topic":"cameras/camera2","payload":"found","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":160,"y":375,"wires":[["f64a48d7.c2b9f8"]]}]

If that is not the goal, I don't understand the purpose.

Sort of, yes, but your latest sample is then not fulfilling my req 2)

When lost, the message is kept 30 s but if a found is arriving during that period, found is anyway sent when 30 s elapsed. And the found is also delayed 30 s (something I think can be accepted)

If it’s found within 30 s then use that to reset the triggers. Also pass it round the trigger so it may be passed straight away, but then into an RBE just before final output so it’s only sent if previous was a not found.

Yes, this works!
Instead of my initial using six nodes, now reduced to only using three for the same logic,
Thank you, now I can "tidy up" the flow...

[{"id":"d5a77533.112e68","type":"trigger","z":"a5703ff7.1af6a","op1":"","op2":"","op1type":"nul","op2type":"payl","duration":"30","extend":true,"units":"s","reset":"","bytopic":"topic","name":"","x":750,"y":630,"wires":[["29505231.907b6e"]]},{"id":"181870a7.45191f","type":"debug","z":"a5703ff7.1af6a","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":970,"y":750,"wires":[]},{"id":"147c9209.5618fe","type":"change","z":"a5703ff7.1af6a","name":"","rules":[{"t":"set","p":"reset","pt":"msg","to":"true","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":530,"y":690,"wires":[["d5a77533.112e68"]]},{"id":"29505231.907b6e","type":"rbe","z":"a5703ff7.1af6a","name":"","func":"rbe","gap":"","start":"","inout":"out","property":"payload","x":750,"y":750,"wires":[["181870a7.45191f"]]},{"id":"468292f8.16160c","type":"inject","z":"a5703ff7.1af6a","name":"","topic":"","payload":"Camera lost","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":310,"y":630,"wires":[["d5a77533.112e68"]]},{"id":"9173cb31.58cf08","type":"inject","z":"a5703ff7.1af6a","name":"","topic":"","payload":"Camera found","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":310,"y":750,"wires":[["147c9209.5618fe","29505231.907b6e"]]}]

I think both trigger and RBE can work per topic independently so that may be all you need

1 Like

Such a nice improvement!!!

This is all needed now compared to the huge & ugly initial solution. I could even have skipped the function node since it is just setting the topic based on the camera id that is part of the payload coming from the mqtt node (that would however require me to change a python script in multiple Pi's)

It's generic and can handle X number of camera id's without any further or future modification!

Thank you all, was a nice excercise in optimization

EDIT: I just saw that I configured the timeout to 10 s, a more realistic setting would be a few minutes or so I think

[{"id":"fd593f.6857d6c","type":"trigger","z":"6d2d6025.a2bb7","op1":"","op2":"","op1type":"nul","op2type":"payl","duration":"10","extend":true,"units":"s","reset":"","bytopic":"topic","name":"","x":790,"y":210,"wires":[["d740c19f.2b669"]]},{"id":"62bafa31.173954","type":"change","z":"6d2d6025.a2bb7","name":"","rules":[{"t":"set","p":"reset","pt":"msg","to":"true","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":790,"y":80,"wires":[["fd593f.6857d6c"]]},{"id":"d740c19f.2b669","type":"rbe","z":"6d2d6025.a2bb7","name":"","func":"rbe","gap":"","start":"","inout":"out","property":"payload","x":1000,"y":140,"wires":[["8bfd3841.66c1d8"]]},{"id":"bf7ea1a4.580bf","type":"mqtt in","z":"6d2d6025.a2bb7","name":"","topic":"motion","qos":"2","broker":"5e6a8bef.cd1ed4","x":130,"y":150,"wires":[["f0f19538.1a8b88"]]},{"id":"f0f19538.1a8b88","type":"function","z":"6d2d6025.a2bb7","name":"","func":"let m = msg.payload.split(' ');\nmsg.topic = m[2];\nreturn msg;","outputs":1,"noerr":0,"x":300,"y":150,"wires":[["9736bcfc.247d5"]]},{"id":"9736bcfc.247d5","type":"switch","z":"6d2d6025.a2bb7","name":"Camera lost or found","property":"payload","propertyType":"msg","rules":[{"t":"cont","v":"Camera found:","vt":"str"},{"t":"cont","v":"Camera lost:","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":520,"y":150,"wires":[["62bafa31.173954","d740c19f.2b669"],["fd593f.6857d6c"]]},{"id":"298a1a3a.b1e776","type":"comment","z":"6d2d6025.a2bb7","name":"Video device monitoring","info":"Video monitoring","x":180,"y":40,"wires":[]},{"id":"8bfd3841.66c1d8","type":"link out","z":"6d2d6025.a2bb7","name":"admin","links":["33f82faa.1e0ce"],"x":1125,"y":140,"wires":[],"inputLabels":["camera_lost"]},{"id":"5e6a8bef.cd1ed4","type":"mqtt-broker","z":"","broker":"127.0.0.1","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","willTopic":"","willQos":"0","willPayload":""}]
2 Likes

And now even better, replaced the function node with a change node and JSONata expression

A typical payload from the mqtt node is "Camera lost: 42" and similar

image