Gang virtual switch with physical switch? (Link to solution)

Hi everyone. I’m trying to find a way to create a virtual switch in HA that is “linked” to a physical switch or light.

There are a couple of reason for wanting this, the main one being that I want to replace all of my wall switches with Sonoff M5 switches, and some of them have Hue bulbs. So when I send a voice command, I will mention a virtual RGB dimmer, and this virtual dimmer will then turn on or off the Sonoff switch and send the RGB/brightness commands to the Hue bulb.
I know I could make the Sonoff switches just work as “remotes” and not actually cut the power to the bulbs, but I’ve done some tests and I don’t like the delays and fade times when using the physical switches.

Also, I want the nodes to be easily editable, I’ve tried this in my first Node Red automation where I just set a device list on the Inject or Event state node, and the rest of the nodes pick the device names from the messages. This allows me to use the same node block with different devices without needing to edit a lot of things every time I copy and paste the block.

As this setup can easily create an insane on/off loop if the switches are actioned a couple of times too fast, I’m adding a bypass flow variable. But the thing is that I’m not being able to make the switch node react to the variable’s content.

[{"id":"fbb020a344ed4251","type":"tab","label":"Flow 2","disabled":false,"info":"","env":[]},{"id":"e161424c0c2c3e42","type":"server-state-changed","z":"fbb020a344ed4251","name":"switch.sonoff_10009bbf5d","server":"8a86b0cc.b2bac","version":4,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityidfilter":"switch.sonoff_10009bbf5d","entityidfiltertype":"exact","outputinitially":false,"state_type":"str","haltifstate":"","halt_if_type":"str","halt_if_compare":"is","outputs":1,"output_only_on_state_change":true,"for":"0","forType":"num","forUnits":"minutes","ignorePrevStateNull":false,"ignorePrevStateUnknown":false,"ignorePrevStateUnavailable":false,"ignoreCurrentStateUnknown":false,"ignoreCurrentStateUnavailable":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"eventData"},{"property":"topic","propertyType":"msg","value":"","valueType":"triggerId"},{"property":"bypassVar","propertyType":"msg","value":"laundryBypass","valueType":"str"},{"property":"otherDevice","propertyType":"msg","value":"input_boolean.laundry_light_test","valueType":"str"}],"x":150,"y":100,"wires":[["5012dc4cef66dc47"]]},{"id":"a0ff4820a55518c9","type":"server-state-changed","z":"fbb020a344ed4251","name":"input_boolean.laundry_light_test","server":"8a86b0cc.b2bac","version":4,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityidfilter":"input_boolean.laundry_light_test","entityidfiltertype":"exact","outputinitially":false,"state_type":"str","haltifstate":"","halt_if_type":"str","halt_if_compare":"is","outputs":1,"output_only_on_state_change":true,"for":"0","forType":"num","forUnits":"minutes","ignorePrevStateNull":false,"ignorePrevStateUnknown":false,"ignorePrevStateUnavailable":false,"ignoreCurrentStateUnknown":false,"ignoreCurrentStateUnavailable":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"eventData"},{"property":"topic","propertyType":"msg","value":"","valueType":"triggerId"},{"property":"bypassVar","propertyType":"msg","value":"laundryBypass","valueType":"str"},{"property":"otherDevice","propertyType":"msg","value":"switch.sonoff_10009bbf5d","valueType":"str"}],"x":170,"y":160,"wires":[["5012dc4cef66dc47"]]},{"id":"1c866e9fe066e5bc","type":"change","z":"fbb020a344ed4251","name":"set bypass true","rules":[{"t":"set","p":"{{bypassVar}}","pt":"flow","to":"true","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":600,"y":100,"wires":[["3c50890b26485123"]]},{"id":"5012dc4cef66dc47","type":"switch","z":"fbb020a344ed4251","name":"if bypass is false","property":"{{bypassVar}}","propertyType":"flow","rules":[{"t":"false"}],"checkall":"true","repair":false,"outputs":1,"x":420,"y":100,"wires":[["1c866e9fe066e5bc","4bc88cbae40d8351"]]},{"id":"3c50890b26485123","type":"switch","z":"fbb020a344ed4251","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"on","vt":"str"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":750,"y":100,"wires":[["72e17a8ce1674c5f"],["09f09295b30a74b6"]]},{"id":"72e17a8ce1674c5f","type":"api-call-service","z":"fbb020a344ed4251","name":"","server":"8a86b0cc.b2bac","version":5,"debugenabled":false,"domain":"light","service":"turn_on","areaId":[],"deviceId":[],"entityId":["{{otherDevice}}"],"data":"","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":450,"y":180,"wires":[["8983ad9def963421","00c3f64cb0421198"]]},{"id":"09f09295b30a74b6","type":"api-call-service","z":"fbb020a344ed4251","name":"","server":"8a86b0cc.b2bac","version":5,"debugenabled":false,"domain":"light","service":"turn_off","areaId":[],"deviceId":[],"entityId":["{{otherDevice}}"],"data":"","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":450,"y":220,"wires":[["8983ad9def963421","00c3f64cb0421198"]]},{"id":"8983ad9def963421","type":"change","z":"fbb020a344ed4251","name":"set bypass false","rules":[{"t":"set","p":"{{bypassVar}}","pt":"flow","to":"false","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":740,"y":200,"wires":[[]]},{"id":"00c3f64cb0421198","type":"debug","z":"fbb020a344ed4251","name":"debug 7","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":660,"y":260,"wires":[]},{"id":"4bc88cbae40d8351","type":"debug","z":"fbb020a344ed4251","name":"debug 8","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":580,"y":40,"wires":[]},{"id":"8a86b0cc.b2bac","type":"server","name":"Home Assistant","version":4,"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"}]

Does every call service node need the Domain set up? If I’m just turning switches and lights on and off, what’s the use of indicating the domain?
What’s the best way to create a virtual switch for this purpose? I imagine I would need the virtual switch to have the same domain as the lights I want to control (I’m currently using an input boolean).

Feel free to give your suggestions, I’m interested in trying different ways of achieving this.
Thanks a lot,
Rodrigo

Based on some debug nodes I added, it seems that the complete message is not going though the first Switch node. Could anyone point me in the right direction here on how to make nodes take the names of variables from other msg. objects?

[{"id":"ec5ee033a945c83c","type":"inject","z":"fbb020a344ed4251","name":"switch.sonoff_10009bbf5d on","props":[{"p":"payload"},{"p":"topic","vt":"str"},{"p":"bypassVar","v":"laundryBypass","vt":"str"},{"p":"otherDevice","v":"input_boolean.laundry_light_test","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"switch.sonoff_10009bbf5d","payload":"on","payloadType":"str","x":180,"y":1200,"wires":[["1fea37218852de08"]]},{"id":"08c462625c8e2520","type":"inject","z":"fbb020a344ed4251","name":"switch.sonoff_10009bbf5d off","props":[{"p":"payload"},{"p":"topic","vt":"str"},{"p":"bypassVar","v":"laundryBypass","vt":"str"},{"p":"otherDevice","v":"input_boolean.laundry_light_test","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"switch.sonoff_10009bbf5d","payload":"off","payloadType":"str","x":180,"y":1240,"wires":[["1fea37218852de08"]]},{"id":"b9eb91abe8bb33c8","type":"inject","z":"fbb020a344ed4251","name":"input_boolean.laundry_light_test on","props":[{"p":"payload"},{"p":"topic","vt":"str"},{"p":"bypassVar","v":"laundryBypass","vt":"str"},{"p":"otherDevice","v":"switch.sonoff_10009bbf5d","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"input_boolean.laundry_light_test","payload":"on","payloadType":"str","x":200,"y":1280,"wires":[["1fea37218852de08"]]},{"id":"894494cb80d11176","type":"inject","z":"fbb020a344ed4251","name":"input_boolean.laundry_light_test off","props":[{"p":"payload"},{"p":"topic","vt":"str"},{"p":"bypassVar","v":"laundryBypass","vt":"str"},{"p":"otherDevice","v":"switch.sonoff_10009bbf5d","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"input_boolean.laundry_light_test","payload":"off","payloadType":"str","x":200,"y":1320,"wires":[["1fea37218852de08"]]},{"id":"f16d1556e5e8d76a","type":"debug","z":"fbb020a344ed4251","name":"debug 14","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":620,"y":1180,"wires":[]},{"id":"27fda9bc455e6f74","type":"change","z":"fbb020a344ed4251","name":"set bypass true","rules":[{"t":"set","p":"{{bypassVar}}","pt":"flow","to":"true","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":640,"y":1220,"wires":[["e14cc840ffb03e57","476b741716e85d17"]]},{"id":"1fea37218852de08","type":"switch","z":"fbb020a344ed4251","name":"if bypass is false","property":"{{bypassVar}}","propertyType":"flow","rules":[{"t":"false"}],"checkall":"true","repair":false,"outputs":1,"x":440,"y":1220,"wires":[["27fda9bc455e6f74","f16d1556e5e8d76a"]]},{"id":"e14cc840ffb03e57","type":"switch","z":"fbb020a344ed4251","name":"","property":"payload","propertyType":"flow","rules":[{"t":"eq","v":"on","vt":"str"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":490,"y":1340,"wires":[["e905f89c1cf89f2a"],["6ff91eaa3fef4872"]]},{"id":"e905f89c1cf89f2a","type":"api-call-service","z":"fbb020a344ed4251","name":"","server":"8a86b0cc.b2bac","version":5,"debugenabled":false,"domain":"light","service":"turn_on","areaId":[],"deviceId":[],"entityId":["{{otherDevice}}"],"data":"","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":690,"y":1320,"wires":[["f17f29c67500073f"]]},{"id":"6ff91eaa3fef4872","type":"api-call-service","z":"fbb020a344ed4251","name":"","server":"8a86b0cc.b2bac","version":5,"debugenabled":false,"domain":"light","service":"turn_off","areaId":[],"deviceId":[],"entityId":["{{otherDevice}}"],"data":"","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":690,"y":1380,"wires":[["f17f29c67500073f"]]},{"id":"f17f29c67500073f","type":"change","z":"fbb020a344ed4251","name":"set bypass false","rules":[{"t":"set","p":"{{bypassVar}}","pt":"flow","to":"false","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":900,"y":1340,"wires":[[]]},{"id":"476b741716e85d17","type":"debug","z":"fbb020a344ed4251","name":"debug 15","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":860,"y":1220,"wires":[]},{"id":"5dc658b53a5ff003","type":"inject","z":"fbb020a344ed4251","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":140,"y":1440,"wires":[["e953372342f8da79"]]},{"id":"e953372342f8da79","type":"change","z":"fbb020a344ed4251","name":"","rules":[{"t":"set","p":"laundryBypass","pt":"flow","to":"true","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":360,"y":1440,"wires":[[]]},{"id":"4fdc16553d1ca530","type":"change","z":"fbb020a344ed4251","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"laundryBypass","tot":"flow"}],"action":"","property":"","from":"","to":"","reg":false,"x":320,"y":1520,"wires":[["42ab06584c6a6742"]]},{"id":"a181caf621f23d67","type":"inject","z":"fbb020a344ed4251","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":140,"y":1520,"wires":[["4fdc16553d1ca530"]]},{"id":"42ab06584c6a6742","type":"debug","z":"fbb020a344ed4251","name":"debug 16","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":500,"y":1520,"wires":[]},{"id":"8a86b0cc.b2bac","type":"server","name":"Home Assistant","version":4,"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"}]

Thanks!
Rodrgo

I’m not sure what you are trying to accomplish but in general, at the bottom of some HA nodes there is an output option. Make sure that is set to entity and not entity state.

image

To pass a variable from an incoming message, use J;expression and the message path.

{"brightness":payload.attributes.brightness}

1 Like

Just to keep things closed, here’s the post with the solutions I found, thanks to @Mikefila and to user bakman2 from node red forum.

Rodrigo