DIY water leak sensors with an ESP32 and ESPHome
A slow leak under a sink or water heater can rot a floor before anyone notices. One ESP32 can watch several spots with nothing more than pairs of wire probes, and send an alert to your phone the moment water shows up.
How it works
Each sensor is two bare metal contacts sitting a few millimeters apart on the floor. Dry, nothing connects them. When water bridges the gap, a small current flows and the ESP32 pin reads it.
The trick is getting the sensitivity right. Tap water conducts, but not well. The ESP32's built-in pull-up resistor is fairly strong, and clean water between probes may not pull the pin low enough to register. A much weaker external pull-up — a 1 MΩ resistor — lets even a thin film of water trigger the input reliably.
Parts
- An ESP32 DevKit with a USB power supply, placed somewhere dry above the leak spots.
- One 1 MΩ resistor per probe.
- Probes: two stainless steel screws in a small plastic block, or ready-made water leak probe cables sold for alarm panels.
- Two-conductor wire to each probe. Runs of several meters are fine.
Wiring
For each probe:
- One probe contact goes to GND.
- The other goes to a GPIO pin, such as GPIO27.
- A 1 MΩ resistor goes from that same GPIO to 3.3V.
Use pins from the "safe" list in the ESP32 safe pin finder. GPIO25, 26, 27, 32 and 33 are good choices for several probes.
Avoid copper or bare steel for the contacts. A constant small current makes them corrode. Stainless steel screws or the gold-plated contacts on commercial probes last for years.
The ESPHome config
Add one block per probe to an ESP32 config (the config generator makes the base). The internal pull-up is turned off because the 1 MΩ resistor replaces it:
binary_sensor:
- platform: gpio
name: "Water heater leak"
device_class: moisture
pin:
number: GPIO27
mode:
input: true
pullup: false
inverted: true
filters:
- delayed_on: 2s
- delayed_off: 30s
- platform: gpio
name: "Kitchen sink leak"
device_class: moisture
pin:
number: GPIO26
mode:
input: true
pullup: false
inverted: true
filters:
- delayed_on: 2s
- delayed_off: 30s
The filters keep it honest. A reading has to stay wet for 2 seconds before it counts, which ignores electrical noise on long wires, and stay dry for 30 seconds before it clears, so a drip doesn't flicker on and off.
Testing
Before trusting it, test each probe the way a real leak would happen. Pour a tablespoon of tap water on the floor where the probe sits, and confirm the sensor turns on within a few seconds. Dry it and watch it clear. Testing with a wet finger isn't the same; skin conducts better than a puddle.
Alerts in Home Assistant
Because the sensors use the moisture device class, Home Assistant shows them as Wet or Dry. Create an automation triggered when any leak sensor turns on, and send a critical notification to every phone. On iPhone, the Home Assistant app's critical alerts play a sound even when the phone is on silent, which is worth enabling for this one automation.
Also alert when the sensor goes offline
A leak sensor that's lost power is worse than none, because you assume it's watching. Add a second automation that warns you if the sensor's state becomes unavailable for more than 10 minutes.
Going further
- Automatic shutoff. A motorized ball valve on the main water line, driven by a relay from the same ESP32, can close the water the moment a leak is detected. Have a plumber fit the valve.
- Freeze warning. Add a DS18B20 temperature probe near pipes in a crawlspace or garage, and alert below 3 °C.
- Combine with the garage opener. If the water heater is in the garage, the garage door controller can carry a leak probe too.