ESPHome pulse_counter update_interval less than 60s (maybe be a bug?)

Tags: #<Tag:0x00007f326d538f80> #<Tag:0x00007f326d538e68>

I’m using the pulse_counter sensor and playing around with it to understand how it works. I’ve noticed that when I change the update_interval value to be anything other than 60s the number of pulses is calculated against this. Here are some examples to show what I mean:

update_interval ==> output_value with one button press
1s ==> 60 pulses/min
5s ==> 12 pulses/min
10s ==> 6 pulses/min
30s ==> 2 pulses/min
60s ==> 1 pulses/min

This is the ESPHome yaml I’m using to test:

sensor:
  - platform: pulse_counter
    pin:
      number: D3
      mode: INPUT_PULLUP
    name: 'Pulses'
    id: pulses
    count_mode:
      rising_edge: DISABLE
      falling_edge: INCREMENT
    internal_filter: 13us
    update_interval: XX
    filters:
      - debounce: 400ms
    accuracy_decimals: 3

Where update_interval: XX is set to 1s, 5s, 10s, 30s and 60s.

With it set to 1s this is the output when pressing the button slowly (less than 1 press per second) I get a value of 60 pulses/min:

[13:53:22][D][pulse_counter:159]: 'Pulses': Retrieved counter: 0.00 pulses/min
[13:53:22][D][sensor:092]: 'Pulses': Sending state 0.00000 in with 3 decimals of accuracy
[13:53:23][D][pulse_counter:159]: 'Pulses': Retrieved counter: 0.00 pulses/min
[13:53:23][D][sensor:092]: 'Pulses': Sending state 0.00000 in with 3 decimals of accuracy
[13:53:24][D][pulse_counter:159]: 'Pulses': Retrieved counter: 60.00 pulses/min
[13:53:24][D][sensor:092]: 'Pulses': Sending state 0.60000 in with 3 decimals of accuracy
[13:53:25][D][pulse_counter:159]: 'Pulses': Retrieved counter: 0.00 pulses/min
[13:53:25][D][sensor:092]: 'Pulses': Sending state 0.00000 in with 3 decimals of accuracy
[13:53:26][D][pulse_counter:159]: 'Pulses': Retrieved counter: 60.00 pulses/min
[13:53:26][D][sensor:092]: 'Pulses': Sending state 0.60000 in with 3 decimals of accuracy
[13:53:27][D][pulse_counter:159]: 'Pulses': Retrieved counter: 0.00 pulses/min
[13:53:27][D][sensor:092]: 'Pulses': Sending state 0.00000 in with 3 decimals of accuracy
[13:53:28][D][pulse_counter:159]: 'Pulses': Retrieved counter: 0.00 pulses/min
[13:53:28][D][sensor:092]: 'Pulses': Sending state 0.00000 in with 3 decimals of accuracy
[13:53:29][D][pulse_counter:159]: 'Pulses': Retrieved counter: 60.00 pulses/min
[13:53:29][D][sensor:092]: 'Pulses': Sending state 0.60000 in with 3 decimals of accuracy

With a value of 5s I see 12 pulses/min (60 / 5 = 12):

[13:58:14][D][pulse_counter:159]: 'Pulses': Retrieved counter: 12.00 pulses/min
[13:58:14][D][sensor:092]: 'Pulses': Sending state 0.12000 in with 3 decimals of accuracy
[13:58:19][D][pulse_counter:159]: 'Pulses': Retrieved counter: 12.00 pulses/min
[13:58:19][D][sensor:092]: 'Pulses': Sending state 0.12000 in with 3 decimals of accuracy
[13:58:24][D][pulse_counter:159]: 'Pulses': Retrieved counter: 24.00 pulses/min
[13:58:24][D][sensor:092]: 'Pulses': Sending state 0.24000 in with 3 decimals of accuracy
[13:58:29][D][pulse_counter:159]: 'Pulses': Retrieved counter: 12.00 pulses/min
[13:58:29][D][sensor:092]: 'Pulses': Sending state 0.12000 in with 3 decimals of accuracy

With a value of 10s I see 6 pulses/min for each button press:

[14:00:07][D][pulse_counter:159]: 'Pulses': Retrieved counter: 0.00 pulses/min
[14:00:07][D][sensor:092]: 'Pulses': Sending state 0.00000 in with 3 decimals of accuracy
[14:00:17][D][pulse_counter:159]: 'Pulses': Retrieved counter: 6.00 pulses/min
[14:00:17][D][sensor:092]: 'Pulses': Sending state 0.06000 in with 3 decimals of accuracy
[14:00:27][D][pulse_counter:159]: 'Pulses': Retrieved counter: 6.00 pulses/min
[14:00:27][D][sensor:092]: 'Pulses': Sending state 0.06000 in with 3 decimals of accuracy
[14:00:37][D][pulse_counter:159]: 'Pulses': Retrieved counter: 0.00 pulses/min
[14:00:37][D][sensor:092]: 'Pulses': Sending state 0.00000 in with 3 decimals of accuracy
[14:00:47][D][pulse_counter:159]: 'Pulses': Retrieved counter: 0.00 pulses/min
[14:00:47][D][sensor:092]: 'Pulses': Sending state 0.00000 in with 3 decimals of accuracy

Maybe this is expected because it’s normalized to pulses/min but it seems like it should just report pulses…

I am experimenting with a rain gauge at the moment and also stumbled upon this unexpected behaviour. Internally, the pulse_counter is changing the raw value (i.e. the actual number of pulses counted since the last update) to normalise it to “pulses per minute”. In other words, with an update interval of 60 seconds you get the actual number of pulses in those last 60 seconds.

For comparison, in my example with the rain gauge, I know that each pulse is equal to 0.2794mm of rain, so I’m using a multiply filter with value “0.2794” and changed the unit_of_measurement to “mm”.

Maybe what you want is to use a multiply filter with a value of (update_interval/60) and change unit_of_measurement to “pulses”?

Yeah, I have a rain gauge too that I’ve enabled with ESPHome using the multiplier and I wanted to understand how to properly handle and accumulate (using an integration sensor). My current setup isn’t working correctly to accumulate hours and days (see the images I posted here for details). I’ve figured it out by building a testbed with an extra esp8266 and a button and forcing pulses but while I was doing that I noticed that all the pulse_counter options are centered around pulses per minute and that’s hard coded in ESPHome. Seems like that shouldn’t be since you could just report straight pulse counts but I don’t know the inner workings of ESPHome.

Anyway, if nothing else this thread will be here to help others who may not know that you have to sample pulse_counter with update_interval of 60s.

Well, let’s compare notes then.

My ESPHome code looks like this:

sensor:
  - platform: pulse_counter
    name: "Rain Gauge"
    pin:
      number: GPIO25
      mode: INPUT_PULLUP
    unit_of_measurement: "mm"
    icon: "mdi:water"
    filters:
      - multiply: 0.2794

As mentioned above, the reason for the multiply filter is because each pulse means that 0.011in = 0.2794mm of rain were counted.

And in Home Assistant I set up 3 simple utility_meter entities based on the ESP’s sensor data:

utility_meter:
  rain_per_hour:
    source: sensor.esp_weather_station_rain_gauge
    name: Rain per hour
    cycle: hourly
  rain_per_day:
    source: sensor.esp_weather_station_rain_gauge
    name: Rain per day
    cycle: daily
    offset:
      hours: 9
  rain_per_month:
    source: sensor.esp_weather_station_rain_gauge
    name: Rain per month
    cycle: monthly

The hourly and monthly ones are literally just accumulating the rain in mm over the current hour and current month respectively. The daily one has an offset because - at least here in Australia - the rain per day is measured from 9am to 9am.

In addition to all that I set up a statistics sensor that accumulates rainfall over the last 60 minutes, and a template sensor that translates that into rain intensity:

sensor:
  - platform: statistics
    entity_id: sensor.esp_weather_station_rain_gauge
    name: Rain over last 60 minutes
    # Device reports value each minute
    sampling_size: 60
    max_age:
      minutes: 60
  - platform: template
    sensors:
      rain_intensity:
        friendly_name: "Rain Intensity"
        value_template: >-
          {% if state_attr('sensor.rain_over_last_60_minutes', 'total')|float == 0.0 %}
            None
          {% elif state_attr('sensor.rain_over_last_60_minutes', 'total')|float < 2.5 %}
            Light
          {% elif state_attr('sensor.rain_over_last_60_minutes', 'total')|float <= 7.5 %}
            Moderate
          {% elif state_attr('sensor.rain_over_last_60_minutes', 'total')|float <= 50.0 %}
            Heavy
          {% else %}
            Violent
          {% endif %}
        availability_template: "{{ not is_state('sensor.rain_over_last_60_minutes', 'unavailable') }}"

I just learned something new about the utility_meter: It expects an increasing source value. But it also compares the current value with the previous value, and if the current value is smaller than the previous value it just ignores the new value.

In other words, there are potentially some flaws when only using the utility_meter, especially in heavy rain. Let’s say the rain gauge sends values every minute, here is how a utility_meter would sum up the values:

  • 1 / 0 / 1 / 0 / 1 => 3 units. Correct.
  • 1 / 0 / 1 / 1 / 0 => 2 units. Incorrect, should be 3.
  • 1 / 0 / 2 / 0 / 1 => 4 units. Correct.
  • 1 / 2 / 0 / 1 / 0 => 3 units. Incorrect, should be 4.

I think my experiments with this rain gauge need to continue. Possible candidates to explore: min/max sensor or integration sensor.

pulse_counter reports a rate (ie pulses per minute which you multiply by a factor to get litres per minute etc)

utility_meter is based on a quantity, (ie litres etc). Because it is based on quantity measured, naturally it expects an increasing amount (you can’t put the water back, or decrease the number of litres that have passed through the counter).

I guess these days you can put electricity back into the grid, but you’d have to measure that separately and subtract it.

1 Like