Make ESPHome node fallback when not connected to HA API

For the record, the binary_sensor.status method doesn’t work.

I tried it the following way:

binary_sensor:
  - platform: gpio
    pin: D4
    name: "Bath Motion"
    id: bath_motion
    device_class: motion
    on_press:
      then:
        - lambda: |-
            ESP_LOGD("main", "Connection status: %d", id(connected).state);
  - platform: status
    name: "Bathroom Ceiling Status"
    id: connected
    on_press:
      then:
        - logger.log: "Connected mode"
    on_release:
      then:
        - logger.log: "Standalone mode"

The log output from the node:

[12:41:45][D][api:546]: Client 'Home Assistant 0.92.2 (x.x.x.x)' connected successfully!
[12:41:55][D][binary_sensor:037]: 'Bath Motion': Sending state ON
[12:41:55][D][main:043]: Connection status: 1
[12:41:57][D][binary_sensor:037]: 'Bath Motion': Sending state OFF
[12:42:24][D][api:073]: Disconnecting Home Assistant 0.92.2 (x.x.x.x)
[12:42:44][D][binary_sensor:037]: 'Bath Motion': Sending state ON
[12:42:44][D][main:043]: Connection status: 1
[12:42:47][D][binary_sensor:037]: 'Bath Motion': Sending state OFF

So it seems that the disconnection/connection state change doesn’t register on the ESP side, probably would work on the Home Assistant side, but that’s not useful in this case.

As for implementing all my automation rules within the ESP node. I think this, in general, is a great solution. however I think it would get very fragile without actually knowing the connection status (which I’m asking about here).

Let’s say there was a power outage and the router/my home assistant doesn’t recover. Now ESP doesn’t have the proper time from the internet, so time based automation won’t work, also I wouldn’t be able to override the status of the light. For example this light shouldn’t turn on during the night, but during an outage, it would be better to make it turn on. – I suppose I could use the .is_valid() function in all my lambdas to check for this.

But now let’s suppose that the node does have the correct time, but my Home Assistant/Wifi is down, making it impossible to force the light ON during the night… so in the end I still need a clear answer whether the node is connected to Home Assistant or not. Also if I rely on forcing from the HA for certain states (steady ON/OFF instead of motion timeout) and the Home Assistant gets inaccessible, those states get stuck on the last available status, which I have no way of changing without knowing that my node is connected or not to the bigger system.

tl;dr: I still need the knowledge of the connection status to Home Assistant if I want to make a well functioning fallback, because a standalone node should use simpler automation routines.

I’m sorry this did not work for you.
I was looking at the code trying to figure out why it might not work. This is the code I looked into first,
which is the status binary sensor for 1.13 which is dev version. (Dev version is latest bits, and likely buggy)
Then there is the 1.12 version you are running most likely: It’s a bit different where it checks what to report. The old one does not check api
Which version are you running?
Seems like dev version will report this as you’d expect, i.e. if you only use api (not mqtt) then it will report disconnected if HA is down.
v1.12 will report disconnected if you are over mqtt and the broker goes down.
Also seems like both will report disconnected if the wifi router goes down.
How are you testing your disconnect event? (shutting down Home Assistant?)

I’d like to know if there’s a way to do this too.

I’m about to install some sonoff duals which I will wire to light switches - plan is to send a toggle command to Home Assistant to turn my Yeelights on/off. Trouble is, if HA or the network goes down, I could be in a position that I’m flicking switches and I’m stuck in the dark without a fallover option.

Have a look at this as a possible solution:

Perhaps for basic functions, you could have it so that a quick double toggle reverts back to the ESPHome api onboard if HA can’t be contacted.

@glmnet Indeed, failed to mention it, but I’m using 1.12.2 stable from pip with the native api (no mqtt) and I was testing it by shutting down Home Assistant, not wifi (so that I can see the logs easily without connecting to the serial line). Glad to know this will work in the following version. I might give it a go with the dev branch, as according to the code you linked it should indeed start working with that.

I’ll post my code when I have it working. Thanks for the help so far!

@efleming I don’t have any switch connected to the ESP (it’s up in the ceiling with only a motion sensor and a relay connected) so using more complicated click patterns won’t help in this case, but it can be a good solution for fallback indeed, thanks for pointing out this workaround.

May be this will suit you better

Yesss, I this is exactly what I was looking for, but somehow couldn’t find it in the docs! :slight_smile:

Thank you once again.

Oh that’s next docs, i.e. v1.13

I’m still new to ESPhome, so let me put some code in here for critique to see if I understand that correctly. If I have ESPHome send a command to HA to run an action (say turn on yeelight), but it cannot connect, I would use this?

on_switch_toggle: 
  - homeassistant.service:
      service: light.toggle
      data:
         entity_id: light.yeelight101
  if:
    condition:
      api.connected: false
    then:
      - switch.toggle: relay_1

So 1.13.x just came out and I gave a go to trying this, but it doesn’t work for me. As for your example, I think the conditions should be just api.connected:, not including false. If we want false, it should be probably:

if:
  condition:
    not:
      api.connected:
    then:
      - logger.log: disconnected

However I tried this code and it gives me back “connected” both when Home Assistant is connected and when it’s disconnected:

binary_sensor:
  - platform: gpio
    pin: D4
    name: "Bath Motion"
    id: bath_motion
    device_class: motion
    on_press:
      if:
        condition:
          api.connected:
        then:
          - logger.log: connected
        else:
          - logger.log: not connected

Example output (cut out the irrelevant lines and censored the IP):

[20:28:31][D][binary_sensor:033]: 'Bath Motion': Sending state OFF
[20:28:42][D][api:572]: Client 'Home Assistant 0.93.1 (x.x.x.x)' connected successfully!
[20:28:44][D][binary_sensor:033]: 'Bath Motion': Sending state ON
[20:28:44][D][main:220]: connected
[20:28:46][D][binary_sensor:033]: 'Bath Motion': Sending state OFF
[20:29:03][D][api:074]: Disconnecting Home Assistant 0.93.1 (x.x.x.x)
[20:29:11][D][binary_sensor:033]: 'Bath Motion': Sending state ON
[20:29:11][D][main:220]: connected
[20:29:14][D][binary_sensor:033]: 'Bath Motion': Sending state OFF
[20:29:37][D][binary_sensor:033]: 'Bath Motion': Sending state ON
[20:29:37][D][main:220]: connected
[20:29:40][D][binary_sensor:033]: 'Bath Motion': Sending state OFF
[20:30:21][I][ota:046]: Boot seems successful, resetting boot loop counter.
[20:31:52][D][api:572]: Client 'Home Assistant 0.93.1 (x.x.x.x)' connected successfully!
[20:32:08][D][binary_sensor:033]: 'Bath Motion': Sending state ON
[20:32:10][D][main:220]: connected

@glmnet did you try this out? Looks like there’s a bug in this new condition. :confused:

I did not test it but looks ok according to docs.

By any chance do you have several ha instances?

Also I don’t know if the logger via OTA would account as an API client, are you logging via usb?

I can test this tomorrow

You’re right again. Fooled once more by the observation altering the result of the experiment. When I disconnected the logging the condition worked as expected. :sweat_smile:

This should be probably noted in the docs, I’d assume I won’t be the only one who falls into this trap.

So I made it work like this: my node is a simple Wemos D1 mini with a relay and a motion sensor. By default the motion sensor reports to Home Assistant and HA decides if it wants to turn on or off the light by the relay. If there are no clients connected to the API, the light turns on and stays for 90 seconds from the last motion activity, but the node doesn’t touch the light in case an API client connects meanwhile.

I have a watchdog routine in my Home Assistant that regularly checks if the lights are in the correct state, but if you don’t have that, this sketch might leave your light turned on if HA connects to the node during the 90 second timeout, so in that case it’s probably better to remove the if condition from the on_release part.

Here’s my full yaml for reference:

esphome:
  name: bathroom_ceiling
  platform: ESP8266
  board: d1_mini

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

# Enable logging
logger:

# Enable Home Assistant API
api:
  password: !secret api_password

ota:
  password: !secret ota_password

binary_sensor:
  - platform: gpio
    pin: D4
    name: "Bath Motion"
    id: bath_motion
    device_class: motion
    on_press:
      if:
        condition:
          not:
            api.connected:
        then:
          - lambda: |-
              id(failover_control).publish_state(true);
              id(failover_control).publish_state(false);
  - platform: template
    id: failover_control
    filters:
      - delayed_off: 90s
    on_press:
      if:
        condition:
          not:
            api.connected:
        then:
          - light.turn_on: bathroom_ceiling
    on_release:
      if:
        condition:
          not:
            api.connected:
        then:
          - light.turn_off: bathroom_ceiling

output:
  - platform: gpio
    pin: D1
    id: relay

light:
  - platform: binary
    name: "Bathroom Ceiling"
    id: bathroom_ceiling
    output: relay
4 Likes

Nice catch, I filled an issue https://github.com/esphome/issues/issues/394

1 Like

Is there a way to to turn OFF the switch for 5 seconds and turn it back to ON after reboot.
I want to the switch to realy perform OFF/ON after a reboot.

Yes. Please create a new question (new thread)

done

can you share your code?

Hi @attila_ha,
Bringing this up from a while back. I’m looking at this code it would only check the condition of the api.connected when your motion is detected. I imagine this works great for checking if you have a connection at the time of motion. However, is there a way to trigger on the not api.connected state after the light is on?

My use case is a bit different as I’m controlling my HVAC furnace. HA turns on a relay and it stays on as long as HA calls for heat. But if I lose connection to the api after the heat is turned on, it will continue to stay on until it reconnects and sees the call for heat is off. Your failover control currently delays for 90s, but even if increase this to 20m, I think it would turn off the heater relay creating a “saw tooth” effect or just turning off the heat completely.

Is there a way of making it check every 5m to see if it’s still connected to the api and if it is, then do nothing, but turn off the relay if it has lost the connection? Effectively an api watchdog?

Hi @poldim,

I hope I understood correctly what you described, I did address similar concerns at a different node I had that was turning on/off a transistor which was turning on a heater.

First, make sure if the ESPHome node shuts down, it turns off the heater. This can happen for reboots from updates or if it wants to reset itself.

  on_shutdown:
    then:
      - switch.turn_off: <id_of_your_switch>

As for a periodic check when it loses connection, you can make a script that periodically checks the condition and acts accordingly. I cannot make a working example, as I don’t have this exact use-case, and I don’t want to suggest you something that’s not working, but in short you need to start a script when the node starts up, then call the script again at the end of the script and do some checks for the API in the middle.

esphome:
  [other options]
  on_boot:
    - script.execute: connection_watchdog

script:
  - id: connection_watchdog
    mode: queued
    then:
      [check here for the API connection and start/stop the relay accordingly]
      - delay: 300s
      - script.execute: connection_watchdog
2 Likes

Why make it so complicated ? I had that issue as I use some shelly cloud relay (esp based) for lights control and wanted it to be working even without network/wifi or ha as it’s light in stairs and bedrooms ! so I made the automation (including for timers) in ESP and I can see states or interact/force them in ha but in all matters it works by itself. Isn’t it easier ? and also makes less processing and basic logic to handle in HA !

Any chance you could share this code @vincen ?