Utility meter - add parameter for reading normalization

Use case
I’m using utility meter for my water sensor. Sensor is reporting values in no constant time (between 90s and 20 minutes). It’s reporting more often when water flows. However if last reading happened while ago, it’s going into “lazy mode”.
I have two separte utility meters definied - one for gathering usage for 3 minutes and second for 15 minutes. Since sensor most of the time reports less than 20 min - 15min utility sensor provides quite accurate values (deltas). However if sensor report less often than 3min - 3min utility sensor gathers over-normative readings:

Previous water sensor report time : 10:01:00 [value 10]
Last water sensor report time : 10:09:00 [value 25]

Delta between last reading will be 15. However real water usage would be 5 per 3 minute period. So if we could obtain values every 3 min - it wold be a sequence of deltas [5,5,5] and last 3min utility meter would report 5 instead of 15.

Idea
The idea is to add attribute to utility sensor to add such capability - to normalize delta if utility meter cycle is less than sensor reading. Of course there is a tradeoff - it need to be interpolated - probably only rational solution is to use linear interpolation.

If attribute is set utility meter would check if related sensor last_change time is more than cycle. If so it do computation (cycle_period / timedifff(related_sensor.last_change - utility_meter.last_updated) * delta_value). If else it provide raw value without altering it.
In general we calculate what percent of time beetween last read and current read is our cycle.

Previous water sensor report time : 10:01:00 [value 10]
Last water sensor report time : 10:09:00 [value 25]
Cycle : 3 min = 180s

10:09:00 - 10:01:00 = 8 min (480s)
percent = 180/480 ~ 38%

value interpolation  = (25-10)*38% = 5,7
reading without interpolation = 15
real world would be 5.

Visualization
Sensor readings and utility meter deltas combined.

The utility meter is state driven it can only update when a change of state is received. If you want to do this you will have to implement a template sensor. Or get a sensor that updates more frequently.

Wait, what? I checked last_updated of utility meter entity and it’s triggered every 3min regardless state change of related sensor.

Part of my testing…

{% set read_reported_timediff = (as_timestamp(states.sensor.czas_odczytu_woda_zimna.state) - as_timestamp(states.sensor.zimna_woda_3_min.last_changed)) %}
TIMEDELTA                   : {{ timedelta(seconds = read_reported_timediff) }}
SENSOR_PAYLOAD_TIMESTAMP    : {{ as_timestamp(states.sensor.czas_odczytu_woda_zimna.state) | timestamp_custom("%d/%m/%y %H:%M:%S") }}
RELATED_SENSOR_LAST_UPDATED : {{ as_timestamp(states.sensor.zimna_woda.last_updated) | timestamp_custom("%d/%m/%y %H:%M:%S") }}
3MIN_METER_LAST_UPATED      : {{ as_timestamp(states.sensor.zimna_woda_3_min.last_updated) | timestamp_custom("%d/%m/%y %H:%M:%S")}}

Produces

SENSOR_PAYLOAD_TIMESTAMP    : 02/06/22 14:27:06
RELATED_SENSOR_LAST_UPDATED : 02/06/22 13:12:34
3MIN_METER_LAST_UPATED      : 02/06/22 14:27:00

RELATED_SENSOR_LAST_UPDATED and 3MIN_METER_LAST_UPATED are different. So I think it’s possible to get timediff.

That’s the cycle of the utility meter isn’t it?

It will reset every three minutes but it only accumulates when there is a state change to the sensor you are feeding it.

OK. So basically it’s just a delta values grabber of sensor feeding it and it just set sum to 0 every cycle. My change request is pointless then :slight_smile: