How to get the rate from a counter?

I use 1-wire sensors DS2423 to count several things like water, energy, wind, etc.
These counters are polled by HA using SNMP from a OWserver. Works great!

My problem now is how to calculate the rate of the meter, using the counter values.
Ideally I would like to calculate the rate when a new sample is available as:
rate = (value - counter[last entry]) / (now - time[last_entry])

  • value: New counter value
  • counter[last entry] : Previous counter value
  • now: Current time
  • time[last_entry]: Time for last entry

Any suggestions how to write this code?

Not sure I fully understand but based on this

I would probably create a few input_text: input_text.rate

and an automation that goes something like:

    platform: state
    entity_id: sensor.counter
    service: input_text.set_value
      entity_id: input_text.rate
      value: '{{ (trigger.to_state.state | float - trigger.from_state.state | float) / (as_timsetamp(now()) - as_timestamp(states.input_text.rate.last_changed)) }}'

Note, this is completely untested and I don’t know if the states.input_text.rate.last_changed in above formula will return the last time it got updated, but I hope it does.
Then if you want a “true” sensor you can add a template_sensor that picks up the value of input_text.rate

Trying to follow what you want and I think this will give you a rate of change value:

I’ve never used it so I can’t really help with the implementation.

It took a while, but now the statistics template is working for me. (The “_mean” suffix was not expected…)
I think the module assumes all samples are evenly spaced in time. The rate etc. is using a number of samples without looking at the sample times.
Please consider to improve this module so the time for each sample is used.
Here is an example where I stopped sampling a counter for a while. The rate should be approximately flat, but…

The “change” attribute of statistics module is actually reporting the diff between oldest and newest data:

                self.change = self.states[-1] - self.states[0]

“change_rate” is calculated with a very odd unit "(change / #entries) / time

                    self.average_change /= len(self.states) - 1
                    time_diff = (self.max_age - self.min_age).total_seconds()
                    if time_diff > 0:
                        self.change_rate = self.average_change / time_diff

I made a quick hack and modified change_rate attribute lite this:

                self.change_rate = (self.states[-1] - self.states[-2]) / (self.ages[-1].timestamp() - self.ages[-2].timestamp())

This is the immediate change_rate as I see it. len(self.states) is completely wrong to use as it assumes something about the sample rate.
After I apply a low-pass filter on this signal I get the curve I wanted.