Interesting flow, and yes it does beg the question ‘what could go wrong?’
I think the key point is in the switch node documentation (my highlights).
If the message has a property enable defined and set to a Boolean the node will not have any output.
The base use of a switch node would normally be ‘output only’, which is safe, or ‘input only’. Both input and output together are OK as long as there are no loops between output and input.
With a loop as you have it here, as long as the only input is a message with msg.enable set to a Boolean value, then there will be no input-output feedback. However, any change to the way this node behaves, for example if this precise feature was removed in future releases, this would certainly set up a feedback loop.
In general, loops can be a real a problem in Node-RED, not least as they can result in memory leaks since the flow never ends. I do have flows with a loop back, and to avoid possible catastrophic run-away feedback I now add a delay node with a limit of 1 message per (minute/hour/day) in the loop return, just to ensure that if a loop does unexpectedly feedback then it will not overwhelm NR and HA.
In your flow:
It certainly works.
I think that there are issues with the start up state, since all switches will be ‘off’, or ‘on’, so I would suggest an initialization of the ‘off’ as ‘on’ and the other ‘on’ switches as ‘off’. Given that this is a heater, personally I would want a Node-RED restart to auto select ‘off’ as the default state.
For my sanity, I re-drew this flow using links, and have named the ‘off’ switch to ‘no heat’, so that I can turn the ‘no heat’ ‘on’ just like all the other switches, rather than turn ‘off’ ‘on’.
[{"id":"f839fda35840f409","type":"ha-switch","z":"659ff45c0b65321e","name":"Sw H Fall Back","version":0,"debugenabled":false,"inputs":1,"outputs":2,"entityConfig":"88fd477e077c7177","enableInput":true,"outputOnStateChange":true,"outputProperties":[{"property":"enable","propertyType":"msg","value":"false","valueType":"bool"},{"property":"payload","propertyType":"msg","value":"F-B","valueType":"str"}],"x":340,"y":2120,"wires":[["9aa0f6b5fd636076"],[]],"server":""},{"id":"5b571ce68a7b7938","type":"ha-switch","z":"659ff45c0b65321e","name":"Sw - NO HEAT","version":0,"debugenabled":false,"inputs":1,"outputs":2,"entityConfig":"0c94a3a8bae58dc6","enableInput":true,"outputOnStateChange":true,"outputProperties":[{"property":"enable","propertyType":"msg","value":"false","valueType":"bool"},{"property":"payload","propertyType":"msg","value":"Off","valueType":"str"}],"x":340,"y":2060,"wires":[["c5a57c1b27faec30"],[]],"server":""},{"id":"4abf0e05ad4b52fc","type":"ha-switch","z":"659ff45c0b65321e","name":"Sw Heat Comfort","version":0,"debugenabled":false,"inputs":1,"outputs":2,"entityConfig":"391c5289cfd48f8d","enableInput":true,"outputOnStateChange":true,"outputProperties":[{"property":"enable","propertyType":"msg","value":"false","valueType":"bool"},{"property":"payload","propertyType":"msg","value":"Com","valueType":"str"}],"x":340,"y":2240,"wires":[["327b3cd564aedf21"],[]],"server":""},{"id":"10aa9e46fc28a10b","type":"ha-switch","z":"659ff45c0b65321e","name":"Sw Heat Boost","version":0,"debugenabled":false,"inputs":1,"outputs":2,"entityConfig":"098487e6c83099a9","enableInput":true,"outputOnStateChange":true,"outputProperties":[{"property":"enable","propertyType":"msg","value":"false","valueType":"bool"},{"property":"payload","propertyType":"msg","value":"Boo","valueType":"str"}],"x":340,"y":2180,"wires":[["5964ca54a35aae8b"],[]],"server":""},{"id":"327b3cd564aedf21","type":"link out","z":"659ff45c0b65321e","name":"Comfort ON","mode":"link","links":["25336b758fddd15f","43cf24ef57023592","77eb0f54d2a18344","2f04550963b526ee"],"x":465,"y":2240,"wires":[]},{"id":"43cf24ef57023592","type":"link in","z":"659ff45c0b65321e","name":"No Heat OFF","links":["327b3cd564aedf21","5964ca54a35aae8b","9aa0f6b5fd636076"],"x":225,"y":2080,"wires":[["5b571ce68a7b7938"]]},{"id":"5964ca54a35aae8b","type":"link out","z":"659ff45c0b65321e","name":"Boost ON","mode":"link","links":["25336b758fddd15f","43cf24ef57023592","450b2e5e35949063","2f04550963b526ee"],"x":465,"y":2180,"wires":[]},{"id":"9aa0f6b5fd636076","type":"link out","z":"659ff45c0b65321e","name":"Fall Back ON","mode":"link","links":["43cf24ef57023592","450b2e5e35949063","77eb0f54d2a18344","2f04550963b526ee"],"x":465,"y":2120,"wires":[]},{"id":"c5a57c1b27faec30","type":"link out","z":"659ff45c0b65321e","name":"No Heat ON","mode":"link","links":["25336b758fddd15f","450b2e5e35949063","77eb0f54d2a18344","2f04550963b526ee"],"x":475,"y":2040,"wires":[]},{"id":"25336b758fddd15f","type":"link in","z":"659ff45c0b65321e","name":"Fall Back OFF","links":["327b3cd564aedf21","5964ca54a35aae8b","c5a57c1b27faec30"],"x":225,"y":2120,"wires":[["f839fda35840f409"]]},{"id":"77eb0f54d2a18344","type":"link in","z":"659ff45c0b65321e","name":"Boost OFF","links":["327b3cd564aedf21","9aa0f6b5fd636076","c5a57c1b27faec30"],"x":225,"y":2180,"wires":[["10aa9e46fc28a10b"]]},{"id":"450b2e5e35949063","type":"link in","z":"659ff45c0b65321e","name":"Comfort OFF","links":["5964ca54a35aae8b","9aa0f6b5fd636076","c5a57c1b27faec30"],"x":225,"y":2240,"wires":[["4abf0e05ad4b52fc"]]},{"id":"a4ad42634e6a22ef","type":"inject","z":"659ff45c0b65321e","name":"Startup - turn all but one OFF","props":[{"p":"enable","v":"false","vt":"bool"}],"repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"","x":230,"y":1960,"wires":[["c5a57c1b27faec30","e3681d964f17772c"]]},{"id":"e3681d964f17772c","type":"change","z":"659ff45c0b65321e","name":"Turn ON","rules":[{"t":"set","p":"enable","pt":"msg","to":"true","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":180,"y":2040,"wires":[["5b571ce68a7b7938"]]},{"id":"88fd477e077c7177","type":"ha-entity-config","server":"","deviceConfig":"","name":"Steve's Office Sw Heat Fall Back","version":"6","entityType":"switch","haConfig":[{"property":"name","value":"Steve's Office Sw Heat Fall Back"},{"property":"icon","value":""},{"property":"entity_category","value":""},{"property":"entity_picture","value":""},{"property":"device_class","value":""}],"resend":false,"debugEnabled":false},{"id":"0c94a3a8bae58dc6","type":"ha-entity-config","server":"","deviceConfig":"","name":"Steve's Office Sw Heat Off","version":"6","entityType":"switch","haConfig":[{"property":"name","value":"Steve's Office Switch Heat Off"},{"property":"icon","value":""},{"property":"entity_category","value":""},{"property":"entity_picture","value":""},{"property":"device_class","value":""}],"resend":false,"debugEnabled":false},{"id":"391c5289cfd48f8d","type":"ha-entity-config","server":"","deviceConfig":"","name":"Steve's Office Switch Heat Comfort","version":"6","entityType":"switch","haConfig":[{"property":"name","value":"Steve's Office Switch Heat Comfort"},{"property":"icon","value":""},{"property":"entity_category","value":""},{"property":"entity_picture","value":""},{"property":"device_class","value":""}],"resend":false,"debugEnabled":false},{"id":"098487e6c83099a9","type":"ha-entity-config","server":"","deviceConfig":"","name":"Steve's Office Sw Heat Boost","version":"6","entityType":"switch","haConfig":[{"property":"name","value":"Steve's Office Sw Heat Boost"},{"property":"icon","value":""},{"property":"entity_category","value":""},{"property":"entity_picture","value":""},{"property":"device_class","value":""}],"resend":false,"debugEnabled":false}]
However:
Basically, this flow is a state-engine where you are keeping the state of the set of switches (buttons) and an alternative would be to use a State Machine (FSM) node. This has an advantage that the state of the ‘switch set’ can be persisted by the node over NR deploys (not restarts). I have added an example flow, using buttons to trigger the state change, and a simple text display for output. Since the state node can only have one state, and the node manages the loops between states, this removes any need for an external loop in the NR flow.
The State Machine node has many features, and at NR restart it should begin in the default state. It can also be set to output the state at start to ensure that the down-stream flow gets initialised to ‘off’.
As an exercise, I also tested out the config node so as to change the button icons when pressed. It does take a little bit of JSONata code to set up, but with the correct node ids and the FSM states hard coded, pressing a button will change the State Machine Node, then change the icon for the button just pressed, and clear all the other buttons. A ‘soft touch’ radio button group.
[{"id":"2862babdee4f51d9","type":"state-machine","z":"659ff45c0b65321e","name":"Radio Switch","triggerProperty":"payload","triggerPropertyType":"msg","stateProperty":"payload","statePropertyType":"msg","initialDelay":"0","persistOnReload":true,"outputStateChangeOnly":false,"throwException":false,"states":["Off","FallBack","Boost","Comfort"],"transitions":[{"name":"Off","from":"*","to":"Off"},{"name":"Com","from":"*","to":"Comfort"},{"name":"Boo","from":"*","to":"Boost"},{"name":"F-B","from":"*","to":"FallBack"}],"x":370,"y":2480,"wires":[["993bd431ca98bd07","e9a918aaca90681f"]]},{"id":"918f5db25bc37345","type":"ha-button","z":"659ff45c0b65321e","name":"Fall Back","version":0,"debugenabled":false,"outputs":1,"entityConfig":"2b2ae3bcf66682b0","outputProperties":[{"property":"payload","propertyType":"msg","value":"F-B","valueType":"str"}],"x":160,"y":2440,"wires":[["2862babdee4f51d9"]],"server":""},{"id":"833ab6d1c0d1916c","type":"ha-button","z":"659ff45c0b65321e","name":"Heat Off","version":0,"debugenabled":false,"outputs":1,"entityConfig":"b3c2c46df359d9f0","outputProperties":[{"property":"payload","propertyType":"msg","value":"Off","valueType":"str"},{"property":"this","propertyType":"msg","value":"","valueType":"triggerId"}],"x":160,"y":2380,"wires":[["2862babdee4f51d9"]],"server":""},{"id":"993bd431ca98bd07","type":"ha-text","z":"659ff45c0b65321e","name":"Steve's Office Heater State","version":1,"debugenabled":false,"inputs":1,"outputs":1,"entityConfig":"5c49aaa0acc38789","mode":"set","value":"payload","valueType":"msg","outputProperties":[],"x":630,"y":2460,"wires":[[]],"server":""},{"id":"11a9eb67648b0461","type":"ha-button","z":"659ff45c0b65321e","name":"Boost","version":0,"debugenabled":false,"outputs":1,"entityConfig":"9092f32700acabd7","outputProperties":[{"property":"payload","propertyType":"msg","value":"Boo","valueType":"str"}],"x":150,"y":2500,"wires":[["2862babdee4f51d9"]],"server":""},{"id":"692d48de42ba2e16","type":"ha-button","z":"659ff45c0b65321e","name":"Comfort","version":0,"debugenabled":false,"outputs":1,"entityConfig":"f8a1347038ecac0e","outputProperties":[{"property":"payload","propertyType":"msg","value":"Com","valueType":"str"}],"x":150,"y":2560,"wires":[["2862babdee4f51d9"]],"server":""},{"id":"24f20e7316bc843a","type":"ha-update-config","z":"659ff45c0b65321e","name":"","server":"","entityConfig":"b3c2c46df359d9f0","version":0,"outputProperties":[],"x":880,"y":2540,"wires":[[]]},{"id":"e9a918aaca90681f","type":"change","z":"659ff45c0b65321e","name":"Icons","rules":[{"t":"set","p":"payload","pt":"msg","to":"(\t $states:=[\"Off\", \"FallBack\", \"Boost\", \"Comfort\"];\t $nodes:=[\"b3c2c46df359d9f0\", \"2b2ae3bcf66682b0\", \"9092f32700acabd7\",\"f8a1347038ecac0e\"];\t\t $seton:=\"mdi:gesture-tap-button\";\t $setoff:=\"mdi:button-pointer\";\t\t $button:=payload;\t $index:=$states#$i.($=$button ? $i);\t $setid:=$nodes[$index];\t\t $notarray:=$nodes[$!=$setid].{\"id\": $, \"icon\": $setoff};\t {\"set\": {\"id\": $setid, \"icon\": $seton}, \"clear\": $notarray }; \t\t)","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":410,"y":2560,"wires":[["4226ee66a23b69fb","f685a555c4bb0551"]]},{"id":"4226ee66a23b69fb","type":"change","z":"659ff45c0b65321e","name":"Set","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.set","tot":"msg","dc":true}],"action":"","property":"","from":"","to":"","reg":false,"x":570,"y":2540,"wires":[["24f20e7316bc843a"]]},{"id":"6ff66e53fed9b171","type":"split","z":"659ff45c0b65321e","name":"","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":710,"y":2600,"wires":[["24f20e7316bc843a"]]},{"id":"f685a555c4bb0551","type":"change","z":"659ff45c0b65321e","name":"Unset","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.clear","tot":"msg","dc":true}],"action":"","property":"","from":"","to":"","reg":false,"x":570,"y":2600,"wires":[["6ff66e53fed9b171"]]},{"id":"ca85f7e73d114fe7","type":"inject","z":"659ff45c0b65321e","name":"Startup","props":[],"repeat":"","crontab":"","once":true,"onceDelay":"1","topic":"","x":380,"y":2420,"wires":[["2862babdee4f51d9"]]},{"id":"2b2ae3bcf66682b0","type":"ha-entity-config","server":"","deviceConfig":"","name":"Steve Office Sw Heat Fall Back BUTTON","version":"6","entityType":"button","haConfig":[{"property":"name","value":"Steve's Office Sw Heat Fall Back BUTTON"},{"property":"icon","value":""},{"property":"entity_category","value":""},{"property":"entity_picture","value":""},{"property":"device_class","value":""}],"resend":false,"debugEnabled":false},{"id":"b3c2c46df359d9f0","type":"ha-entity-config","server":"","deviceConfig":"","name":"Steve Office Sw Heat Off BUTTON","version":"6","entityType":"button","haConfig":[{"property":"name","value":"Steve's Office Sw Heat Off BUTTON"},{"property":"icon","value":""},{"property":"entity_category","value":""},{"property":"entity_picture","value":""},{"property":"device_class","value":""}],"resend":false,"debugEnabled":false},{"id":"5c49aaa0acc38789","type":"ha-entity-config","server":"","deviceConfig":"","name":"Steve's Office Heater","version":"6","entityType":"text","haConfig":[{"property":"name","value":"Steve's Office Heater"},{"property":"icon","value":""},{"property":"entity_category","value":""},{"property":"entity_picture","value":""},{"property":"mode","value":"text"},{"property":"min_length","value":""},{"property":"max_length","value":""},{"property":"pattern","value":""}],"resend":false,"debugEnabled":false},{"id":"9092f32700acabd7","type":"ha-entity-config","server":"","deviceConfig":"","name":"Steve Office Sw Heat Boost BUTTON","version":"6","entityType":"button","haConfig":[{"property":"name","value":"Steve's Office Sw Heat Boost BUTTON"},{"property":"icon","value":""},{"property":"entity_category","value":""},{"property":"entity_picture","value":""},{"property":"device_class","value":""}],"resend":false,"debugEnabled":false},{"id":"f8a1347038ecac0e","type":"ha-entity-config","server":"","deviceConfig":"","name":"Steve Office Sw Heat Comfort BUTTON","version":"6","entityType":"button","haConfig":[{"property":"name","value":"Steve's Office Sw Heat Comfort BUTTON"},{"property":"icon","value":""},{"property":"entity_category","value":""},{"property":"entity_picture","value":""},{"property":"device_class","value":""}],"resend":false,"debugEnabled":false}]
In the end, it is very much a matter of personal choice as to how to code something like this, but yes loops in the flow can be problematic. Long ago I worked for a small insurance company and the IT manager brought in a forth gen language and proceeded to write an email system in it. Not being a ‘professional’ programmer he (far too easily) wrote a while loop with no termination, which promptly brought the entire IBM mainframe to a full stop, and the entire company sat around for the best part of an hour while the ops team shut it down and brought everything back on line.