Some hardware links on this page are affiliate links. As an Amazon Associate I earn from qualifying purchases. We may earn a commission if you buy through them, at no extra cost to you. See the affiliate disclosure.
An analog water meter already has the measurement. A small magnet on the liter dial, or a pair of pulse wires the utility left on the register, closes a contact once per unit of water. This pack puts an ESP32-C6 Super Mini on that contact, turns each closure into liters per minute and a running total, and pages you when flow keeps going long after every tap should be shut.
Wi-Fi credentials stay in secrets.yaml. The liters-per-pulse number is a substitution you fill after a bucket test. Do not publish a live meter’s total or a photo of the register.
A puddle under one fixture is a different sensor. Pair this with IKEA Badring leak alert for a probe on the floor. A circulator pump on a timer is hot water recirculation on demand.
What problem it solves
You want today’s water use, and a warning when a toilet flapper or a hose bib runs for the better part of an hour, from the meter you already have.
How it works
- One pulse, one GPIO — a normally-open reed sits between the pulse pin and ground. The pin’s pull-up holds it high. Each time the meter magnet passes, the reed closes, the pin falls, and
pulse_metercounts the edge. A meter that already has a dry-contact pulse cable lands on the same two wires. - Rate —
pulse_meterreports pulses per minute. A multiply filter scales that byliters_per_pulse, so the entity is liters per minute.timeout(pack default 2 minutes) returns the rate to 0 after the magnet stops. Without that timeout the last rate sits on the dashboard forever. - Total — the component’s
totalblock counts pulses and applies the same liters-per-pulse scale.device_class: waterandstate_class: total_increasinglet Home Assistant graph it. A reboot can restart the on-device counter at 0.total_increasingtells Home Assistant that drop is a meter reset, and a Utility Meter helper keeps the daily and monthly sums. - Debounce — a glass reed bounces.
internal_filter: 200mswithinternal_filter_mode: PULSEignores edges closer together than that. If a single dial revolution shows up as two or three pulses, raise the filter before you touchliters_per_pulse. - Continuous flow — a blueprint watches the flow sensor. Above a trickle you set, for longer than a real shower, it sends one notification. The duration has to be longer than the longest legitimate draw, or a bath becomes an alarm.
Leave the meter sealed. The reed goes on the outside of the glass, over the dial that carries the magnet, or on the pulse terminals the manufacturer brought out. It does not go inside the register.
Hardware notes
- Board. ESP32-C6 Super Mini, mains-powered from the USB-C supply. Leave GPIO8 (LED and strap), GPIO9 (BOOT and strap), GPIO12 and GPIO13 (USB), and GPIO15 (strap) alone. The pack uses GPIO6 for the pulse, with the internal pull-up.
- Reed. A normally-open glass reed closes only while a magnet is close. The linked set is 2×14 mm normally-open contacts plus small magnets. A normally-closed door contact is the wrong part: it sits closed all day and the counter runs wild. If the meter already has a pulse cable, you may not need a separate reed at all.
- Placement. Tape the reed to the register glass where a fridge magnet on the dial makes it click once per revolution. Confirm with a continuity beep before you close the box. Keep the leads short, and keep them off the I²C pins if you add the optional sensor.
- Optional climate. An AHT20 on GPIO0 (SDA) and GPIO1 (SCL) is the same bus as the ESP32-C6 climate sensor. Skip it when you only want water.
Wiring
| Reed or meter pulse cable | ESP32-C6 Super Mini |
|---|---|
| Contact A | GPIO6 |
| Contact B | GND |
The internal pull-up is enabled in YAML. An external resistor is optional.
| AHT20 (optional) | ESP32-C6 Super Mini |
|---|---|
| VCC | 3V3 |
| GND | GND |
| SDA | GPIO0 |
| SCL | GPIO1 |
Snippet
Pins and the calibration factor are substitutions. Measure liters_per_pulse before you trust the total.
substitutions:
pulse_pin: GPIO6
liters_per_pulse: "1.0"
sensor:
- platform: pulse_meter
pin:
number: ${pulse_pin}
mode:
input: true
pullup: true
name: "Water flow"
unit_of_measurement: "L/min"
device_class: volume_flow_rate
state_class: measurement
accuracy_decimals: 2
timeout: 2min
internal_filter: 200ms
internal_filter_mode: PULSE
filters:
- multiply: ${liters_per_pulse}
total:
name: "Water total"
unit_of_measurement: "L"
device_class: water
state_class: total_increasing
accuracy_decimals: 3
filters:
- multiply: ${liters_per_pulse}
The continuous-flow blueprint takes the flow entity, a threshold in L/min, a duration, and a notify target (!input). A Utility Meter helper on sensor.water_total, cycled daily, is the number to put on a dashboard.
Setup outline
- Flash the YAML. Confirm the flow entity sits at 0 with every tap off.
- Fill a container you can measure (a 10 L bucket is enough). Count the pulses on the total while it fills.
liters_per_pulseis volume divided by pulses. Put that number in the substitution and reflash. - Run the same volume again. The total should move by about that volume. A factor-of-two error is almost always a bounce (raise
internal_filter) or a dial that pulses twice per liter. - Add a Utility Meter on the total, cycle daily or monthly.
- Import the continuous-flow blueprint. Set the threshold just above what you read with the house quiet, and the duration longer than a shower. Trigger it once with a low threshold so you see the notification, then put the real numbers back.
Troubleshooting
- Total climbs with the water off. The reed is normally closed, the wires are shorted, or the magnet sits on the reed at rest. Use a normally-open contact, and move it until it clicks only as the dial magnet passes.
- One revolution counts two or three. Contact bounce. Raise
internal_filter(try 500 ms) and repeat the bucket test. Changeliters_per_pulseonly after one revolution is one pulse. - Flow stays at the last number after you close the tap.
timeoutis missing or very long. The pack default is 2 minutes, which is the gap that means “stopped.” - Total returns to 0 after a power cut. The on-device counter restarted. Home Assistant statistics and the Utility Meter keep history when
state_classistotal_increasing. The ESP number is “since boot”; the helper is the one you read. - No pulses at all. The magnet never reaches the reed, or the pulse cable is a powered output rather than a dry contact. A dry contact clicks on a continuity meter. A powered output needs a different interface. Do not tie a meter wire that is above 3.3 V straight to the GPIO.
- Board will not boot. The pulse wire landed on a strap pin (GPIO8, GPIO9, or GPIO15) and holds it during reset. Move it to GPIO6.
Credits
Pulse counting on an ESP32-C6 for a Home Assistant water total follows the SmartHomeShop WaterMeterKit V3 (firmware). This write-up is an original Super Mini recipe: a normally-open reed or the meter’s own pulse contact, a liters-per-pulse calibration, and a continuous-flow alert. It does not use that kit’s board, cloud firmware, or onboard humidity sensor.