Pulse_meter keeps the last value as current flow, even flow = 0

Hi,

I’ve been playing with Chinese 1" pulse flow meter YF-B10. Got it wired up and pulses come pretty OK, some deviation time to time.

But, it keeps showing the last actual flow value, even there is no flow and no pulses. I’ve tried to configure it (and some ChatGPT stuff), but no luck.

My current ESPHome config:


mqtt:
  broker: xxx.xxx.xxx.xxxx
  port: xxxx
  discovery: true
  discovery_prefix: homeassistant

globals:
  - id: cumulative_pulses
    type: float
    restore_value: true  # Persist across reboots
    initial_value: '0.0'

sensor:
  - platform: pulse_meter
    id: flow_rate
    name: "Flow Rate"
    pin: GPIO21
    unit_of_measurement: "L/min"
    accuracy_decimals: 1
    state_class: measurement
    internal_filter: 5ms
    timeout: 1s  # Mark flow as 0 after 1 second without pulses
    force_update: true  # Force MQTT to send 0 when no pulses are detected

    filters:
      - lambda: |-
          if (x == 0) return 0.0;  // If no pulses, return 0
          if (x < 709) return 0.0;  // Ignore flow below 2 L/min (corresponding to 709 pulses/min)
          return ((x - 709) / 354.8) + 2.0;  // Apply calibration: 354.8 pulses/L, threshold at 2 L/min
      - throttle: 1s  # Limit updates to every 1 second
      - sliding_window_moving_average:
          window_size: 5
          send_every: 1
      - clamp:
          min_value: 0.0
          max_value: 30.0  # Adjust for max sensor capacity

  - platform: template
    name: "Cumulative Flow"
    unit_of_measurement: "L"
    accuracy_decimals: 2
    state_class: total_increasing  # Required for HA Energy dashboard
    lambda: |-
      // Convert the cumulative pulses to liters
      return (id(cumulative_pulses) * 0.002817);

interval:
  - interval: 1s
    then:
      - lambda: |-
          // Add the current raw pulse count to the cumulative total
          id(cumulative_pulses) += id(flow_rate).state;

I thought that timeout: 1s should have worked, but no.

Those straight lines in chart don’t have any updates in between.

I made template sensor in config.yaml to fix it. This helps a bit, but there are still some ghost remains 5-50 sec after no flow:

template:
  - sensor:
      - name: "Flow Rate Corrected"
        unit_of_measurement: "L/min"
        state: >-
          {% set last_change = as_timestamp(states.sensor.flowmeter_esp_flow_rate.last_changed) %}
          {% set time_now = as_timestamp(now()) %}
          {% set flow_rate = states('sensor.flowmeter_esp_flow_rate') | float(0) %}
          {% if (time_now - last_change) > 2 or flow_rate == 0 %}
            0
          {% else %}
            {{ flow_rate }}
          {% endif %}
        availability: >-
          {{ states('sensor.flowmeter_esp_flow_rate') not in ['unknown', 'unavailable', 'none'] }}

I am not an expert on esphome, but I did once use the pulse meter. (I switched to Tasmota, because I found esphome no reliable, but that might have been the HW I was using).

I do know enough to know that if you NEED to use ChatGPT to configure esphome you WILL likely have a bad experience. This section is littered with posts from people saying ChatGPT told them to do it that way.

The documentation on many of the components is not easy to understand (unless perhaps if you are already an expert).

Read this: Pulse Meter Sensor — ESPHome

If you don’t understand any part of it, ask questions until you do.

This component appears to be able to do the conversion you doing a different way (pulses to liters). It also has a timeout that defaults to 5 min that will return the flow rate to zero, you can shorten that value and likely get what you want.

I’m using the pulse-meter with a similar flowmeter, but have not experience that kind of problem as I can remember. It’s a year or two since I was playing with the code…

Two things that I thought of

  1. What does the raw value from the sensor looks like in the log? Does it go to zero or is it also keeping a value like the scaled one?

  2. I may be totally wrong here, but what is actual happening in the filter function?
    Will it jump out immediately when an if-condition is met, or will it continue to evaluate/execute the rest as well in that “block”?
    Could that cause some weird behavior?
    Will it make any difference if the filter is set up as an if/elseif/else function instead to force only one return to be valid?

Did you (yet) try configuring according the docs? :thinking:

And asking humans to debug it :person_facepalming: Welcome to 2025 :tada: