How to link 2 switches together, so state of one mirrors state of second

Read this :

You saved previous time with this perfectly workign answer. Thank you.

1 Like

Hello,
Here how i had it worked without delay problems.

Cheers

I have the same ā€œinfinite loopā€ issue with the provided answer above.

I ā€œknowā€ how the issue can be resolved (in terms of logic flow) but I donā€™t know how to write this in automation ruleā€¦

Maybe someone can turn this into a working rule:
So we keep the main logic by setting a mirror switch value to the ā€œcurrently setā€ value. But we must set a flag on the mirror switch which will mean that the next assigned value will be from an automation rule (so we can ignore this).

Step by step:

  1. switch A gets clicked (off -> on)
  2. switch B sets custom ā€œfrom_autoā€ flag to ā€œ1ā€
  3. switch B sets state to ā€œonā€ (same as switch A)

[mirroring is ā€œdoneā€ at this point. everything below is what causes the loop to happen when states were changed too quickly (when not using ā€œfrom_autoā€)]

  1. automation is fired for switch B as itā€™s state was changed (off -> on)
  2. automation condition must check if switch B has a ā€œfrom_autoā€ attribute set to ā€œ1ā€
  3. [automation] IF no, then do switch.turn_on as usual mirroring flowā€¦
  4. [automation] IF yes, then do not try to ā€œmirrorā€ this state (do no run switch.turn_on for mirroring to another switches)
  5. [automation] change switch B (current trigger.from_state.entity_id) attribute ā€œfrom_autoā€ to ā€œ0ā€ to return to the initial state

thats allā€¦ from_auto will control if the new state must be sent to ā€œotherā€ switches or not.

I hope someone can turn this into an automation rule.

I have a ā€œvirtualā€ bedside light that is actually a switch (wifi wall plug) and can also be switched via a 433MHz RF switch (connected to the Sonoff RF bridge). So itā€™s three things to sync for me: The light, the switch, and the state of the RF switch.

I use a more ā€œbrute-forceā€ method by setting all three of the entities to whatever state I get when any changes:

  # Synchronize switches for bedside light
  - alias: Sync bedside light switches
    trigger:
      platform: state
      entity_id:
        - light.bedside # the light (which is actually switch3)
        - switch.switch3 # the physical switch
        - switch.rfbridge1_2 # RF switch
    action:
      service_template: >
        {% if trigger.to_state.state == "on" %}
        homeassistant.turn_on
        {% elif trigger.to_state.state == "off" %}
        homeassistant.turn_off
        {% endif %}
      entity_id:
        - light.bedside # the light (which is actually switch3)
        - switch.switch3 # the physical switch
        - switch.rfbridge1_2 # RF switch

This has been working without side effects for over a year now, and proved a good strategy for any entity that is to be controlled by more than one actuator (like my hallway lights that have 5 switches, one next to each door).

1 Like

unfortunately it has the same infinite-loop effect too

you canā€™t skip events as then switches may stuck in different states.

1 second delay is not a solution. this was described above.

Hi @Delphir, not sure if you have solve it. I understand what you mean by infinite loop. This happens when you flick the switch multiple time too fast, it can happens also when the network is slow and switch2 delay in action causing the out of sync. So they trigger each other indefinitely.
I manage to find something that work though, see if it helps you.
I am more primitive, i use only GUI automation. If you use code, you can use this concept and use your own code if you like.
I use 4automations entriesā€¦ on1trigger_on2, off1trigger_off2, on2trigger_on1, off2trigger_off1, the important thing is to add a condition to the action switch, make sure the action switch is in the correct state.

example for the 1st automation
trigger : switch1 on
condition: switch2 is off
action: turn on switch2.

You try this, it will not go into infinite loopā€¦ Convert this concept into code, as i only know how to use GUIā€¦let me know if it works for youā€¦

the loop happens not because of the wrong states, but because of the delay itself

look at this:

  1. switch2 current state = off
  2. switch1 on (trigger delayed [A])
  3. switch1 off (trigger delayed [B]) <<<<<<<< our expected final value
  4. trigger automation for switch1 on [A] = switch2 on (will fire an automation too [C])
  5. trigger automation for switch1 off [B] = switch2 off (will fire an automation too)
  6. trigger automation for switch2 on [C] !!! = switch1 on <<<<<<<<<< the actual final value and looping then
    ā€¦
    and so onā€¦ here they start looping fast for the infinite amount of time. and each time the state of the another switch has an ā€œoppositeā€ value, so your ā€œconditionā€ will not solve the problem.

it would be handy to have a condition ā€œNOT from automationā€ - this would solve the whole issue

Delphir, like i said in my post, i know the root cause is the delay, please check. It is the delay causing the 2switches out of sync, and always in opposite state, and they start triggering each other to change state without first checking the opp switch for their state. I know it is not the condition that cause this problem. I am saying by adding a condition to check the opp switch before firing the action, it does prevent the infinite loop. I am not just giving a hypothetical theory, i tried it in my automation. It prevent them from infinite togglingā€¦I physicaly flick the switch onoff more than 10time in succession, it doesnt happen anymoreā€¦ so i place my sucessful trial here and hopefully someone need this piece of information. I am not sure if you have tried it before you conclude. peaceā€¦:blush:

By the way i am not good at code, i use 4automations to pair 2 switches. And I also have infinite loop issue like you, causing by network delay. Now I am all settled after i add in the condition. hope it helpā€¦

Sorry, maybe i didnt explain properly, i try again just in case you didnt understandā€¦

  1. switch2 current state = off
  2. switch1 current state = off
  3. switch1 trigger on but check condition of switch2 first.
  4. if condition of switch2, is off, then fire the action to turn on switch2
  5. if condition of switch2 is on, do nothing.

hope you can understandā€¦

My solution uses two automations. Both switches are MQTT with physical switches. Iā€™ve tried flipping the physical switches as fast as I can and I never get out of sync or have blinking lights.

My other automation is the same as this, but with the switch names reversed.

- alias: "Family North Sync" # Synchronize north and south lights
  trigger:
    - platform: state
      entity_id: switch.family_recessed_north
  action:
    - choose:
        - conditions: 
            - condition: state
              entity_id: switch.family_recessed_north
              state: 'on'
          sequence:
            - service: switch.turn_on
              entity_id: switch.family_recessed_south
      default:
        - service: switch.turn_off
          entity_id: switch.family_recessed_south

1 Like

Hi I am new to HA. Can you tell me where I should put this code? automation.yaml or configuration.ymal? How is the automation id get generated? Many thanks,

sorry guys, i cannot put my switches, working as a mirror, can you help?

- id: '1606786491838'
  alias: Quarto R/C Switch  ON
  description: ''
  trigger:
    - platform: state
      entity_id: switch.sonoff_100021a80a, switch.sonoff_10002181de
      from: 'on'
      to: 'off'
    - platform: state
      entity_id: switch.sonoff_100021a80a, switch.sonoff_10002181de
      from: 'off'
      to: 'on'
  action:
    service_template: >
      {% if trigger.to_state.state == "on" %}
      switch.turn_on
      {% elif trigger.to_state.state == "off" %}
      switch.turn_off
      {% endif %}
    data_template: 
      entity_id: >
        {% if trigger.from_state.entity_id == "switch.sonoff_100021a80a" %}
        switch.sonoff_10002181de
        {% elif trigger.from_state.entity_id == "switch.sonoff_10002181de" %}
        switch.sonoff_100021a80a
        {% endif %}
  mode: single

This is under automations.yaml

Awesome! Thanks. This worked for me.

1 Like

Just to toss in the way Iā€™ve done this - never been a problem for me. I have the following code. In this case, the dining_room_table_a light is a single light in the chandelier, and the light.dining_room_table is the group. (I wanted some redundancy, so if alexa turned on the lights it would also set the switches to the correct state). Obviously, I have a similar code for the table_off state. I think having mode:single works with the system here - I donā€™t think itā€™s physically possible for things to get out of sync this way.

- id: 'DiningRoomTableon'
  alias: Dining Room Table on
  description: ''
  trigger:
  - platform: device
    type: turned_on
    device_id: 99300785192text9091984670
    entity_id: switch.dining_room_table_1
    domain: switch
  - platform: device
    type: turned_on
    device_id: 3356022273text24728020666
    entity_id: switch.dining_room_table_2
    domain: switch
  - platform: device
    type: turned_on
    device_id: 79370607906text37076040675
    entity_id: light.dining_room_table_a
    domain: light
  condition: []
  action:
  - type: turn_on
    device_id: 99300785192text9091984670
    entity_id: switch.dining_room_table_1
    domain: switch
  - type: turn_on
    device_id: 3356022273text24728020666
    entity_id: switch.dining_room_table_2
    domain: switch
  - type: turn_on
    device_id: 68013182361text88415920360
    entity_id: light.dining_room_table
    domain: light
  mode: single

For the guys with the infinite loop.

I donā€™t know your exact setup so this might not work for you, but have you considered a master <> slave relation between you lights? This way you can avoid an infinite loop, as there is only one master, and the rest are slaves, that follow the master.

This problem has been bouncing around in my skull for a while. In my situation, I have a number of Insteon switches that are controlling zigbee, wled, or esphome based lights. Up until now Iā€™ve been content with the switch controlling the light, and if the light gets shut-off or dimmed by HomeKit or Home Assistant independently of the switch, then they just get out of sync, in order to avoid the loop problem.

I realized tonight that if I set a condition on the automation that checks to see if the controlling entity has changed more recently than the target entity, then it should react accordingly and not cause loops because the other automation sees a change and wants to change its target. Eureka! It works, and no loops. Now both the switch and the light are in perfect sync.

- alias: Light Hot Tub Mirror Switch Off
  trigger:
    - platform: state
      entity_id: light.hot_tub_flood_switch
      to: 'off'
      from: 'on'
  condition: "{{  states.light.hot_tub_flood_switch.last_updated > states.light.hot_tub_flood.last_changed }}"
  action:
    - service: light.turn_off
      entity_id: light.hot_tub_flood

- alias: Light Hot Tub Mirror Switch On
  trigger:
    - platform: state
      entity_id: light.hot_tub_flood_switch
  condition: "{{  states.light.hot_tub_flood_switch.last_updated > states.light.hot_tub_flood.last_changed }}"
  action:
    service: light.turn_on
    entity_id: light.hot_tub_flood
    data_template:
      brightness: >
        {{ state_attr('light.hot_tub_flood_switch', 'brightness') | default(0, true) }}

- alias: Light Hot Tub Mirror Flood Off
  trigger:
    - platform: state
      entity_id: light.hot_tub_flood
      to: 'off'
      from: 'on'
  condition: "{{  states.light.hot_tub_flood.last_updated > states.light.hot_tub_flood_switch.last_changed }}"
  action:
    - service: light.turn_off
      entity_id: light.hot_tub_flood_switch

- alias: Light Hot Tub Mirror Flood On
  trigger:
    - platform: state
      entity_id: light.hot_tub_flood
  condition: "{{  states.light.hot_tub_flood.last_updated > states.light.hot_tub_flood_switch.last_changed }}"
  action:
    service: light.turn_on
    entity_id: light.hot_tub_flood_switch
    data_template:
      brightness: >
        {{ state_attr('light.hot_tub_flood', 'brightness') | default(0, true) }}

Edit: Changed ā€œlast_changedā€ to ā€œlast_updatedā€ since brightness doesnā€™t affect ā€œlast_changedā€ but it does affect ā€œlast_updatedā€.

1 Like

This isnā€™t quite there yet. Sometimes there is a bit of looping when HA changes one of the entities, but it eventually stops for some reason.