How to default to a "safe" state on loss of connection to HA

I have an electric water heater that heats a water tank, if there is excess PV power. I’ve set up this automation with ESPHome and Homeassistant which has been working fine for half a year (including switching the 3 heating elements of the 3-phase heater with SSRs/relays to achieve 6 different power levels).

But there is one issue: if the ESPHome node for any reason (wifi/network down, HA acting up) does not get a new power setting it will stay at the last power level until the heater’s thermostat kicks in (which it never does in “normal” operation, because I’ve set my own slightly lower temperature limit with HA, which stops the heater before that). In this case it’s not a safety issue, but I’m might be heating the water with expensive grid electricity.

How can I check if HA “is still there” in ESPHome? (My HA automation only sends new power levels on change, so I can’t use that as a “heartbeat”.)
There’s the api.connected condition and the on_client_disconnected trigger. Would these be the functions to use here?
How long does it take for them to change/trigger, if the connection to HA is lost (assuming an “unclean” disconnect)?

Yes :checkered_flag:

Very quickly - what is your update interval on the power meter? :zap:

Yes.
And I would make some time-condition as well, for example 5min time out for missing updates.

The PV inverter is queried by HA every 10 seconds (not something I can change; it seems internal to the GoodWe integration). The inverter has its internal measurements, but also reports those of the external smart meter it is connected to.
My ESPHome node also reports back the heater temperature (from a dallas 1-wire sensor) every 30 seconds, if that’s of any use to create a “fail” trigger.

I expect an espHome node to react faster than this if the HA (client) looses the connection to the node. :timer_clock:

:thinking:
I have found timing values in the ESPHome source, where it looks like it could be up to 2.5 minutes.
https://github.com/esphome/esphome/blob/c63a5457509b69bd75cda9962ee654e6cacab405/esphome/components/api/api_connection.cpp#L156

Especially:

  static uint32_t keepalive = 60000;
  static uint8_t max_ping_retries = 60;
  static uint16_t ping_retry_interval = 1000;
  const uint32_t now = millis();
  if (this->sent_ping_) {
    // Disconnect if not responded within 2.5*keepalive
    if (now - this->last_traffic_ > (keepalive * 5) / 2) {
      on_fatal_error();
      ESP_LOGW(TAG, "%s didn't respond to ping request in time. Disconnecting...", this->client_combined_info_.c_str());
    }
  } else if (now - this->last_traffic_ > keepalive && now > this->next_ping_retry_) {
    ESP_LOGVV(TAG, "Sending keepalive PING...");
    this->sent_ping_ = this->send_ping_request(PingRequest());  
    ...

As I understand it, ESPHome tries to “ping” the API connection only after 60 seconds of no traffic.
If the outgoing ping was successful (so the network was OK), it waits another 1.5 minutes for a response.
If the outgoing ping wasn’t successful (most likely some kind of network issue), it tries again every second up to 60 times.
Only if these fail, will it mark the connection as closed (happening in on_fatal_error()).

If only that weren’t so hard to test. You need an ESPHome connected to an API, then break the connection somehow (preventing a clean client disconnect) and can’t have any other API connection to view the logs, because api.connected would never became false in that case.

Do it vice-versa. :point_down:

Monitor HA and just unplug your esphome node :electric_plug::x:

Another (more sophisticated) approach would be to get the power readings from HA and store them in a global which flushes old values after x seconds so you are not stuck with “outdated” readings :bulb:

You can use the timeout filter on the power sensor in ESPHome to give a default value if no updates are received.

The power level is a number component, which don’t seem to have a filter property.

A number component? So you can change the value in ESPHome and send it back to HA, and presumably the inverter? That doesn’t sound like it’s going to work, surely it should be a sensor?

No, it is the other way round. It is an ESPHome number component, which appears in and can by set by HA. I set the number to a certain value (from 0 to 6 in my case) with a HA automation, which gets sent to the ESPHome node automatically (that’s the point of a number component) and the node the sets outputs corresponding to relays.

No, the point of a number component is that it can be set at either end and the value is reflected to the other, and there is no suggestion that you need that functionality. A homeassistant sensor in ESPHome also gets updated automatically as the HA value changes.

You could also just get the inverter power into ESPHome as a sensor and do the automation in ESPHome, which would make incorporating fail safe logic somewhat easier and more reliable (I had wrongly assumed that was what you were actually doing.)

Absolute.

For maximum resiliance you want to have the logic on the esphome node only feeding in the inverters data.

Your inverter should be a sensor entity in HA and with this ESPHome component you get that via push to the node for further automation. :point_down: