Best way to wire switches in parallell?

Would appreciate some help with the attached flow.

The flow works but is a bit of a hack and I would appreciate a hint or two of how you would do this to optimize it.
It is simply three switches wired in parallell. One for Home kit, one for the Node red dashboard and one for a physical Shelly relay.
All serve to switch the Shelly the same way.
A physical moment switch at the shelly and the two soft switches should switch it the same, and also reflect a change anywhere between the three of them, yet not create a loop. I am unable to come up with a clean and robust solution. But again, this appears to work, so is perhaps a half-decent way to at least show why I am trying to do..

Can you suggest a cleaner and more robust way of doing this by any chance? Many thanks!

[ { "id": "bd02da3896c29e8e", "type": "group", "z": "eef618ccc6e2ee8c", "name": "", "style": { "fill": "#c8e7a7", "label": true }, "nodes": [ "6cf1745b3ff6c936", "4af867cdef1fe329", "471bab8f3e6f3ee5", "2d525d44e40f0620", "7474a3430fe26c3b", "fc59cc75739f647e", "275e3477b122dccb", "d51fad32e4e06e01", "9d8303659e2b8c88", "1ba86a8a37c44aad", "4a56db0a0217c071", "bee423ae8e3b77bd", "ee6fb4a6d08475c3", "06ddbd6bdb128515", "1d06c797a0da1a3a", "9f7eb3b869ac7d8a", "24ffd3e970e86e62", "8347e45955618064", "56b25b4442efe183", "7724b8fa22901271" ], "x": 74, "y": 119, "w": 1192, "h": 522 }, { "id": "6cf1745b3ff6c936", "type": "homekit-service", "z": "eef618ccc6e2ee8c", "g": "bd02da3896c29e8e", "isParent": true, "hostType": "0", "bridge": "1d2439381726168b", "accessoryId": "", "parentService": "", "name": "Switch 3 - Homekit", "serviceName": "Switch", "topic": "", "filter": false, "manufacturer": "NRCHKB", "model": "1.3.6", "serialNo": "Default Serial Number", "firmwareRev": "1.3.6", "hardwareRev": "1.3.6", "softwareRev": "1.3.6", "cameraConfigVideoProcessor": "ffmpeg", "cameraConfigSource": "", "cameraConfigStillImageSource": "", "cameraConfigMaxStreams": 2, "cameraConfigMaxWidth": 1280, "cameraConfigMaxHeight": 720, "cameraConfigMaxFPS": 10, "cameraConfigMaxBitrate": 300, "cameraConfigVideoCodec": "libx264", "cameraConfigAudioCodec": "libfdk_aac", "cameraConfigAudio": false, "cameraConfigPacketSize": 1316, "cameraConfigVerticalFlip": false, "cameraConfigHorizontalFlip": false, "cameraConfigMapVideo": "0:0", "cameraConfigMapAudio": "0:1", "cameraConfigVideoFilter": "scale=1280:720", "cameraConfigAdditionalCommandLine": "-tune zerolatency", "cameraConfigDebug": false, "cameraConfigSnapshotOutput": "disabled", "cameraConfigInterfaceName": "", "characteristicProperties": "{}", "waitForSetupMsg": false, "outputs": 2, "x": 810, "y": 440, "wires": [ [ "4af867cdef1fe329", "7474a3430fe26c3b", "8347e45955618064" ], [] ] }, { "id": "4af867cdef1fe329", "type": "ui_switch", "z": "eef618ccc6e2ee8c", "g": "bd02da3896c29e8e", "name": "Switch 2 - NR Dash", "label": "Switch 2 - NR Dash", "tooltip": "", "group": "e48e8a33f9fc6cf2", "order": 1, "width": 7, "height": 1, "passthru": true, "decouple": "false", "topic": "payload", "topicType": "msg", "style": "", "onvalue": "{\"On\":true}", "onvalueType": "json", "onicon": "", "oncolor": "", "offvalue": "{\"On\":false}", "offvalueType": "json", "officon": "", "offcolor": "", "animate": true, "className": "", "x": 820, "y": 380, "wires": [ [ "6cf1745b3ff6c936", "56b25b4442efe183" ] ] }, { "id": "471bab8f3e6f3ee5", "type": "shelly-gen2", "z": "eef618ccc6e2ee8c", "g": "bd02da3896c29e8e", "hostname": "", "description": "Switch 1 Shelly", "pollinginterval": 5000, "pollstatus": true, "getstatusoncommand": true, "devicetype": "Relay", "outputs": 1, "credentials": { "username": "", "password": "" }, "x": 500, "y": 500, "wires": [ [ "275e3477b122dccb", "7724b8fa22901271" ] ] }, { "id": "2d525d44e40f0620", "type": "switch", "z": "eef618ccc6e2ee8c", "g": "bd02da3896c29e8e", "name": "split", "property": "payload", "propertyType": "msg", "rules": [ { "t": "eq", "v": "{\"On\":true}", "vt": "str" }, { "t": "eq", "v": "{\"On\":false}", "vt": "str" } ], "checkall": "true", "repair": false, "outputs": 2, "x": 250, "y": 320, "wires": [ [ "9d8303659e2b8c88" ], [ "4a56db0a0217c071" ] ] }, { "id": "7474a3430fe26c3b", "type": "delay", "z": "eef618ccc6e2ee8c", "g": "bd02da3896c29e8e", "name": "", "pauseType": "rate", "timeout": "5", "timeoutUnits": "seconds", "rate": "1", "nbRateUnits": "5", "rateUnits": "second", "randomFirst": "1", "randomLast": "5", "randomUnits": "seconds", "drop": true, "allowrate": false, "outputs": 1, "x": 180, "y": 500, "wires": [ [ "fc59cc75739f647e" ] ] }, { "id": "fc59cc75739f647e", "type": "json", "z": "eef618ccc6e2ee8c", "g": "bd02da3896c29e8e", "name": "", "property": "payload", "action": "", "pretty": false, "x": 250, "y": 360, "wires": [ [ "2d525d44e40f0620" ] ] }, { "id": "275e3477b122dccb", "type": "json", "z": "eef618ccc6e2ee8c", "g": "bd02da3896c29e8e", "name": "", "property": "payload", "action": "", "pretty": false, "x": 770, "y": 220, "wires": [ [ "bee423ae8e3b77bd" ] ] }, { "id": "d51fad32e4e06e01", "type": "inject", "z": "eef618ccc6e2ee8c", "g": "bd02da3896c29e8e", "name": "Turn On", "props": [ { "p": "payload", "v": "", "vt": "date" }, { "p": "topic", "v": "", "vt": "str" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "", "payloadType": "date", "x": 490, "y": 220, "wires": [ [ "9d8303659e2b8c88" ] ] }, { "id": "9d8303659e2b8c88", "type": "function", "z": "eef618ccc6e2ee8c", "g": "bd02da3896c29e8e", "name": "0 on", "func": "msg.payload = {\n method: \"Switch.Set\",\n parameters : {\n id : 0,\n on : true,\n // toggle_after : 2 // optional flip back time in seconds\n }\n};\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 490, "y": 260, "wires": [ [ "471bab8f3e6f3ee5" ] ] }, { "id": "1ba86a8a37c44aad", "type": "inject", "z": "eef618ccc6e2ee8c", "g": "bd02da3896c29e8e", "name": "Turn Off", "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "", "payloadType": "date", "x": 490, "y": 300, "wires": [ [ "4a56db0a0217c071" ] ] }, { "id": "4a56db0a0217c071", "type": "function", "z": "eef618ccc6e2ee8c", "g": "bd02da3896c29e8e", "name": "0 off", "func": "msg.payload = {\n method: \"Switch.Set\",\n parameters : {\n id : 0,\n on : false,\n // toggle_after : 2 // optional flip back time in seconds\n }\n};\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 490, "y": 340, "wires": [ [ "471bab8f3e6f3ee5" ] ] }, { "id": "bee423ae8e3b77bd", "type": "switch", "z": "eef618ccc6e2ee8c", "g": "bd02da3896c29e8e", "name": "", "property": "payload", "propertyType": "msg", "rules": [ { "t": "cont", "v": "output\":true", "vt": "str" }, { "t": "cont", "v": "output\":false", "vt": "str" } ], "checkall": "true", "repair": false, "outputs": 2, "x": 770, "y": 260, "wires": [ [ "ee6fb4a6d08475c3" ], [ "06ddbd6bdb128515" ] ] }, { "id": "ee6fb4a6d08475c3", "type": "ui_button", "z": "eef618ccc6e2ee8c", "g": "bd02da3896c29e8e", "name": "{\"On\":true}", "group": "e48e8a33f9fc6cf2", "order": 14, "width": 0, "height": 0, "passthru": true, "label": "{\"On\":true}", "tooltip": "", "color": "", "bgcolor": "", "className": "", "icon": "", "payload": "{\"On\":true}", "payloadType": "json", "topic": "topic", "topicType": "msg", "x": 790, "y": 300, "wires": [ [ "4af867cdef1fe329" ] ] }, { "id": "06ddbd6bdb128515", "type": "ui_button", "z": "eef618ccc6e2ee8c", "g": "bd02da3896c29e8e", "name": "{\"On\":false}", "group": "e48e8a33f9fc6cf2", "order": 14, "width": 0, "height": 0, "passthru": true, "label": "{\"On\":false}", "tooltip": "", "color": "", "bgcolor": "", "className": "", "icon": "", "payload": "{\"On\":false}", "payloadType": "json", "topic": "topic", "topicType": "msg", "x": 790, "y": 340, "wires": [ [ "4af867cdef1fe329" ] ] }, { "id": "1d06c797a0da1a3a", "type": "comment", "z": "eef618ccc6e2ee8c", "g": "bd02da3896c29e8e", "name": "3 switches in parallell. Each switch needs to be able to switch on and off and the other two switches need to reflect changes. All without creating a loop.", "info": "", "x": 630, "y": 160, "wires": [] }, { "id": "9f7eb3b869ac7d8a", "type": "comment", "z": "eef618ccc6e2ee8c", "g": "bd02da3896c29e8e", "name": "This Shelly is a physical relay that can also be switched with a physical button", "info": "", "x": 420, "y": 560, "wires": [] }, { "id": "24ffd3e970e86e62", "type": "comment", "z": "eef618ccc6e2ee8c", "g": "bd02da3896c29e8e", "name": "So the Shelly needs to be the master state", "info": "", "x": 440, "y": 600, "wires": [] }, { "id": "8347e45955618064", "type": "debug", "z": "eef618ccc6e2ee8c", "g": "bd02da3896c29e8e", "name": "Switch 3 - Homekit", "active": true, "tosidebar": true, "console": false, "tostatus": true, "complete": "true", "targetType": "full", "statusVal": "payload", "statusType": "auto", "x": 1090, "y": 460, "wires": [] }, { "id": "56b25b4442efe183", "type": "debug", "z": "eef618ccc6e2ee8c", "g": "bd02da3896c29e8e", "name": "Switch 2 - NR Dash", "active": true, "tosidebar": true, "console": false, "tostatus": true, "complete": "true", "targetType": "full", "statusVal": "payload", "statusType": "auto", "x": 1100, "y": 380, "wires": [] }, { "id": "7724b8fa22901271", "type": "debug", "z": "eef618ccc6e2ee8c", "g": "bd02da3896c29e8e", "name": "Switch 1 - Shelly Gen 2", "active": true, "tosidebar": true, "console": false, "tostatus": true, "complete": "true", "targetType": "full", "statusVal": "payload", "statusType": "auto", "x": 1110, "y": 520, "wires": [] }, { "id": "1d2439381726168b", "type": "homekit-bridge", "bridgeName": "Dev share 1b", "pinCode": "033-96-068", "port": "", "advertiser": "bonjour-hap", "allowInsecureRequest": false, "manufacturer": "NRCHKB", "model": "1.4.3", "serialNo": "Default Serial Number", "firmwareRev": "1.4.3", "hardwareRev": "1.4.3", "softwareRev": "1.4.3", "customMdnsConfig": false, "mdnsMulticast": true, "mdnsInterface": "", "mdnsPort": "", "mdnsIp": "", "mdnsTtl": "", "mdnsLoopback": true, "mdnsReuseAddr": true, "allowMessagePassthrough": true }, { "id": "e48e8a33f9fc6cf2", "type": "ui_group", "name": "Default", "tab": "3ecaa427cf920875", "order": 1, "disp": true, "width": "7", "collapse": true, "className": "" }, { "id": "3ecaa427cf920875", "type": "ui_tab", "name": "Dev share", "icon": "dashboard", "disabled": false, "hidden": false } ]

I don't have your custom nodes so cannot really test.
Can you please explain why you need 3 switches for one device ?

Thanks for reply. Sure. One is the physical relay with a physical button that can also be switched via a web gui, one is to access that relay via the Apple HomeKit app and the last one is to access it via the node red dash.

For the dashboard switch, set it to NOT pass messages through, and to to show state of INPUT. Feed the actual state of the external device into the front of the dashboard switch. The result is that if the device is switched externally then the dashboard will show the new state, and if the dashboard switch is clicked it will send the new state to the device, which will then report the new state, so the dashboard state shown will follow it. If, for some reason, the external device does not change state then the state shown on the dashboard will not change.

1 Like

Many thanks @Colin
Very useful info, as the Shelly needs to be the master state.
How would you suggest we wire the second HK switch in order not to create any loop?

  1. The same in parallell basically? That means they both get updated at the same time but may perhaps send dual messages out when updated. I guess I can solve that with a rate limit that drops intermediate messages..
  2. Is there another approach worth trying in your opinion?

So looking at your flow you have 2 buttons and a switch on the same dashboard.

As far as I can tell they are all inteded to switch the same device, so I don't understand why you cannot just have 1 switch to operate the relay and show the current state of the relay (and also if it was changed locally)
I guess the state comes from the shelly node, not sure what the homekit node does ?

I don't see any connection from the switches other than debug so how is the flow working ?

Thanks @smcgann99
The two soft switches are for different GUI, HomeKit and Node Red Dash.
The flow, as mentioned is working. I just feel it could be better...
Many thanks

Perhaps you posted the wrong flow then, as you have functions nodes and buttons/switches which do not connect to anything else ?

It is the correct flow. I checked again to make sure.
I would assume you do not have all the nodes in your own palette?

I just imported again and can now see the wires.

Its the logic I don't really get, you say The two soft switches are for different GUI, HomeKit and Node Red Dash but they are both on the same dashboard group.

If they all operate the same device why have more than 1 switch ?

I am sorry if I am unclear. But Home kit and Node Red Dash are two different GUI:s.
Again, the Shelly is the physical relay with a physical button attached but can also be switched via a web gui, one is to access that relay via the Apple HomeKit app and the last one is to access it via the node red dash. I hope this makes sense.
Node Red Dash is far adminsand HomeKit for a number of people that use the system daily.
There are a bunch of these relays for various voltages so that is why this is so important to me. Many thanks.

The Apple HomeKit app has its own gui, so why do you need the extra button / switch in the NR dashboard ?

As mentioned, for admins.

We seem to be going around in circles here :wink:

Its logic behind having 2 buttons and a switch in NR that confuses me as I don’t see any need for it.

  1. I don’t use home kit but I assume in principal its the same as using an Alexa or google app to control the device ?

  2. Does the actual home kit app control the device directly (i.e. independent of NR) or is it like a virtual device which just sends a message to NR, which you then need to act on to control the device ?

The way I would do this is to have 1 switch on the NR dashboard. This would send control message to the Shelly. I assume you will then get a response from the shelly. You use this message to update the switch state on the NR dashboard.

If the shelly is controlled locally (via buttons or web interface, or possibly direct from home kit app ?) you should get a message also, so this will also update the switch to show the correct state in NR.

Depending on the answers to above you may need to interpret the messages from home kit and translate to shelly format then forward to shelly, which will then generate a response from shelly again updating your NR dashboard switch.

If necessary, to keep home kit app in sync, then this shelly response may then need translating to home kit format and sending back to home kit.

So you have a variety of ways to control the shelly, but only need 1 switch in NR dashboard to control and show status from there.

Yes. That is what the flow does.
I now see what you mean. The two extra on/off dashboard buttons are not seen on the dash. They are just used instead of function nodes as I could not get that payload to work properly in a function node.

As mentioned, it all works, I just think it could be done much cleaner and it is beyond my skillset.

I'm sure it could - if you post all the required messages shelly in/out and homekit in/out then I could take a look, or just leave well alone :wink:

Well if you have a moment to replace the mentioned NR dash buttons with regular properly formatted function nodes that would be really useful. Both switches use the HomeKit standard for the switching to try and be as simple in there as possible. So you see the required on/off right there. {"On":true} and {"On":false}
The required payload for the shelly is in the function node above it. That is the one thing I am 100% sure is correct :wink:
If you switch it off it will spit out this as payload object: {"was_on":false} and this if you switch it on: {"was_on":true} .
It will also send out its state every once in a while in a large object that looks like this:

{"status":{"ble":{},"cloud":{"connected":false},"input:0":{"id":0,"state":false},"mqtt":{"connected":true},"switch:0":{"id":0,"source":"HTTP","output":true,"apower":0,"voltage":216.2,"current":0,"aenergy":{"total":0,"by_minute":[0,0,0],"minute_ts":1649099876},"temperature":{"tC":54.4,"tF":129.9}},"sys":{"mac":"308398098C68","restart_required":false,"time":"21:18","unixtime":1649099880,"uptime":388265,"ram_size":254680,"ram_free":140136,"fs_size":458752,"fs_free":221184,"cfg_rev":40,"available_updates":{}},"wifi":{"sta_ip":"192.168.xxxx","status":"got ip","ssid":"xxxxn","rssi":-49}},"payload":{"switch0":{"id":0,"source":"HTTP","output":true,"apower":0,"voltage":216.2,"current":0,"aenergy":{"total":0,"by_minute":[0,0,0],"minute_ts":1649099876},"temperature":{"tC":54.4,"tF":129.9}},"input0":{"id":0,"state":false}},"_msgid":"d38e2ea19ba21cbf"}

This is one of the things I find hard to reconcile. In the flow example I am using the http state which is strings in the shape of output":true andoutput":false
Ah well. A little ugly....
Any improvements or suggestions would be much appreciated. Many thanks for listening!

Try this - you will need to replace the shelly and homekit function nodes with the correct nodes as these were for testing (without your nodes installed)

If it doesn't work check the payloads are correct as they come from your homekit and shelly nodes.

[{"id":"b8fdb2449c1363cb","type":"ui_switch","z":"ec5a1f5f47a9879b","name":"Switch 2 - NR Dash","label":"Switch 2 - NR Dash","tooltip":"","group":"e48e8a33f9fc6cf2","order":1,"width":7,"height":1,"passthru":false,"decouple":"true","topic":"","topicType":"str","style":"","onvalue":"{\"On\":true}","onvalueType":"json","onicon":"","oncolor":"","offvalue":"{\"On\":false}","offvalueType":"json","officon":"","offcolor":"","animate":true,"className":"","x":1310,"y":500,"wires":[["8abbebd5c5039926","8476d59a003e0353"]]},{"id":"8476d59a003e0353","type":"switch","z":"ec5a1f5f47a9879b","name":"split","property":"payload.On","propertyType":"msg","rules":[{"t":"true"},{"t":"false"}],"checkall":"true","repair":false,"outputs":2,"x":570,"y":500,"wires":[["406d54dab9ecc466"],["0f0fe955fb98a718"]]},{"id":"386ce8fc17a223ce","type":"inject","z":"ec5a1f5f47a9879b","name":"Turn On","props":[{"p":"payload.On","v":"true","vt":"bool"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":380,"y":360,"wires":[["8476d59a003e0353"]]},{"id":"9ec79414c9339ba7","type":"debug","z":"ec5a1f5f47a9879b","name":"Switch 3 - Homekit","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"true","targetType":"full","statusVal":"payload","statusType":"auto","x":510,"y":580,"wires":[]},{"id":"8abbebd5c5039926","type":"debug","z":"ec5a1f5f47a9879b","name":"Switch 2 - NR Dash","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"true","targetType":"full","statusVal":"payload.On","statusType":"msg","x":1570,"y":500,"wires":[]},{"id":"734df8cd94bafeda","type":"function","z":"ec5a1f5f47a9879b","name":"homekit","func":"\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":340,"y":500,"wires":[["9ec79414c9339ba7","8476d59a003e0353"]]},{"id":"f1a8aca756746b5e","type":"function","z":"ec5a1f5f47a9879b","name":"shelly","func":"msg.payload = { \"was_on\": msg.payload.parameters.on }\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":870,"y":500,"wires":[["2d04c8f6a4e855b9","79b347878a4f2212"]]},{"id":"2d04c8f6a4e855b9","type":"debug","z":"ec5a1f5f47a9879b","name":"Switch 1 - Shelly Gen 2","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"true","targetType":"full","statusVal":"payload","statusType":"auto","x":1050,"y":420,"wires":[]},{"id":"406d54dab9ecc466","type":"function","z":"ec5a1f5f47a9879b","name":"0 on","func":"msg.payload = {\n    method: \"Switch.Set\",\n    parameters: {\n        id: 0,\n        on: true\n    }\n};\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":710,"y":460,"wires":[["f1a8aca756746b5e"]]},{"id":"0f0fe955fb98a718","type":"function","z":"ec5a1f5f47a9879b","name":"0 off","func":"msg.payload = {\n    method: \"Switch.Set\",\n    parameters: {\n        id: 0,\n        on: false\n    }\n};\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":710,"y":500,"wires":[["f1a8aca756746b5e"]]},{"id":"79b347878a4f2212","type":"change","z":"ec5a1f5f47a9879b","name":"","rules":[{"t":"set","p":"payload.On","pt":"msg","to":"payload.was_on","tot":"msg"},{"t":"delete","p":"payload.was_on","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1060,"y":500,"wires":[["b8fdb2449c1363cb"]]},{"id":"7f0c6e27ca8e02c1","type":"inject","z":"ec5a1f5f47a9879b","name":"Turn Off","props":[{"p":"payload.On","v":"false","vt":"bool"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":380,"y":420,"wires":[["8476d59a003e0353"]]},{"id":"e48e8a33f9fc6cf2","type":"ui_group","name":"Default","tab":"3ecaa427cf920875","order":1,"disp":true,"width":"7","collapse":true,"className":""},{"id":"3ecaa427cf920875","type":"ui_tab","name":"Dev share","icon":"dashboard","disabled":false,"hidden":false}]

Hello @smcgann99 !
Sorry for late reply. Some travelling..
Many thanks for your suggested flow.
Will try these today and report back!

Edit: I can see that the HomeKit node in your example is not in the loop to have its state updated by the other switches. That is a requirement.
The change node you suggest is also not updating the NR dash switch
as it still has the HK payload configured.Many thanks though!

The change node was based on this message from shelly ?

it should change this message to HK format and update the switch state.

If you move the connection from the switch output to the HK input instaed of change node that should update the state - I don't know if HK would then re send a new message ? If it does then all is good.

If not then put a 2nd link from swtich out to change node (split)