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

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.

It helps to write the conditions properly. I also threw in a 1 second limit on changes to stop any potential loops. It prevents things from being rapidly synced if you rapidly change them, but that isn’t a big problem. I’ve tested this on a number of paired lights & switches and I think this works well.

- alias: Light Hot Tub Mirror Switch Off
  trigger:
    - platform: state
      entity_id: light.hot_tub_flood_switch
      to: 'off'
      from: 'on'
  condition:
    - condition: template
      value_template: "{{ states.light.hot_tub_flood_switch.last_updated > states.light.hot_tub_flood.last_updated }}"
    - condition: template
      value_template: "{{ (now() - states.light.hot_tub_flood.last_updated ).seconds > 1 }}"
  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:
    - condition: template
      value_template: "{{ states.light.hot_tub_flood_switch.last_updated > states.light.hot_tub_flood.last_updated }}"
    - condition: template
      value_template: "{{ (now() - states.light.hot_tub_flood.last_updated ).seconds > 1 }}"
  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:
    - condition: template
      value_template: "{{ states.light.hot_tub_flood.last_updated > states.light.hot_tub_flood_switch.last_updated }}"
    - condition: template
      value_template: "{{ (now() - states.light.hot_tub_flood_switch.last_updated ).seconds > 1 }}"
  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:
    - condition: template
      value_template: "{{ states.light.hot_tub_flood.last_updated > states.light.hot_tub_flood_switch.last_updated }}"
    - condition: template
      value_template: "{{ (now() - states.light.hot_tub_flood_switch.last_updated ).seconds > 1 }}"
  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) }}
3 Likes

I see this is old, but still active, here is how I do it, no loops, can add many entities. The boolean ensures it runs once, more important if you have a bunch

alias: Pool Pumps On
description: 'Ensure both pumps are on/off at same time'
trigger:
  - platform: state
    entity_id: 'switch.pool_heat_circ_pump, switch.pool_pump'
    from: 'off'
    to: 'on'
condition:
  - condition: state
    entity_id: input_boolean.pool_pumps
    state: 'off'
action:
  - service: switch.turn_on
    data: {}
    entity_id: 'switch.pool_heat_circ_pump, switch.pool_pump'
  - service: input_boolean.turn_on
    data: {}
    entity_id: input_boolean.pool_pumps
mode: single

alias: Pool Pumps Off
description: 'Ensure both pumps are on/off at same time'
trigger:
  - platform: state
    entity_id: 'switch.pool_heat_circ_pump, switch.pool_pump'
    from: 'on'
    to: 'off'
condition:
  - condition: state
    entity_id: input_boolean.pool_pumps
    state: 'on'
action:
  - service: switch.turn_off
    data: {}
    entity_id: 'switch.pool_heat_circ_pump, switch.pool_pump'
  - service: input_boolean.turn_off
    data: {}
    entity_id: input_boolean.pool_pumps
mode: single
2 Likes

Im using this automation, works like a charm.

- alias: Bedroom2
  trigger:
  - platform: state
    entity_id: light.bedroom, light.bedroom2
    from: 'on'
    to: 'off'
  - platform: state
    entity_id: light.bedroom, light.bedroom2
    from: 'off'
    to: 'on'
  action:
    service_template: '{% if trigger.to_state.state == "on" %} light.turn_on {% elif
      trigger.to_state.state == "off" %} light.turn_off {% endif %}
      '
    data_template:
      entity_id: '{% if trigger.from_state.entity_id == "light.bedroom" %} light.bedroom2
        {% elif trigger.from_state.entity_id == "light.bedroom2" %} light.bedroom
        {% endif %}
3 Likes

Lol, you don’t have kids for sure…

I really like this scheme.
I wish I were better versed at templates to come up with some of these.
Thanks for sharing.
Works really well and is pretty elegant.

CFC

I have created a blueprint of this with selecting the entitys over the UI.

blueprint:
  name: Sync two switches
  description: Turn on a switch when other one is turend on and vice versa
  domain: automation
  input:
    switch_entity1:
      name: Switch 1
      selector:
        entity:
          domain: switch
    switch_entity2:
      name: Switch 2
      selector:
        entity:
          domain: switch
variables:
  switch_entity1: !input switch_entity1
  switch_entity2: !input switch_entity2
trigger:
  - platform: state
    entity_id: 
      - !input switch_entity1
      - !input switch_entity2
    from: 'on'
    to: 'off'
  - platform: state
    entity_id: 
      - !input switch_entity1
      - !input switch_entity2
    from: 'off'
    to: 'on'
condition: "{{ trigger.to_state.context.parent_id == none }}"
action:
  - wait_template: "{{ (as_timestamp(now()) - as_timestamp(this.attributes.last_triggered | default(0)) | int > 3) }}"
    timeout: 3
  - 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.entity_id == switch_entity1 %}
        {{ switch_entity2 }}
        {% elif trigger.entity_id == switch_entity2 %}
        {{ switch_entity1 }}
        {% endif %}

This blueprint and adittional for 3 and 4 switches at [General] Sync switches

Creating blueprints is really a pain in the ass. As a guy programming all day in differnt languages I needed hours to get this working.

4 Likes

how do i import your blueprint

I just add it to a subfolder under config/homeassistant/blueprints/automation and after calling the service automation.reload on the UI it is selectable.

1 Like

Great job! Many thanks!

Just came across this thread again and thought I link to this solution which I think is much more elegant, works with more than 2 switches, and is shorter as well:
2 Switches - 1 Light - Configuration - Home Assistant Community (home-assistant.io)

My need is exactly the opposite of this. I have 2 pumps one being a backup of the other. The plumbers suggested it’d be a good practice to rotate their on/off status to increase their lifetime and for some other reasons.

I connected them to a sonoff wireless switch and wrote the following automation, which works. Sadly it’s super primitive and also prone to many fail cases such as any power failure during the automation or say if HA goes down during the automation for some reason. Is there a smart way to mirror the opposite states for two switches without having two automations?

Here’s my current code:

alias: Time - pumps
description: ""
trigger:
  - platform: time_pattern
    minutes: "2"
condition: []
action:
  - if:
      - condition: template
        value_template: "{{ now().hour >= 8 and now().hour < 14 }}"
    then:
      - if:
          - condition: template
            value_template: "{{ now().hour == 8 }}"
        then:
          - service: switch.turn_off
            data: {}
            target:
              entity_id: switch.pump_1
          - delay:
              seconds: 10
          - service: switch.turn_off
            data: {}
            target:
              entity_id: switch.pump_2
        enabled: true
    else:
      - if:
          - condition: template
            value_template: "{{ now().hour % 2 == 0 }}"
        then:
          - service: switch.turn_off
            data: {}
            target:
              entity_id: switch.pump_1
          - delay:
              seconds: 10
          - service: switch.turn_on
            data: {}
            target:
              entity_id: switch.pump_2
        else:
          - service: switch.turn_off
            data: {}
            target:
              entity_id: switch.pump_2
          - delay:
              seconds: 10
          - service: switch.turn_on
            data: {}
            target:
              entity_id: switch.pump_1
  - if:
      - condition: template
        value_template: >-
          {{ is_state('switch.pump_1', 'on') and
          is_state('switch.pump_2', 'on') }}
    then:
      - service: switch.turn_off
        data: {}
        target:
          entity_id:
            - switch.pump_1
            - switch.pump_2
        enabled: true
mode: single

Hello, I’m completely new to HA and automations. I have a running network of zigbee devices and more and more of them are coming.

I already have 15 ZBMINI switches operational, and now I wanted to use ZBMINI in the staircase switch scenarios, however it seems that the wiring I have doesn’t allow me for this use case (no direct L out to the light). Do you think, it would be possible to use a pair of ZBMINIL2 and somehow program mirroring automation for this use case?

Thanks!

Hi.
I know this is a long time ago.
But do I save this code in the automations.yaml file?

You could just add it to the end of the automations.yaml file then see if it appears in the Automations UI. As old as it is, there’s no assurance that the automation would work.

1 Like

Took a little fiddling to get the formatting right… But this works GREAT syncing Virtual switches in Smartthings and real switches in HA. This is a cool/easy way to get Alex/Google Voice Assistant to turn on and off devices in HA.