Two-way switch with two one-way switches

I have z-wave neo coolcam wall switches. Two one-way switches are located on opposite sides of the corridor, connected to different lights.

The idea was to make automation, in which when you turn on one of the switches, the second one also turns on. Conversely, when you turn off any of them, the second one also turns off.

- id: '1556723254319'
  alias: TURN ON
  trigger:
  - entity_id: switch.shenzhen_neo_1
    platform: state
    to: 'on'
  - entity_id: switch.shenzhen_neo_2
    platform: state
    to: 'on'
  condition: []
  action:
  - data:
      entity_id: switch.shenzhen_neo_1
    service: switch.turn_on
  - data:
      entity_id: switch.shenzhen_neo_2
    service: switch.turn_on
- id: '1556723807512'
  alias: TURN OFF
  trigger:
  - entity_id: switch.shenzhen_neo_1
    platform: state
    to: 'off'
  - entity_id: switch.shenzhen_neo_2
    platform: state
    to: 'off'
  condition: []
  action:
  - data:
      entity_id: switch.shenzhen_neo_1
    service: switch.turn_off
  - data:
      entity_id: switch.shenzhen_neo_2
    service: switch.turn_off

It works, but after one time:
I turn on switch 1 - switch 2 remains off
I turn off switch 1 - switch 2 remains off
I turn on switch 1 - switch 2 is turned on
I turn off switch 1 - switch 2 remains on
I turn on switch 1 - switch 2 remains on
I turn off switch 1 - switch 2 is turned off

And so on. Same with the other switch. What am I doing wrong in automation?

Try this:

- alias: 'Sync Lights'
  trigger:
  - platform: state
    entity_id: switch.shenzhen_neo_1, switch.shenzhen_neo_2
  action:
  - service_template: "switch.turn_{{trigger.to_state.state}}"
    data_template:
      entity_id: "switch.shenzhen_neo_{{'2' if trigger.to_state.object_id[-1:] == '1' else '1'}}"
  • The automation is triggered by either one of the two switches changing state from off to on or on to off.
  • The service_template determines which service to call, either turn_on or turn_off, based on which state-change triggered the automation (using trigger_to_state.state).
  • The data_template determines which of the two switches to use. It should choose the opposite switch from the one that triggered the automation. It does this by looking at the name of whichever switch triggered the automation (trigger.to_state.object_id). If the last character in the name is 1 then it should use switch 2. Otherwise, it will use switch 1.

I tried your version, but the effect is exactly the same :frowning:
Have to turn on and turn off one of switches several times until the second one operates. It is not in random order, but each time by one algorithm, the same as I indicated in the first post.

Addition: If you switch the light in the HASS, the switches are synchronized, everything works correctly. And if you use the device physical, then you need to click a few times as I wrote above.

Interesting. I made a different version for myself, using my own lights, and, unfortunately, it didn’t work the way I expected!

It didn’t behave exactly the way you described. When I turned one light on the other one turned on as well. So far, so good. However, when I turned the first light off, it caused a few cycles of blinking lights and then they both stayed on. Ha-ha! Definitely not the desired behavior! :slight_smile:

I even tried using a condition to avoid turning the other light on if it is already on (or turning it off if it is already off). However, that didn’t fix it.

The automation’s logic seems right so it leads me to suspect this is a timing issue. The automation executes faster than the lights take to change their state. Normally you don’t notice it but in this case we are attempting to synchronize the states of two lights.

I added a delay of 2 seconds in the action and that eliminated the blinking and confirmed it was a matter of timing.

I want to experiment with it some more before I post the corrected version.

Thank you very much, I will wait for news from you :slight_smile:

I don’t like using delay to fix things but I just couldn’t make a condition solve the timing problem. I added a delay of 1 second and, at least for me, it solved the problem.

- alias: 'Sync Lights'
  trigger:
  - platform: state
    entity_id: switch.shenzhen_neo_1, switch.shenzhen_neo_2
  action:
  - delay: '00:00:01'
  - service_template: "switch.turn_{{trigger.to_state.state}}"
    data_template:
      entity_id: "switch.shenzhen_neo_{{'2' if trigger.to_state.object_id[-1:] == '1' else '1'}}"

I consider this a ‘bandaid’ fix (and there’s no guarantee it will fix it for you).

Here’s how this automation works in theory:

Turn on

  1. Turn on the first light and the automation turns on the second light.
  2. When the second light is turned on, that’s a state-change.
  3. This state-change will trigger the automation again.
  4. The automation will now attempt to turn on the first light.
  5. The first light is already on so nothing else happens.

Turn off

  1. Turn off the first light and the automation turns off the second light.
  2. When the second light is turned off, that’s a state-change.
  3. This state-change will trigger the automation again.
  4. The automation will now attempt to turn off the first light.
  5. The first light is already off so nothing else happens.

Well, that’s how it works in theory but in practice it doesn’t.

The problem appears to occur at step 3 where the automation is triggered again (that’s what I tried, but failed, to prevent using a condition). It seems to happen faster than Home Assistant has time to properly set the light’s state (in other words, the light is still understood to be in the opposite state of what we expect it to be). As a result, it can cause yet more re-triggering of the automation.

Inserting a delay provides the system with a bit of time to record the light’s state properly and seems to prevent more than one re-triggering of the automation.

Try it and see if it works. Try 2 seconds if 1 second fails to fix it. If it doesn’t work at all … it’s back to the drawing board!

Everything remains the same, only with a delay :slight_smile: Tried 1,2,3 secs.

I still have to go through the whole cycle of five taps, so that both switches are turned on or off.

Clearly your system behaves very differently from mine. Not sure I can be of much more help in this situation.

As a second confirmation…

I just created a set of automations using exactly the same format as your original post and mine works exactly the way you want and as expected. If I turn on or off either light the other one follows to the same state immediately:

- alias: TURN ON
  trigger:
    - entity_id: switch.room1_light
      platform: state
      to: 'on'
    - entity_id: switch.room2_light
      platform: state
      to: 'on'
  action:
    - data:
        entity_id: switch.room1_light
      service: switch.turn_on
    - data:
        entity_id: switch.room2_light
      service: switch.turn_on
- alias: TURN OFF
  trigger:
    - entity_id: switch.room1_light
      platform: state
      to: 'off'
    - entity_id: switch.room2_light
      platform: state
      to: 'off'
  action:
    - data:
        entity_id: switch.room1_light
      service: switch.turn_off
    - data:
        entity_id: switch.room2_light
      service: switch.turn_off

I’m not sure why yours wouldn’t work the same way.

If I do automation for one switch, everything works as it should. Both switches are turned on and off.
But if I add the second switch to the automation, it breaks down.
I’ll leave it so far, maybe some of the updates will save the situation :slight_smile:

- id: '1556723254319'
  alias: TURN ON
  trigger:
  - entity_id: switch.shenzhen_neo_2
    platform: state
    to: 'on'
  condition: []
  action:
  - data:
      entity_id: switch.shenzhen_neo_1
    service: switch.turn_on
- id: '1556723807512'
  alias: TURN OFF
  trigger:
  - entity_id: switch.shenzhen_neo_2
    platform: state
    to: 'off'
  condition: []
  action:
  - data:
      entity_id: switch.shenzhen_neo_1
    service: switch.turn_off

can you create another set of on/off automations with the switches reversed and make it work like that?

add the following additional automations to the two existing automations and then see if it works:

- alias: TURN ON 2
  trigger:
  - entity_id: switch.shenzhen_neo_1
    platform: state
    to: 'on'
  condition: []
  action:
  - data:
      entity_id: switch.shenzhen_neo_2
    service: switch.turn_on
- alias: TURN OFF 2
  trigger:
  - entity_id: switch.shenzhen_neo_1
    platform: state
    to: 'off'
  condition: []
  action:
  - data:
      entity_id: switch.shenzhen_neo_2
    service: switch.turn_off

That’s because the ‘one-switch’ automation can only be triggered by that one switch. The automation is triggered by only one switch and then its action changes the state of the other switch (which triggers no automation).

I tested it and it works well for me too.

It gets more complicated when the automation can be triggered by either of the two switches. Now when its action changes the state of the other switch, that state-change re-triggers the same automation.

This is the situation that does not work well in my system (i.e. inconsistently)

That’s true but that shouldn’t matter at that point since the first switch is already on.

sequence of events:

switch 1 turns on.
automation triggers and turns on switch 2
switch 2 turns on
automation triggers and turns on switch 1 but since switch 1 is already on nothing else happens

the same thing happens if you switch all 1’s to 2’ & all 2’s to 1’s & also for swapping the on’s & off’s.

In my automation I posted above everything works exactly as it should/is expected with two switches in both the trigger and in the action.

We’re in agreement; it’s literally what I said in my previous post when I described the detailed sequence of events.

Except, in my situation, it doesn’t care about theory and works its own way … and it’s not a good way.

I didn’t bother mentioning it but my version of the automation also writes to the system log. Just before the action calls for changing the opposite light’s state, it writes what it’s about to do to the log. The results were perplexing. I’d see it claimed the light was already on when it should’ve been off. It would repeat the same operation (run turn_on twice in a row) and other weirdness. It tended to misbehave more when turning a light off than when turning it on. It was these results that led me to believe it was a timing issue. In my case, once I added a mere second of delay, everything worked according to theory.

I even added a condition that would prevent executing the action needlessly (like turn off the opposite light if it was already on) and that failed as well. It reinforced my suspicion that states weren’t being set in a timely fashion and so testing them would produce the kind of erratic results I was seeing. The inclusion of the delay made the flakiness go away.

I tried to add the same set of automation for the second switch. Then both stop working as they should. It takes a few clicks to turn on both.

It only works if the automation is configured for one of them.

I tried it with different switches in the apartment, the situation is the same with all of them (all switches are neo coolcam).

Ensure you have no other automations controlling the two lights then use the 4 automations shown below.

They are very similar to the previous examples you posted except they also have a condition. The condition attempts to ensure that, before changing the switch’s state, the switch is currently in the opposite state (so it doesn’t try to turn off a light that’s already off).

At this late stage, in this grand problem-solving session, I have no reason to be optimistic; my guess is these four automations won’t fix the problem. However, each one of the four automations is as straightforward as can be and employs no tricky templating. Following the automation’s logic is very easy. So if these ordinary automations fail to make the lights work in unison, they serve to demonstrate that the underlying problem isn’t going to yield to ordinary solutions (in this specific situation).

- alias: 'turn on 2'
  trigger:
  - entity_id: switch.shenzhen_neo_1
    platform: state
    to: 'on'
  condition:
    condition: template
    value_template: "{{ is_state('switch.shenzhen_neo_2', 'off') }}"
  action:
  - service: switch.turn_on
    data:
      entity_id: switch.shenzhen_neo_2

- alias: 'turn off 2'
  trigger:
  - entity_id: switch.shenzhen_neo_1
    platform: state
    to: 'off'
  condition:
    condition: template
    value_template: "{{ is_state('switch.shenzhen_neo_2', 'on') }}"
  action:
  - service: switch.turn_off
    data:
      entity_id: switch.shenzhen_neo_2


- alias: 'turn on 1'
  trigger:
  - entity_id: switch.shenzhen_neo_2
    platform: state
    to: 'on'
  condition:
    condition: template
    value_template: "{{ is_state('switch.shenzhen_neo_1', 'off') }}"
  action:
  - service: switch.turn_on
    data:
      entity_id: switch.shenzhen_neo_1

- alias: 'turn off 1'
  trigger:
  - entity_id: switch.shenzhen_neo_2
    platform: state
    to: 'off'
  condition:
    condition: template
    value_template: "{{ is_state('switch.shenzhen_neo_1', 'on') }}"
  action:
  - service: switch.turn_off
    data:
      entity_id: switch.shenzhen_neo_1

I suggest you start by using the first two automations (‘turn off 2’ and ‘turn on 2’) and confirm they work. I suspect they will (because they’re not substantially different from what you’ve already used). Then add the remaining two automations. I imagine that will cause it to misbehave in the same manner you’ve already experienced. Or maybe not. :crossed_fingers:

2 Likes

Four automations solved the problem. Now both switches work correctly)
Thanks for your help!

In truth, it is not clear why it does not want to work without conditions.

I’m both pleasantly surprised and glad to hear it worked.

Here’s my theory of why separating the automations makes a difference (rather than combining them into one). In Home Assistant, you can’t execute a script (an action is effectively the same as a script) that is already executing. The all-in-one version of the automation effectively calls itself. When the action sets the second light from off to on, this state-change calls the same automation again. Perhaps sometimes the first execution of the script is considered finished when the second execution begins and maybe sometimes it does not (leading to odd behavior). This is a potential vulnerability of a self-referential automation.

By handling each of the four possible state-changes in four separate automations, it eliminates the possible of an automation calling itself.

Anyway, it was interesting experiment and, in the future, I will steer clear of creating self-referential automations.

you mean like I suggested up around post #11? :wink: :grinning:

as another experiment that might substantiate that theory…

try adding the entity_ids in a list for both the triggers and the action. That way you won’t be calling the same automation before the actions have completely run.

like this:

- alias: TURN ON
  trigger:
    - entity_id: 
        - switch.shenzhen_neo_1
        - switch.shenzhen_neo_2
      platform: state
      to: 'on'
  action:
    - data:
        entity_id: 
          - switch.shenzhen_neo_1
          - switch.shenzhen_neo_2
      service: switch.turn_on
- alias: TURN OFF
  trigger:
    - entity_id: 
        - switch.shenzhen_neo_1
        - switch.shenzhen_neo_2
      platform: state
      to: 'off'
  action:
    - data:
        entity_id: 
          - switch.shenzhen_neo_1
          - switch.shenzhen_neo_2
      service: switch.turn_off