Node Red Stop Loop Timer

First off I’m totally new to Node Red so forgive me if the answer is obvious. I have several water leak detectors and I want to be notified via phone and Alexa when water is detected. I have all that figured out but want it to keep notifying me until the issue is rectified. I setup the loop timer which works great but what is an easy way to stop it when the leak detector is dry (state is false)?

I use a loop timer to turn a light in my morning routine off at sunrise once skies are clear. To achieve this, weather conditions are checked every fifteen minutes using a “Current State” node. The state is then passes through a function node. The function node uses a little logic to determines if the skies are clear and if so, turns off the light then sends a “STOP” command to the loop timer. Perhaps you could use a similar routine, replacing a check on weather conditions for a check in the state of the leak detector.

Code from the section of my “Morning Routine” that handles the loop timer is shown below. Hope it helps

[{"id":"6fb9a82c.7a5148","type":"time-range-switch","z":"3396837c.86304c","name":"Is sun above horizon?","lat":"43.388451","lon":"-80.994888","startTime":"sunrise","endTime":"sunsetStart","startOffset":"75","endOffset":"30","x":460,"y":280,"wires":[["36f4ec5a.b764a4"],["b6e0493c.5e3a08"]],"outputLabels":["Yes","No"]},{"id":"36f4ec5a.b764a4","type":"api-current-state","z":"3396837c.86304c","name":"Current Forecast","server":"fcf9b76b.256a88","version":2,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"weather.thermostat","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"x":730,"y":260,"wires":[["a85a3108.66f59"]]},{"id":"a85a3108.66f59","type":"function","z":"3396837c.86304c","name":"Do weather conditions necessitate lighting?","func":"if ((msg.payload === \"exceptional\") || (msg.payload === \"sunny\") || (msg.payload === \"partlycloudy\")) {\n    return [msg, null];\n}\nreturn [null, msg];","outputs":2,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1050,"y":260,"wires":[["d2204a6.d48b2b8"],["b6e0493c.5e3a08"]],"outputLabels":["No","Yes"],"info":"The weather platform only knows the below listed conditions. The reason for this is that for these conditions is an icon from Material Design Icons available and mapped in the frontend.\r\n\r\n‘clear-night’\r\n‘cloudy’\r\n‘fog’\r\n‘hail’\r\n‘lightning’\r\n‘lightning-rainy’\r\n‘partlycloudy’\r\n‘pouring’\r\n‘rainy’\r\n‘snowy’\r\n‘snowy-rainy’\r\n‘sunny’\r\n‘windy’\r\n‘windy-variant’\r\n‘exceptional’\r\n\r\n\r\n\r\ncondition: state\r\nentity_id: weather.thermostat\r\nattribute: forecast\r\nstate: sunny"},{"id":"b6e0493c.5e3a08","type":"api-call-service","z":"3396837c.86304c","name":"Turn desk lamp on","server":"fcf9b76b.256a88","version":3,"debugenabled":false,"service_domain":"switch","service":"turn_on","entityId":"switch.desk_lamp","data":"","dataType":"jsonata","mergecontext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":970,"y":340,"wires":[["ae67da4f.db8d88"]]},{"id":"ae67da4f.db8d88","type":"stoptimer","z":"3396837c.86304c","duration":"15","units":"Minute","payloadtype":"num","payloadval":"0","name":"Wait 15 minutes then recheck sun conditions.","x":1290,"y":340,"wires":[["6fb9a82c.7a5148"],[]]},{"id":"d2204a6.d48b2b8","type":"api-call-service","z":"3396837c.86304c","name":"Turn desk lamp off","server":"fcf9b76b.256a88","version":3,"debugenabled":false,"service_domain":"switch","service":"turn_off","entityId":"switch.desk_lamp","data":"","dataType":"jsonata","mergecontext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1410,"y":260,"wires":[["eca9e7af.c4ea68"]]},{"id":"eca9e7af.c4ea68","type":"change","z":"3396837c.86304c","name":"Stop Timer","rules":[{"t":"set","p":"payload","pt":"msg","to":"STOP","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":1630,"y":260,"wires":[["ae67da4f.db8d88"]]},{"id":"fcf9b76b.256a88","type":"server","name":"Home Assistant","version":1,"legacy":false,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true}]

The wait until nodes is waiting until the aqara water sensor is not wet. When it’s not wet, the flow ends. As long as it’s wet, the wait until node times out every 5 minutes looping the flow.

[{"id":"52613f39.5ebda","type":"server-state-changed","z":"6cd0b2f8.4bb6fc","name":"Aqara wet?","server":"9405c3fe.d0a6c","version":1,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityidfilter":"sensor.aqara_water_lear","entityidfiltertype":"exact","outputinitially":false,"state_type":"str","haltifstate":"wet","halt_if_type":"str","halt_if_compare":"is","outputs":2,"output_only_on_state_change":true,"for":0,"forType":"num","forUnits":"minutes","ignorePrevStateNull":false,"ignorePrevStateUnknown":false,"ignorePrevStateUnavailable":false,"ignoreCurrentStateUnknown":false,"ignoreCurrentStateUnavailable":false,"x":200,"y":900,"wires":[["31c6901a.67d55"],[]]},{"id":"31c6901a.67d55","type":"api-call-service","z":"6cd0b2f8.4bb6fc","name":"Notify","server":"9405c3fe.d0a6c","version":1,"debugenabled":false,"service_domain":"","service":"","entityId":"","data":"","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":390,"y":900,"wires":[["e65cad50.a3a9c"]]},{"id":"e65cad50.a3a9c","type":"ha-wait-until","z":"6cd0b2f8.4bb6fc","name":"Notify every 5 minutes while it's wet","server":"9405c3fe.d0a6c","outputs":2,"entityId":"sensor.aqara_water_lear","entityIdFilterType":"exact","property":"state","comparator":"is_not","value":"wet","valueType":"str","timeout":"5","timeoutType":"num","timeoutUnits":"minutes","entityLocation":"","entityLocationType":"none","checkCurrentState":true,"blockInputOverrides":true,"x":620,"y":960,"wires":[[],["31c6901a.67d55"]]},{"id":"9405c3fe.d0a6c","type":"server","name":"Home Assistant","addon":true}]

Thank you!

1 Like

Figured I’d share my leak detector notification flow that I built off this thread’s basic ideas. I wanted a centralized notification flow so I could easily add more sensors as needed.

This flow has a 5 min backoff after each round of notifications so I don’t get overwhelmed by some errant sensor. You need a “Leak Sensors” group containing all sensors’ binary_sensor values.

[{"id":"cc79f244762aa45f","type":"tab","label":"Leak","disabled":false,"info":"","env":[]},{"id":"141bbf58f22cfdf5","type":"api-call-service","z":"cc79f244762aa45f","name":"","server":"6897d4d.3c81f2c","version":5,"debugenabled":false,"domain":"notify","service":"gmail","areaId":[],"deviceId":[],"entityId":[],"data":"{    \t    \"title\": \"Leak detected: \"  & $.displayName,\t    \"message\": \"There is a leak on \" & $.displayName\t}","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":850,"y":60,"wires":[["7d771f6904109666"]]},{"id":"84c215adfd69e407","type":"server-state-changed","z":"cc79f244762aa45f","name":"Upstairs Bathroom Leak","server":"6897d4d.3c81f2c","version":4,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityidfilter":"binary_sensor.leak_bathroom_upstairs_aq1","entityidfiltertype":"exact","outputinitially":false,"state_type":"str","haltifstate":"on","halt_if_type":"str","halt_if_compare":"is","outputs":2,"output_only_on_state_change":true,"for":"5","forType":"num","forUnits":"seconds","ignorePrevStateNull":false,"ignorePrevStateUnknown":false,"ignorePrevStateUnavailable":false,"ignoreCurrentStateUnknown":false,"ignoreCurrentStateUnavailable":false,"outputProperties":[{"property":"data","propertyType":"msg","value":"","valueType":"eventData"},{"property":"topic","propertyType":"msg","value":"","valueType":"triggerId"},{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"}],"x":170,"y":120,"wires":[["a4af3efaf9117b65"],[]]},{"id":"6198caf18f7a35c8","type":"server-state-changed","z":"cc79f244762aa45f","name":"Downstairs Bathroom Leak","server":"6897d4d.3c81f2c","version":4,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityidfilter":"binary_sensor.leak_sensor_aq2","entityidfiltertype":"exact","outputinitially":false,"state_type":"str","haltifstate":"on","halt_if_type":"str","halt_if_compare":"is","outputs":2,"output_only_on_state_change":true,"for":"5","forType":"num","forUnits":"seconds","ignorePrevStateNull":false,"ignorePrevStateUnknown":false,"ignorePrevStateUnavailable":false,"ignoreCurrentStateUnknown":false,"ignoreCurrentStateUnavailable":false,"outputProperties":[{"property":"data","propertyType":"msg","value":"","valueType":"eventData"},{"property":"topic","propertyType":"msg","value":"","valueType":"triggerId"},{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"}],"x":170,"y":180,"wires":[["a4af3efaf9117b65"],[]]},{"id":"7d771f6904109666","type":"api-call-service","z":"cc79f244762aa45f","name":"","server":"6897d4d.3c81f2c","version":5,"debugenabled":false,"domain":"notify","service":"persistent_notification","areaId":[],"deviceId":[],"entityId":[],"data":"{    \t    \"title\": \"Leak detected: \"  & $.displayName,\t    \"message\": \"There is a leak on \" & $.displayName\t}","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":900,"y":120,"wires":[["28b1ea1f15c023db"]]},{"id":"28b1ea1f15c023db","type":"api-call-service","z":"cc79f244762aa45f","name":"","server":"6897d4d.3c81f2c","version":5,"debugenabled":false,"domain":"notify","service":"mobile_app_pixel_4a_5g","areaId":[],"deviceId":[],"entityId":[],"data":"{    \t    \"title\": \"Leak detected: \"  & $.displayName,\t    \"message\": \"There is a leak on \" & $.displayName\t}","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":910,"y":180,"wires":[["89f6a0a7732f052a"]]},{"id":"a4af3efaf9117b65","type":"function","z":"cc79f244762aa45f","name":"Get Friendly Device Name","func":"const haCtx = global.get(\"homeassistant\");\n\n// Note: the 'homeassistant' below must match the server name\nconst configCtx = haCtx.homeassistant;\nconst entity = configCtx.states[msg.topic];\nmsg.displayName = entity.attributes.friendly_name;\n// node.warn(\"displayName is: \" + msg.displayName);\n//msg.entityState = entity.state === \"on\" ? true : false;\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":510,"y":200,"wires":[["141bbf58f22cfdf5"]]},{"id":"89f6a0a7732f052a","type":"ha-wait-until","z":"cc79f244762aa45f","name":"wait until all leak sensors report dry","server":"6897d4d.3c81f2c","version":2,"outputs":2,"entityId":"binary_sensor.leak_sensors","entityIdFilterType":"exact","property":"state","comparator":"is","value":"off","valueType":"str","timeout":"1","timeoutType":"num","timeoutUnits":"seconds","checkCurrentState":true,"blockInputOverrides":true,"outputProperties":[],"entityLocation":"data","entityLocationType":"none","x":920,"y":260,"wires":[[],["df142fd9ae42a1b0"]]},{"id":"f54d509b60cdca30","type":"server-state-changed","z":"cc79f244762aa45f","name":"Dishwasher Leak","server":"6897d4d.3c81f2c","version":4,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityidfilter":"binary_sensor.wleak_aq1_dishwasher","entityidfiltertype":"exact","outputinitially":false,"state_type":"str","haltifstate":"on","halt_if_type":"str","halt_if_compare":"is","outputs":2,"output_only_on_state_change":true,"for":"5","forType":"num","forUnits":"seconds","ignorePrevStateNull":false,"ignorePrevStateUnknown":false,"ignorePrevStateUnavailable":false,"ignoreCurrentStateUnknown":false,"ignoreCurrentStateUnavailable":false,"outputProperties":[{"property":"data","propertyType":"msg","value":"","valueType":"eventData"},{"property":"topic","propertyType":"msg","value":"","valueType":"triggerId"},{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"}],"x":200,"y":240,"wires":[["a4af3efaf9117b65"],[]]},{"id":"513c6a671834dc98","type":"server-state-changed","z":"cc79f244762aa45f","name":"Downstairs Washing Machine Leak","server":"6897d4d.3c81f2c","version":4,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityidfilter":"binary_sensor.wleak_aq1_washingmachine","entityidfiltertype":"exact","outputinitially":false,"state_type":"str","haltifstate":"on","halt_if_type":"str","halt_if_compare":"is","outputs":2,"output_only_on_state_change":true,"for":"5","forType":"num","forUnits":"seconds","ignorePrevStateNull":false,"ignorePrevStateUnknown":false,"ignorePrevStateUnavailable":false,"ignoreCurrentStateUnknown":false,"ignoreCurrentStateUnavailable":false,"outputProperties":[{"property":"data","propertyType":"msg","value":"","valueType":"eventData"},{"property":"topic","propertyType":"msg","value":"","valueType":"triggerId"},{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"}],"x":140,"y":300,"wires":[["a4af3efaf9117b65"],[]]},{"id":"738d4059108b0671","type":"delay","z":"cc79f244762aa45f","name":"Delay by msg.delay (ms)","pauseType":"delayv","timeout":"0","timeoutUnits":"minutes","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":510,"y":260,"wires":[["141bbf58f22cfdf5"]]},{"id":"df142fd9ae42a1b0","type":"function","z":"cc79f244762aa45f","name":"Add 5 mins to delay.","func":"const five_minutes = 1000 * 60 * 5; \nlet delay = five_minutes; // // Default delay 5 mins\nif (msg.delay)\n{\n    delay = msg.delay + five_minutes;\n    // node.warn(\"delay is now: \" + delay / 1000 / 60 + ' minutes');\n}\nmsg.delay = delay;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":900,"y":360,"wires":[["738d4059108b0671"]]},{"id":"18f019f684c02d88","type":"comment","z":"cc79f244762aa45f","name":"Leak sensors need to be in group \"Leak Sensors\"","info":"","x":180,"y":80,"wires":[]},{"id":"6897d4d.3c81f2c","type":"server","name":"homeassistant","version":5,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true,"heartbeat":false,"heartbeatInterval":"30","areaSelector":"friendlyName","deviceSelector":"friendlyName","entitySelector":"friendlyName","statusSeparator":"at: ","statusYear":"hidden","statusMonth":"short","statusDay":"numeric","statusHourCycle":"h23","statusTimeFormat":"h:m","enableGlobalContextStore":true}]

2 Likes

Hi just started adding my leak sensors to NR and wanted to create something like you did here. what do you mean by Leak sensors need to be in group “Leak Sensors” ? where do i create that group? in NR?

I created a Helper Group called “Leak Sensors” (binary_sensor.leak_sensors) that wraps up all the moisture sensors into a single group so the “All Clear” message is easier to determine. This was only to determine when they all reported Dry. You could probably also do this in groups.yaml



Screen Shot 2024-02-21 at 3.21.02 PM