Restore values from Home Assistant after reboot (doing it with automations). Is there a better way?

For energy usage monitoring I need a sensor with the total value of kWh used. I need it to always go higher and never reset to 0 for the same device. That way I can easily calculate the usage for any given interval (in SQL, or with Grafana).

By default a ESPHome sensor will lose it’s value after a power down and start again at 0. You could persist it in flash but even the manual warns that it will wear out your flash memory.

I would really like a simple way (as a configuration parameter for the native api in ESPHome?) to make ESPHome automatically use the last value it reported to Home Assistant after a reboot as a new base value.

Am I missing something?

My current workaround is a Home Assistant service configured in the device, together with an input_number and two automations in Home Assistant like this:

I am using my own custom component, but I hope one can make it work with other sensors too:

On the device:

api:
  password: !secret homeassistant_api_password
  services:
    - service: restore_usage
      variables:
        old_usage: float
      then:
        - lambda: |-
           ((CSE7776Component*)id(my_cse7776))->set_last_usage(old_usage);

In home assistant (you have to create the input_number first):

- alias: save old usage in input number when sensors goes unavailable
  trigger:
    platform: state
    entity_id: sensor.stromverbrauch_0_1_2
    to: unavailable
  action:
  -  service: input_number.set_value
     data_template:
       entity_id:  input_number.last_power_meter_usage_value
       value: "{{ trigger.from_state.state }}"

- alias: restore value from input number when sensors comes back online by calling it's service 
  trigger:
    platform: state
    entity_id: sensor.stromverbrauch_0_1_2
    to: unknown
  action:
  -  service: esphome.powermeter_restore_usage
     data_template:
       old_usage:   "{{ states('input_number.last_power_meter_usage_value') }}"

There has to be a better way? I have 10 such sensors…

1 Like

How about storing the values as retained messages in an mqtt broker?

If you use mqtt rather than the api this would mean no extra code to store the values.

Use the on_boot trigger in the esp to restore the values. If that’s possible. I haven’t looked into it.

@danielw Did you ever come up with a better solution? I’ve got a similar situation where I’d really like to retain a value through reboots.

Isn’t restore_value what you are looking for? I never used that, but this is my understand from reading the docs.

Definitely didn’t see that when I setup my device; thanks!

Any idea of what kind of a read/write count would start to be of concern when it comes to degrading the memory? My use-case is volume for an audio amplifier, so we’re talking tens of changes each day. I’m guessing it won’t be an issue for my use-case, but kind of curious for other projects. Obviously a failure isn’t the end of the world since ESPs are cheap, but still…

I don’t know about the limit, but I wouldn’t expect this to be a problem unless you are writing tons of values every second, which is probably not the case for almost all ESP use cases.

Good to know! And thanks again for helping me out! Implemented it already, so we’ll see if it works as I expect it to.

1 Like

I am now using something based on the idea of tom_l. I am storing the value in a MQTT retain message. That wis working fine the last years. Not sure if there is a better way today.

It works like this:

A global to hold the last usage with an initial value of NAN

globals:
 - id: last_usage
   type: float
   restore_value: no

An MQTT on_message that waits for the first “total_usage” message after boot (the broker will deliver all retain messages to every client after connect) and stores it global “last_usage”. The local static bool “already_restored” makes sure that it will only once at boot fetch the value and not the message the device itself updates.

mqtt:
  broker: mosquitto
  discovery: False
  on_message:
    - topic: "power_meter/total_usage"
      then:
        lambda: |-
          static bool already_restored = false;
          if (already_restored)
            return;

          auto value = esphome::parse_number<float>(x);
          if (value.has_value()) {
            id(last_usage) = value.value();
            already_restored = true;
          }

An integration sensor with a filter that will deliver the actual value since boot added the restored_value if that has already been restored. If the last value is not restored yet, it will produce a NAN and later filter that. That makes it that it will only start to deliver the total (after a new boot) when it has received the previous value.

  - platform: integration
    name: energy
    sensor: power
    time_unit: h
    unit_of_measurement: "kWh"
    accuracy_decimals: 3
    icon: mdi:counter
    state_topic: "power_meter/total_usage"
    device_class: energy
    state_class: total_increasing
    filters:
    - multiply: 0.001
    - lambda: |
        static float restored_value = NAN;
        if (isnan(restored_value) && !isnan(id(last_usage)))
        {
           restored_value = id(last_usage);
           ESP_LOGI("main", "Restored value: %f", restored_value);
        }
        return !isnan(restored_value) ?  restored_value+x : NAN;
    - filter_out: NAN

The final step is to make it work to once push the expected initial value to the topic manually. (using mosquitto_pub or any other MQTT tool). It also allows you to change the last value for example if you had an issue with the sensor for a few days and want to fix the current value to the new value on the actual meter. (just remove power vom the esp, push the new message on the topic manually and restart the esp).

I know it looks quite complicated but works very stable for years now with multiple sensors. Thanks to tom_l for the idea.

Regarding the “restore_value” feature. Sure that should work. I was afraid it would wear out the flash memory on my ESP8266. I was pushing a message every rotation of my ferraris meter which means a message every 1 /375 kWh of enery used so about 2000 values a day. I expect that to kill the flash in a few months, but not sure.

1 Like

Hi @danielw,
Have you found another way or are you still using this technic?