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:
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…
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.
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.
First, thanks @danielw for this solution to storing values in MQTT, it works a treat.
Just a note on the snippet of code for globals above. It may have been truncated with the cut/paste but the process logic relies on an initial value of NAN (as you have stated) and my testing says that a global value of type: float has a default initial value of 0.0.
So that part of the code solution above should include
initial_value: NAN
just in case someone else finds and follows this thread