Sync HA Switch Status with that of an API-Driven Sensor

Have run across several posts that come close to what I’m trying to do, but as always, they seem just different enough that I cannot get the offered solutions to work, or there are a jillion lines of code that make it impractical to do this without creating a fair amount of clutter.

I have several circuits that report status back as sensors directly from an external device’s restful API (while I don’t have anything defined as binary sensors per se, they only report back 1 or 0).

Each circuit sensor has a corresponding switch and state value that I’ve been able to set up within the context of HA. On their own, I can use these switches in a glance card to toggle the external device’s circuits. The states I have set up track and stay in sync with the switch. All good so far.

However, if I turn on a circuit directly outside of HA using the external device’s controller, neither the switch or state in the glance card reflects the current status. But the API-driven sensors do.

Everything works so this is more of a nit, but how in the world do I get the switches and statuses to track their respective sensors and show an On/Off state, if control was performed external to HA?

Bear in mind, I don’t want the HA switch to send a command in this scenario since that has already been done by the external controller, but rather to just reflect the state of the API-driven sensor if and when that happens.

There is a python script available from HACS that will let you set the state of an entity in an automation.

It would be helpful to see how you have the HA sensors setup and get more detail on the actual device, as there might be a different way to set them up that would resolve this without having to do something as brute force as setting the state based on some other state. Otherwise we’re just shooting in the dark.

First, create the binary sensor that tracks the state. As part of the REST config you’ll specify the frequency at which to poll. That frequency will be the fastest rate at which it can detect a change. For example, if you set the polling at 1 minute, it may take up to 1:59 mmss, for a change to be detected.

Second, create a switch template whose value_template is driven by that binary sensors and put your switch on/off commands in here.

Understood. Here is what I have in place - I currently have the components broken out into their respective .yaml files. I’m only including one circuit here for brevity:

rest:
# Integration to Equipment control API
  - authentication: basic
    username: !secret pool_usr
    password: !secret pool_psw
    scan_interval: 3
    resource: http://MY.IPA.DDR.ESS/status.xml
    sensor:	
	  - name: "Pool Equipment"
        json_attributes_path: "$.response.equipment"
        value_template: "OK"
        json_attributes:
          - "circuit4"

###

input_boolean:
# Correcly reflects state of HA switch ONLY.  Used in button card for observation.  
# Toggling changes its state and that of the associated switch, but does not 
# control the actual circuit.
  pool_lights_state:
    name: Pool Light State

###

script:		  
  pool_lights_on:
    sequence:
      - service: rest_command.pool_lights_on
      - service: input_boolean.turn_on
        entity_id: input_boolean.pool_lights_state
  pool_lights_off:
    sequence:
      - service: rest_command.pool_lights_off
      - service: input_boolean.turn_off
        entity_id: input_boolean.pool_lights_state

###		

rest_command:
  pool_lights_off:
    url: "http://MY.IPA.DDR.ESS/set.cgi?name=circuit4&value=0"
    method: get
    headers:
      authorization: 'Basic MYAUTHORIZATIONCODEXYZ123'
      content-type: 'application/json'
  pool_lights_on:
    url: "http://MY.IPA.DDR.ESS/set.cgi?name=circuit4&value=1"
    method: get
    headers:
      authorization: 'Basic MYAUTHORIZATIONCODEXYZ123'
      content-type: 'application/json'

###

template:
# API-based sensor used in Glance card.  ALWAYS tracks current state, whether triggered by HA 
# switch, or external controller
  sensor:
    - name: "Pool Circuit4"
      state: "{{state_attr('sensor.autelis_pool_equipment','circuit4')}}"

###

switch:	  
# Used in Glance Card.  Toggles external equipment on/of and correctly reflects status
# when used from within HA.  Does not sync status if lights are toggled from external controller.
  - platform: template
    switches:
      pool_lights:
        value_template: "{{ is_state('input_boolean.pool_lights_state', 'on') }}"
        turn_on:
          service: script.pool_lights_on
        turn_off:
          service: script.pool_lights_off 

PeteRage, that’s what I already have in place, which is working. My issue is that the switch status in HA does not reflect the state of the actual circuit, if controlled externally from HA.

Please post your configuration for the binary sensor and switch template. Never mind I see it now.

The value template should not use the input boolean it should use the sensor “Pool Circuit 4”

Doing this makes the switch follow the state of the equipment which is what you want,

Right now it’s following the state of the input boolean.

PeteRage, I tried your suggestion, but the switch still does not follow the state of Circuit 4. It also causes the switch to stop showing its own state when used within HA.

I thought there may be a simple way to assign state from one entity to another, sort of like: state.switch4 = state.sensor4

Perhaps that’s what the python script does that pkscout pointed me to. He suggested that using it would be a brute force approach, however, so I was hoping to find an easier method along the lines of what you offered, without having to set up a slew of automations.

I thought you said that sensor tracks the state, regardless of where it gets set?

If it does then it should be what you use, you will need to convert it to a True/False expression or set it up as a Binary_Sensor.

Based on your REST config it should update every 3 seconds.

First step, try to get that binary sensor working.

Because it’s driven by the external API’s status integration, sensor.pool_circuit4 always reflects the proper state, regardless of whether the light is triggered within HA or from the pool’s controller. It always returns a 1 or 0, so this part works correctly. But by itself, it will not trigger the lights off/on within HA, if used as a button, for example. It only reports status.

However, switch.pool_lights does work within HA to physically toggle the lights on or off, and the glance card I use it in correctly shows the state of the lights. The glance card icon just doesn’t change status if I turn the lights on using the actual pool’s control panel.

This is why I was hoping to use the state of sensor.pool_circuit4 to somehow drive the icon status in the switch.pool_lights glance card. But I can’t use sensor.pool_circuit4 within the value template here, again because it only reports status and does not actually control the lights.

Unfortunately, when I was putting together my code post, I left out the very important rest_command that actually reaches out to a different command API to physically turn the lights off or on. I’ve edited the post to include it.

So it sounds like you have a sensor that will always tell you the current state of the device and a sensor that will control it but not tell you anything about the state. Which you’re probably thinking you’ve said like 9 times, but I think I finally got it. '-)

You should be able to write an automation that will update switch.pool_lights any time the state of sensor.pool_circuit4 changes. I’m doing this off the top of my head, so it might not be 100% right, but maybe:

alias: Match Switch to State
description: ""
mode: single
trigger:
  - platform: state
    entity_id:
      - sensor.pool_circuit4
condition: []
action:
  - if:
      - condition: state
        entity_id: sensor.pool_circuit4
        state: "1"
    then:
      - service: switch.turn_on
        data: {}
        target:
          entity_id: switch.pool_lights
    else:
      - service: switch.turn_off
        data: {}
        target:
          entity_id: switch.pool_lights

This will technically change the state of the switch even if you change the switch in Home Assistant, but since it’s changing it to what it already is, it should be fine. And if you change the state outside Home Assistant, it should notice that and update the switch.

I think it took so long to understand your challenge because most device switches send back the state to the switch to avoid this exact problem.

Pretty impressive for off the top of your head! It works perfectly just as is - thank you!

So there’s really no easy method of assigning the state of one entity to another, then. Would you recommend this automation approach over the python script you linked me to earlier?

Thanks, again!

This should work also:


switch:	  
# Used in Glance Card.  Toggles external equipment on/of and correctly reflects status
# when used from within HA.  Does not sync status if lights are toggled from external controller.
  - platform: template
    switches:
      pool_lights:
        value_template: "{{ states('sensor.pool_circuit4’)|int(0) == 1  }}"
        turn_on:
          service: script.pool_lights_on
        turn_off:
          service: script.pool_lights_off 

Thanks, PeteRage,

This works, too. I had an issue with the quotes, but got it figured out. I’ve got about 20 circuits to apply either one of these solutions to. I’ve sort of gotten lost stringing the multiple automations together, and was in the process of breaking them into individual files.

I’m going to attempt to mark both of the contributions you and pkscout made as solutions. Two different approaches, and I’ve learned a bit more from each of them.

Sounds good. I have some similar items where I need to apply the same config over and over. The first thing is to create a working package for the first circuit. Then replicate and replace to create the other packages. To make it easier, I create shell scripts to do the replication. I think in your config the only thing that changes is the circuit number.

So if your package is for circuit4, and you want to replace it for circuit5, you can do this from a Linux shell prompt. You could also do the same in a window batch file.

sed 's/circuit4/circuit5/circuit4_package.yaml > circuit5_package.yaml

If you need to substitute multiple string you can chain the seds together

sed 's/circuit4/circuit5/circuit4_package.yaml | sed ‘s/this/that/g> circuit5_package.yaml

Two main benefits. First, make sure all the packages are consistent, and if you need to make a change later, you change one file and rerun the script/batch file.

That’s awesome - good info!

Thanks, again,
DBB1