"wait until" node only forwards one of multiple messages

Hello,

I only recently discovered Node-RED and use V3.0.2 with Home Assistant. I work on automating my covers depending on the sun position and the weather.

What the flow does:

  • starts at a defined sun position (azimuth)
  • checks the weather and decides whether it is necessary to lower the covers
  • takes a list of covers
  • checks whether each of those windows is already lower than the desired position
  • if this is not the case, saves the current position and lowers it to the desired position
  • WAITS (-> here is the problem, see below)
  • sets the position of each window back to the prior position unless the position has been changed manually in the meantime

My problem is:

  • I have to use the "delay" node to make the flow wait. That works, but I would rather want to wait until the sun reaches a predefined position before the covers are moved to their prior position
  • If I use the "wait until" node instead, the behaviour is not what I would expect. Unlike the "delay" node, which forwards all messages (one for each cover), the "wait until" node only forwards the message for ONE cover and thus only one cover is moved to its prior position.

Is there a more elegant solution that lets the flow wait until sun.azimut reaches a predefined position and then forwards all queued messages instead of only one?

Thank you for your help!

The flow:

[{"id":"5c77e641ea8fb1b7","type":"tab","label":"Rollo Forum","disabled":true,"info":"","env":[]},{"id":"e38af58e4866faa3","type":"function","z":"5c77e641ea8fb1b7","name":"Verschattung Süd aktiv","func":"var speicher = flow.get('verschattung_sud_aktiv') || \"Nein\";\nif (speicher===\"Nein\")\n{\n    flow.set('verschattung_sud_aktiv',\"Ja\");\n    msg.payload=\"Ja\";\n    return msg;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1120,"y":300,"wires":[["55818be2c27c5a6e"]]},{"id":"928480982b3c4e88","type":"trigger-state","z":"5c77e641ea8fb1b7","name":"azimuth_start bis azimuth_start+3","server":"5a3777c7.b71588","version":2,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityid":"sensor.sun_solar_azimuth","entityidfiltertype":"exact","debugenabled":false,"constraints":[{"targetType":"this_entity","targetValue":"","propertyType":"current_state","propertyValue":"new_state.state","comparatorType":">=","comparatorValueDatatype":"num","comparatorValue":"130"},{"targetType":"this_entity","targetValue":"","propertyType":"current_state","propertyValue":"new_state.state","comparatorType":"<=","comparatorValueDatatype":"num","comparatorValue":"133"}],"inputs":0,"outputs":2,"customoutputs":[],"outputinitially":true,"state_type":"num","enableInput":false,"x":220,"y":300,"wires":[["68707f5eb506fd20"],[]]},{"id":"68707f5eb506fd20","type":"api-current-state","z":"5c77e641ea8fb1b7","name":"Erw. Temperatur über x","server":"5a3777c7.b71588","version":3,"outputs":2,"halt_if":"23","halt_if_type":"num","halt_if_compare":"gte","entity_id":"sensor.openweathermap_forecast_temperature","state_type":"num","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"},{"property":"test","propertyType":"msg","value":"temperatur","valueType":"flow"}],"for":0,"forType":"num","forUnits":"minutes","x":540,"y":300,"wires":[["35568355a6d8a2f3","48e0862dbcc7ea02"],[]]},{"id":"35568355a6d8a2f3","type":"api-current-state","z":"5c77e641ea8fb1b7","name":"Wird es Sonnig?","server":"5a3777c7.b71588","version":3,"outputs":2,"halt_if":"sunny","halt_if_type":"str","halt_if_compare":"is","entity_id":"sensor.openweathermap_condition","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"for":0,"forType":"num","forUnits":"minutes","x":770,"y":260,"wires":[["e38af58e4866faa3"],[]]},{"id":"48e0862dbcc7ea02","type":"api-current-state","z":"5c77e641ea8fb1b7","name":"Wird es teilweise bedeckt?","server":"5a3777c7.b71588","version":3,"outputs":2,"halt_if":"partlycloudy","halt_if_type":"str","halt_if_compare":"is","entity_id":"sensor.openweathermap_condition","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"for":0,"forType":"num","forUnits":"minutes","x":810,"y":320,"wires":[["e38af58e4866faa3"],[]]},{"id":"c7270cdd4589d38e","type":"split","z":"5c77e641ea8fb1b7","name":"","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":300,"y":420,"wires":[["d2967c82ef6a5105"]]},{"id":"d2967c82ef6a5105","type":"change","z":"5c77e641ea8fb1b7","name":"","rules":[{"t":"set","p":"position_verschattung","pt":"msg","to":"65","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":510,"y":420,"wires":[["b38a6088a43f6d36"]]},{"id":"55818be2c27c5a6e","type":"template","z":"5c77e641ea8fb1b7","name":"Liste Rollos","field":"payload","fieldType":"msg","format":"handlebars","syntax":"plain","template":"cover.rollo_wohnen_2\ncover.rollo_wohnen_3\ncover.rollo_kids_1\ncover.rollo_schlafzimmer","output":"str","x":160,"y":420,"wires":[["c7270cdd4589d38e"]]},{"id":"b38a6088a43f6d36","type":"function","z":"5c77e641ea8fb1b7","name":"States Rollo aus Liste","func":"var states = global.get('homeassistant.homeAssistant.states');\nvar rollo = states[msg.payload];\nmsg.rollo = rollo;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":770,"y":420,"wires":[["26c11a07f216d8d5"]]},{"id":"26c11a07f216d8d5","type":"switch","z":"5c77e641ea8fb1b7","name":"Position höher (>) als position_verschattung","property":"rollo.attributes.current_position","propertyType":"jsonata","rules":[{"t":"gte","v":"position_verschattung","vt":"jsonata"},{"t":"lt","v":"position_verschattung","vt":"jsonata"}],"checkall":"true","repair":true,"outputs":2,"x":1080,"y":420,"wires":[["0fcb45bf2f12b6ab"],[]]},{"id":"5e097ee94b46ca36","type":"api-call-service","z":"5c77e641ea8fb1b7","name":"Rollo auf position_verschattung","server":"5a3777c7.b71588","version":5,"debugenabled":true,"domain":"cover","service":"set_cover_position","areaId":[],"deviceId":[],"entityId":[],"data":"{\t    \"entity_id\": (payload),\t    \"position\": (position_verschattung) \t}","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":240,"y":480,"wires":[["757935e7ccecfa70"]]},{"id":"0fcb45bf2f12b6ab","type":"change","z":"5c77e641ea8fb1b7","name":"","rules":[{"t":"set","p":"position_vorher","pt":"msg","to":"rollo.attributes.current_position","tot":"msg","dc":true}],"action":"","property":"","from":"","to":"","reg":false,"x":1390,"y":420,"wires":[["5e097ee94b46ca36"]]},{"id":"20460f22f30bce95","type":"function","z":"5c77e641ea8fb1b7","name":"States Rollo aus Liste","func":"var states = global.get('homeassistant.homeAssistant.states');\nvar rollo2 = states[msg.payload];\nmsg.rollo2 = rollo2;\n//msg.vorgaben.rollo = states[\"cover.rollo_buro_2\"];\n// var rollo = states[\"cover.rollo_buro_2\"];\n// return rollo;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":370,"y":560,"wires":[["3ba81601a5219231"]]},{"id":"3ba81601a5219231","type":"switch","z":"5c77e641ea8fb1b7","name":"Position unverändert?","property":"rollo2.attributes.current_position","propertyType":"msg","rules":[{"t":"eq","v":"position_verschattung","vt":"msg"}],"checkall":"true","repair":false,"outputs":1,"x":590,"y":560,"wires":[["d204e1c135cf267e"]]},{"id":"d204e1c135cf267e","type":"api-call-service","z":"5c77e641ea8fb1b7","name":"Rollo auf position_vorher","server":"5a3777c7.b71588","version":5,"debugenabled":true,"domain":"cover","service":"set_cover_position","areaId":[],"deviceId":[],"entityId":[],"data":"{\t    \"entity_id\": (payload),\t    \"position\": (position_vorher) \t}","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":820,"y":560,"wires":[["9666611b068d6220"]]},{"id":"757935e7ccecfa70","type":"delay","z":"5c77e641ea8fb1b7","name":"","pauseType":"delay","timeout":"6","timeoutUnits":"hours","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":170,"y":560,"wires":[["20460f22f30bce95"]]},{"id":"9666611b068d6220","type":"function","z":"5c77e641ea8fb1b7","name":"Verschattung Süd deaktiv","func":"var speicher = flow.get('verschattung_sud_aktiv') || \"Nein\";\nif (speicher===\"Ja\")\n{\n    flow.set('verschattung_sud_aktiv',\"Nein\");\n    msg.payload=\"Nein\";\n    return msg;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1060,"y":560,"wires":[[]]},{"id":"5a3777c7.b71588","type":"server","name":"Home Assistant","version":5,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":false,"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}]

Hi, unfortunately, I find not many people here use Home Assistant (preferring instead to do everything in Node-RED)

This is what happens when you post a flow with lots of HA Nodes...

What is the sun position you are interested in?

If it is Sunrise or Sunset or nadir or one of the common ones, then I suggest a re-jig.

Basically, if you use a delay node, you risk losing the queued messages if there is a power interuption.

If you use something like cron-plus node, you can do this...

Then just generate the messages after the cron node. This has the advantage of not relying on memory based data and will survive a server restart.

PS, if you can build a demo flow that does NOT use HA nodes, we can make aa working demo for you.

if you want to queue messages until some event occurs then you can use node-red-contrib-queue-gate.

@Steve-Mcl
Thank you for your reply! I totally missed that the "wait until" node also stems from the Home Assistant integration and not from Node Red itself. Thus, it is impossible for me to build a demo flow wthout Home Assistant components.

Maybe I can rephrase my question:

  • I want to move the shades back to their prior position when sun.azimut = 220 (degrees), i.e. the sun does not shine into the south facing windows. For this I (that is what I think...) need all messages to be queued until the condition sun.azimut = 220 is true. I assume starting a new flow with cron would make it much harder to pass on the prior position per cover.

@colin0031
Thank you, that appears to be a solution to my problem :slight_smile:

Thank you for your helpful answers!

Sure you can. You can simulate all nodes using combinations of inject/template/function/change nodes. This way, we can test it without having HA.
And, note: Even if we DID use HA, we would not have your configuration.
Therefore, a slimmed down demo flow will help us to help you.

For a demo: The parts that matter are the delay logic and the multiple messages to close blinds - and they are nodes that are either part of Node-RED code OR can be installed on a system without HA.
The node to Close Blinds can just be a debug node!

For example:

To simulate sun.azimut = 220 - capture a payload from the node that creates that & inject it using an inject node.
image

Then fake the other bits:

And this is how you capture a payload

image

Thank you for your detailed explanation. I tried my best to simulate the flow without Home Assistant components:

[{"id":"c7270cdd4589d38e","type":"split","z":"5c77e641ea8fb1b7","name":"","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":330,"y":420,"wires":[["d2967c82ef6a5105"]]},{"id":"d2967c82ef6a5105","type":"change","z":"5c77e641ea8fb1b7","name":"Set target position","rules":[{"t":"set","p":"position_verschattung","pt":"msg","to":"65","tot":"num"},{"t":"set","p":"data","pt":"msg","to":"{\"entity_id\":\"cover.rollo_buro_1\",\"state\":\"open\",\"attributes\":{\"current_position\":72,\"device_class\":\"shutter\",\"friendly_name\":\"Rollo Büro 1\",\"supported_features\":15},\"last_changed\":\"2023-08-20T16:35:55.808Z\",\"last_updated\":\"2023-08-20T16:35:55.808Z\",\"context\":{\"id\":\"01H89WV4CGCEFW8SDJ2FQMTGPW\",\"parent_id\":null,\"user_id\":\"b2b960d4c603465eb0bb20f04585c54f\"},\"timeSinceChangedMs\":20086533}","tot":"json"},{"t":"set","p":"data.entity_id","pt":"msg","to":"payload","tot":"msg","dc":true}],"action":"","property":"","from":"","to":"","reg":false,"x":490,"y":420,"wires":[["26c11a07f216d8d5"]]},{"id":"55818be2c27c5a6e","type":"template","z":"5c77e641ea8fb1b7","name":"List of covers","field":"payload","fieldType":"msg","format":"handlebars","syntax":"plain","template":"cover.rollo_wohnen_2\ncover.rollo_wohnen_3\ncover.rollo_kids_1\ncover.rollo_schlafzimmer","output":"str","x":170,"y":420,"wires":[["c7270cdd4589d38e"]]},{"id":"26c11a07f216d8d5","type":"switch","z":"5c77e641ea8fb1b7","name":"current position > target position?","property":"data.attributes.current_position","propertyType":"jsonata","rules":[{"t":"gte","v":"position_verschattung","vt":"jsonata"},{"t":"lt","v":"position_verschattung","vt":"jsonata"}],"checkall":"true","repair":true,"outputs":2,"x":760,"y":420,"wires":[["0fcb45bf2f12b6ab"],[]]},{"id":"3ba81601a5219231","type":"switch","z":"5c77e641ea8fb1b7","name":"Position unchanged?","property":"data.attributes.current_position","propertyType":"msg","rules":[{"t":"eq","v":"position_verschattung","vt":"msg"}],"checkall":"true","repair":false,"outputs":1,"x":720,"y":560,"wires":[["d406d9e53faf15c1"]]},{"id":"757935e7ccecfa70","type":"delay","z":"5c77e641ea8fb1b7","name":"","pauseType":"delay","timeout":"6","timeoutUnits":"hours","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":170,"y":560,"wires":[["3ba81601a5219231"]]},{"id":"95a5bf396714b5f3","type":"inject","z":"5c77e641ea8fb1b7","name":"Trigger: Fake azimut sensor","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"_msgid\":\"a0fd4ab3129e8fea\",\"payload\":\"130.78\",\"topic\":\"\",\"data\":{\"entity_id\":\"sensor.sun_solar_azimuth\",\"state\":\"130.78\",\"attributes\":{\"state_class\":\"measurement\",\"unit_of_measurement\":\"°\",\"icon\":\"mdi:sun-angle\",\"friendly_name\":\"Sun Azimut\"},\"last_changed\":\"2023-08-20T22:08:54.328Z\",\"last_updated\":\"2023-08-20T22:08:54.328Z\",\"context\":{\"id\":\"01H8AFWWHRRCYFT6T8X325MZMG\",\"parent_id\":null,\"user_id\":null},\"timeSinceChangedMs\":967831}}","payloadType":"json","x":200,"y":360,"wires":[["55818be2c27c5a6e"]]},{"id":"0fcb45bf2f12b6ab","type":"change","z":"5c77e641ea8fb1b7","name":"save current position","rules":[{"t":"set","p":"position_vorher","pt":"msg","to":"data.attributes.current_position","tot":"msg","dc":true}],"action":"","property":"","from":"","to":"","reg":false,"x":1040,"y":420,"wires":[["9138bc8f18a8432f"]]},{"id":"9138bc8f18a8432f","type":"change","z":"5c77e641ea8fb1b7","name":"Fake lower covers","rules":[{"t":"set","p":"data.attributes.current_position","pt":"msg","to":"65","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":190,"y":500,"wires":[["757935e7ccecfa70"]]},{"id":"d406d9e53faf15c1","type":"change","z":"5c77e641ea8fb1b7","name":"Fake move to prior position","rules":[{"t":"set","p":"data.attributes.current_position","pt":"msg","to":"position_vorher","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":980,"y":560,"wires":[[]]},{"id":"d1dd373369a0f334","type":"comment","z":"5c77e641ea8fb1b7","name":"Fake: all covers unchanged","info":"","x":440,"y":580,"wires":[]}]

The delay node works but a fixed delay is very unelegant, I would rather re-open the covers once sun.azimuth = 220. I tried to accomplish this using the Home Assistant "wait-until" node, but it only forwards the last message.

I assume I will have to let sun.azimuth trigger a change node that opens the q-gate and then close the q-gate again once the covers are back to their old position. Correct?

Would you prefer saving the prior position somewhere else to avoid being at risk for power loss for several hours?

You can use the delay node with a delay of 1 day or even longer to block all messages - and flush all messages at the desired time.

[{"id":"9f5c7af07c5fdfbe","type":"delay","z":"289f539dcc33814e","name":"","pauseType":"delay","timeout":"1","timeoutUnits":"days","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":2620,"y":4140,"wires":[["aeea8adb2d91b1af"]]},{"id":"1580c47aabd528db","type":"inject","z":"289f539dcc33814e","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"top1","payload":"1","payloadType":"num","x":2390,"y":4080,"wires":[["9f5c7af07c5fdfbe"]]},{"id":"9624562a67b281d6","type":"inject","z":"289f539dcc33814e","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"top2","payload":"2","payloadType":"num","x":2390,"y":4120,"wires":[["9f5c7af07c5fdfbe"]]},{"id":"49115f31b0733ce3","type":"inject","z":"289f539dcc33814e","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"top3","payload":"3","payloadType":"num","x":2390,"y":4160,"wires":[["9f5c7af07c5fdfbe"]]},{"id":"783402e0ff54fc42","type":"inject","z":"289f539dcc33814e","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"top4","payload":"4","payloadType":"num","x":2390,"y":4200,"wires":[["9f5c7af07c5fdfbe"]]},{"id":"aeea8adb2d91b1af","type":"debug","z":"289f539dcc33814e","name":"debug 45","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":2840,"y":4140,"wires":[]},{"id":"5f29c5bf6bc2d7a6","type":"inject","z":"289f539dcc33814e","name":"flush all messages","props":[{"p":"flush","v":"true","vt":"bool"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":2350,"y":4240,"wires":[["9f5c7af07c5fdfbe"]]}]

Thank you. From what I understand, the q-gate node is more versatile, but the delay node is sufficient for my purpose.

Would you recommed routinely resetting the delay node at e.g. 0100 to prevent a pile-up of messages in case power goes off while waiting for sun.azimuth to reach the desired value?

Depends when the messages are created - but for sure you have the options. But your request was that the node collects incoming messages and can be released on request. So you can also reset the node before all messages for all shutters in your list are created

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.