Home Assistant Community

Make ESPHome node fallback when not connected to HA API

#1

I want to make my ESPHome node have some fallback automations in place during infrastructure problems (wifi down, Home Assistant down, etc.)

Currently I use a firmware I wrote for my Wemos D1 mini, which has a motion sensor and a relay controlling a light in a room. It sends the motion data to Home Assistant, and then HA decided if the light should be turned on or not, based on a bunch of factors (time of day, state of other sensors, etc.)

In case it can’t update the state, I’m putting it in a “fallback” state where the motion sensor directly controls the relay with a 90 second timeout for motion until it’s able to send the state again to Home Assistant. This works fine.

I want to move over to ESPHome, because it’s pretty cool from the HA integration perspective, but I can’t figure out how to get this to work in a similar way.

I suspect the solution will be around Template Lambdas and the api::APIConnection::ConnectionState but I don’t know how to really put something useful together.

Any guidance would be appreciated!

For reference, this is how I’m doing it currently (just the relevant part in the loop()):

void loop() {
  HTTPClient http;
  int http_code;

  motion_sensor.update();
  if (motion_sensor.rose()) {
    motion_counter++;
    //Serial.println("Motion detected");
    http.begin(MOTION_STATE);
    http.addHeader("Content-Type", "application/json");
    sprintf(buff, MOTION_MSG, motion_counter);
    http_code = http.sendRequest("POST", String(buff));
    if (http_code < 0) {
      standalone_mode = true;
      standalone_timer = millis();
    }
    else {
      standalone_mode = false;
    }
    Serial.printf("[HTTP] POST return code: %d\n", http_code);
    http.end();
  }

  if (standalone_mode) {
    if (relay_state && (millis() - standalone_timer > standalone_timeout)) {
      relay_state = false;
      digitalWrite(RELAY_PIN, relay_state);
    }
    else if (!relay_state && (millis() - standalone_timer < standalone_timeout)) {
      relay_state = true;
      digitalWrite(RELAY_PIN, relay_state);
    }
  }

  server.handleClient();
  ArduinoOTA.handle();
}
#2

Try this https://esphome.io/components/binary_sensor/status.html

You should be able to check the state property.

#3

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 !

#4

Thank you for both of the suggestions! I will try the sensor status and mull over whether I can move all the automation logic into the ESP. Both seem very promising ways to solve this.

#5

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.

#6

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.

#7

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?)

#8

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.

#9

@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.

#10

May be this will suit you better

#11

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.

#12

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

#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