I am trying to get the gas values in real time, I am using the following hardware: ESP8266 d1 mini, with contact reed . if the mechanical gas counter shows 1.005 m³ ≈ 100 pulses , the reed contact is registering 1.470 m³ ≈ 147 pulses (≈ +46 %). I tried to place the contact reed further but I was able to get to 28% error and I set the pulse to 4000 ms. Any idea, if I can reach my goal with this reed contact or is it the code that is not adequate? Thank in advance for the help.
My gas meter is a Dresser G4 NPL12/110 EI (1 imp = 0.01 m³, Qmax = 6 m³/h), I am using the following code for the pulse counter.
substitutions:
devicename: gas-meter
# Dresser G4 label: 1 imp = 10 dm³ = 0.01 m³
m3_per_pulse: "0.01"
# Start at 1500 ms; raise to 2000–3000 ms if you still see occasional double counts
min_pulse_gap_ms: "5500"
esphome:
name: ${devicename}
esp8266:
board: d1_mini
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
logger:
level: DEBUG # VERY_VERBOSE only for short tests
api:
ota:
platform: esphome
preferences:
flash_write_interval: 60s
# --- Debug helpers (no extra pin ownership) ---
globals:
- id: last_accept_ms
type: uint32_t
restore_value: no
initial_value: '0'
- id: accepted_no
type: uint32_t
restore_value: no
initial_value: '0'
sensor:
- platform: pulse_meter
id: gas_flow_pulse
pin:
number: D1 # GPIO5
mode:
input: true
pullup: true
inverted: true
name: "Gas Flow"
unit_of_measurement: "m³/h"
device_class: gas
state_class: measurement
accuracy_decimals: 3
# KEY: merge/ignore pulses closer than the min gap (bounce / double-edge)
internal_filter: ${min_pulse_gap_ms}ms
# Low flows: don't drop to zero too quickly
timeout: 120s
# pulses/min -> m³/h
filters:
- multiply: !lambda "return (${m3_per_pulse}) * 60.0;"
# Log each ACCEPTED pulse timing (debug; safe to keep or remove later)
on_value:
then:
- lambda: |-
const uint32_t now = millis();
const uint32_t dt = (id(last_accept_ms) == 0) ? 0 : (now - id(last_accept_ms));
id(last_accept_ms) = now;
id(accepted_no)++;
// x is the current sensor state (m³/h) after this accepted pulse
ESP_LOGI("pulse", "ACCEPTED #%u gap=%u ms (%.3f s), flow=%.2f m3/h",
id(accepted_no), dt, dt/1000.0, x);
total:
name: "Gas Total"
unit_of_measurement: "m³"
device_class: gas
state_class: total_increasing
accuracy_decimals: 3
filters:
- multiply: ${m3_per_pulse}
# Optional health metrics
- platform: wifi_signal
name: "Wi-Fi Signal Strength"
update_interval: 3600s
- platform: uptime
name: "Device Uptime"
update_interval: 3600s
switch:
- platform: restart
name: "Restart ${devicename}"
Have you tried fiddling with the internal_filter: values? What you are seeing sounds like debounce issues - that setting is to help cope with debounce.
internal_filter (Optional, Time): If a pulse shorter than this time is detected, it is discarded. Defaults to 13us.This acts as a debounce filter to eliminate input noise, so choose a value a little less than your expected minimum pulse width.
internal_filter_mode (Optional, string): Determines how the internal filter is applied. One of EDGE or PULSE. Defaults to EDGE.
In EDGE mode, subsequent rising edges are compared and if they fall into an interval lesser than the internal filter value, the last one is discarded. This is useful if your input signal bounces, but is otherwise clean.
In PULSE mode, the rising edge is discarded if any further interrupts are detected before the internal_filter time has passed. In other words, a high pulse must be at least internal_filter long to be counted. This is useful if you have a noisy input signal that may have bounces before and/or after the main pulse.
It’s a start. Try various values until you get the result that matches the meter. 5ms is a longish time - make sure the reed switch is always closed for at least that long each pulse.
There is a little known “gotcha” that trips a lot of people up when using the pulse counter.
The pulse counter updates every minute by default, but…
The first reading after a restart is offset by some random amount of time (so multiple sensors aren’t all time synchronised and don’t spam the cpu at once).
Try waiting for a few updates (minutes) after a restart before taking your calibration measurement. This confused the heck out of me when setting up my rain gauge pulse counter with a 15 minute update interval. I had to wait >15 minutes after a restart then do the calibration test.
Thank you @tom_l for the tip, I will keep it in mind when I do the next update.
Ok @zoogara , will start doing this. Just waiting to be able to physically take pictures and test.
Do you think replacing the reed by a bipolar hall sensor US1881 would solve the problem and provide better accuracy?
You could use external pullup, 10k for example.
Also, if your Qmax is 6m3/h the shortest possible pulse interval is 6s. That gives you plenty of room to play with the internal_filter…