Node Red Radio Buttons

Hello,
I have a need for radio buttons and came up with the following design in Node-Red.

I created four switch entites in NR and cross linked them so that when one turns on, the others are all turned off:

[{"id":"f839fda35840f409","type":"ha-switch","z":"12b919271b59722d","name":"Sw Heat Fall Back","version":0,"debugenabled":false,"inputs":1,"outputs":2,"entityConfig":"88fd477e077c7177","enableInput":true,"outputOnStateChange":true,"outputProperties":[{"property":"outputType","propertyType":"msg","value":"state change","valueType":"str"},{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"enable","propertyType":"msg","value":"false","valueType":"bool"}],"x":1590,"y":2100,"wires":[["5b571ce68a7b7938","4abf0e05ad4b52fc","10aa9e46fc28a10b"],[]]},{"id":"5b571ce68a7b7938","type":"ha-switch","z":"12b919271b59722d","name":"Sw Heat Off","version":0,"debugenabled":false,"inputs":1,"outputs":2,"entityConfig":"0c94a3a8bae58dc6","enableInput":true,"outputOnStateChange":true,"outputProperties":[{"property":"outputType","propertyType":"msg","value":"state change","valueType":"str"},{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"enable","propertyType":"msg","value":"false","valueType":"bool"}],"x":1790,"y":2000,"wires":[["f839fda35840f409","4abf0e05ad4b52fc","10aa9e46fc28a10b"],[]]},{"id":"4abf0e05ad4b52fc","type":"ha-switch","z":"12b919271b59722d","name":"Sw Heat Comfort","version":0,"debugenabled":false,"inputs":1,"outputs":2,"entityConfig":"391c5289cfd48f8d","enableInput":true,"outputOnStateChange":true,"outputProperties":[{"property":"outputType","propertyType":"msg","value":"state change","valueType":"str"},{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"enable","propertyType":"msg","value":"false","valueType":"bool"}],"x":1740,"y":2220,"wires":[["5b571ce68a7b7938","f839fda35840f409","10aa9e46fc28a10b"],[]]},{"id":"10aa9e46fc28a10b","type":"ha-switch","z":"12b919271b59722d","name":"Sw Heat Boost","version":0,"debugenabled":false,"inputs":1,"outputs":2,"entityConfig":"098487e6c83099a9","enableInput":true,"outputOnStateChange":true,"outputProperties":[{"property":"outputType","propertyType":"msg","value":"state change","valueType":"str"},{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"enable","propertyType":"msg","value":"false","valueType":"bool"}],"x":1960,"y":2140,"wires":[["5b571ce68a7b7938","f839fda35840f409","4abf0e05ad4b52fc"],[]]},{"id":"88fd477e077c7177","type":"ha-entity-config","server":"2be748d3.da7088","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":"2be748d3.da7088","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":"2be748d3.da7088","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":"2be748d3.da7088","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},{"id":"2be748d3.da7088","type":"server","name":"Home Assistant","addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"","connectionDelay":false,"cacheJson":false,"heartbeat":true,"heartbeatInterval":"10","statusSeparator":"","enableGlobalContextStore":false}]

I will connect the On outputs to nodes to actually control the heating by calling service climate set temperature.

These four switches are added to a single card
image

Only one can be turned on at a time.

The simulated radio button action seems to work correctly, but I am just a little concerned that there might be conditions that would cause it to start looping. Any insights into conditions that might need to be handled would be much appreciated.

Steve

Some other options could be to use a select entity instead of switches. If you want to stay with switches this may be not prone to race conditions.

[{"id":"d1deee9049e7d93e","type":"ha-switch","z":"120358abd7c22d30","name":"test off","version":0,"debugenabled":false,"inputs":0,"outputs":2,"entityConfig":"ed51c962abf66f6d","enableInput":false,"outputOnStateChange":true,"outputProperties":[{"property":"entityId","propertyType":"msg","value":"switch.test_off","valueType":"str"}],"x":722,"y":3920,"wires":[["309fe172d21101b4"],[]]},{"id":"041d5e0d3eb5eb56","type":"ha-switch","z":"120358abd7c22d30","name":"test cool","version":0,"debugenabled":false,"inputs":0,"outputs":2,"entityConfig":"eebfc2619ed1e7c8","enableInput":false,"outputOnStateChange":true,"outputProperties":[{"property":"entityId","propertyType":"msg","value":"switch.test_cool","valueType":"str"}],"x":732,"y":3968,"wires":[["309fe172d21101b4"],[]]},{"id":"19e4aa36f540e7db","type":"ha-switch","z":"120358abd7c22d30","name":"test warm","version":0,"debugenabled":false,"inputs":0,"outputs":2,"entityConfig":"4e3fabe2318ffee8","enableInput":false,"outputOnStateChange":true,"outputProperties":[{"property":"entityId","propertyType":"msg","value":"switch.test_warm","valueType":"str"}],"x":732,"y":4016,"wires":[["309fe172d21101b4"],[]]},{"id":"a80df52dca615644","type":"ha-switch","z":"120358abd7c22d30","name":"test boost","version":0,"debugenabled":false,"inputs":0,"outputs":2,"entityConfig":"1e7f29f7c4f6cebc","enableInput":false,"outputOnStateChange":true,"outputProperties":[{"property":"entityId","propertyType":"msg","value":"switch.test_boost","valueType":"str"}],"x":732,"y":4064,"wires":[["309fe172d21101b4"],[]]},{"id":"309fe172d21101b4","type":"change","z":"120358abd7c22d30","name":"switch ids","rules":[{"t":"set","p":"payload","pt":"msg","to":"[\"switch.test_off\",\"switch.test_cool\",\"switch.test_warm\",\"switch.test_boost\"]","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":956,"y":3920,"wires":[["38b46e95254940a9"]]},{"id":"38b46e95254940a9","type":"split","z":"120358abd7c22d30","name":"","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":1086,"y":3920,"wires":[["40191d3f609c4d82"]]},{"id":"40191d3f609c4d82","type":"switch","z":"120358abd7c22d30","name":"","property":"payload","propertyType":"msg","rules":[{"t":"neq","v":"entityId","vt":"msg"}],"checkall":"true","repair":true,"outputs":1,"x":1218,"y":3920,"wires":[["c81308a25ad8490c"]]},{"id":"d5770b412665c215","type":"api-call-service","z":"120358abd7c22d30","name":"","server":"","version":5,"debugenabled":true,"domain":"switch","service":"turn_off","areaId":[],"deviceId":[],"entityId":["{{payload}}"],"data":"{}","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1504,"y":3920,"wires":[[]]},{"id":"c81308a25ad8490c","type":"join","z":"120358abd7c22d30","name":"","mode":"auto","build":"object","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","accumulate":"false","timeout":"","count":"","reduceRight":false,"x":1346,"y":3920,"wires":[["d5770b412665c215"]]},{"id":"ed51c962abf66f6d","type":"ha-entity-config","server":"2dad33ee.42bf5c","deviceConfig":"","name":"test off","version":"6","entityType":"switch","haConfig":[{"property":"name","value":"test off"},{"property":"icon","value":""},{"property":"entity_picture","value":""},{"property":"entity_category","value":""},{"property":"device_class","value":""}],"resend":false,"debugEnabled":false},{"id":"eebfc2619ed1e7c8","type":"ha-entity-config","server":"2dad33ee.42bf5c","deviceConfig":"","name":"test cool","version":"6","entityType":"switch","haConfig":[{"property":"name","value":"test cool"},{"property":"icon","value":""},{"property":"entity_picture","value":""},{"property":"entity_category","value":""},{"property":"device_class","value":""}],"resend":false,"debugEnabled":false},{"id":"4e3fabe2318ffee8","type":"ha-entity-config","server":"2dad33ee.42bf5c","deviceConfig":"","name":"test warm","version":"6","entityType":"switch","haConfig":[{"property":"name","value":"test warm"},{"property":"icon","value":""},{"property":"entity_picture","value":""},{"property":"entity_category","value":""},{"property":"device_class","value":""}],"resend":false,"debugEnabled":false},{"id":"1e7f29f7c4f6cebc","type":"ha-entity-config","server":"2dad33ee.42bf5c","deviceConfig":"","name":"test boost","version":"6","entityType":"switch","haConfig":[{"property":"name","value":"test boost"},{"property":"icon","value":""},{"property":"entity_picture","value":""},{"property":"entity_category","value":""},{"property":"device_class","value":""}],"resend":false,"debugEnabled":false}]
1 Like

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.

1 Like

Thank you @Kermit and @Biscuit for the considered replies. I learnt a lot from this.

@Kermit I’ve implemented your example - I like the split, switch, join to loop over all the entities and remove the active one before turning off the remaining ones.

It’s also nice that the switch nodes show their status in NR.

Having the radio button logic is no use unless it can be modelled in the dashboard. I’m not about to go down the rabbit hole of learning how to create custom dashboard components - I did manage to get something that looks about right:

This uses a horizontal stack card with custom tap action

I can get this implemented right away.

@Biscuit I did not know about the FSM node which is very interesting. I shall certainly look at how that can be applied in my flows. I generally use input_text helpers to store intended states, so restoring after a restart should be straightforward.

And yes, I also use links for my sanity, but left them in to illustrate the question :slight_smile:

When I saw your dashboard image I remembered I did something similar for someone using an input_select.

type: entities
entities:
  - entity: input_select.test
type: horizontal-stack
cards:
  - type: custom:button-card
    entity: input_select.test
    name: One
    icon: mdi:numeric-1-circle-outline
    color: var(--state-icon-color)
    state:
      - value: one
        color: var(--state-icon-active-color)
    tap_action:
      action: call-service
      service: input_select.select_option
      service_data:
        entity_id: input_select.test
        option: one
  - type: custom:button-card
    entity: input_select.test
    name: Two
    icon: mdi:numeric-2-circle-outline
    color: var(--state-icon-color)
    state:
      - value: two
        color: var(--state-icon-active-color)
    tap_action:
      action: call-service
      service: input_select.select_option
      service_data:
        entity_id: input_select.test
        option: two
  - type: custom:button-card
    entity: input_select.test
    name: Three
    icon: mdi:numeric-3-circle-outline
    color: var(--state-icon-color)
    state:
      - value: three
        color: var(--state-icon-active-color)
    tap_action:
      action: call-service
      service: input_select.select_option
      service_data:
        entity_id: input_select.test
        option: three
  - type: custom:button-card
    entity: input_select.test
    name: Four
    icon: mdi:numeric-4-circle-outline
    color: var(--state-icon-color)
    state:
      - value: four
        color: var(--state-icon-active-color)
    tap_action:
      action: call-service
      service: input_select.select_option
      service_data:
        entity_id: input_select.test
        option: four

@kermit - interesting. I suppose a drop down list can be semantically the same as a radio button group (if single selection is enforced).

The real work in all these solutions is to have the climate control mirror the radio buttons and vice-versa.

b.t.w. some of the discussions in HA Community are are marked as answered, but I can’t see how to do that on my questions.

It’s work, Thank a lot