Do you need to keep track of how much water is in your tank? In this guide, I’ll walk you through how I built a simple water level sensor using:
- 🧠 ESP32
- 📏 AJ-SR04M waterproof ultrasonic sensor
- 💡 ESPHome
- 🏠 Home Assistant
With this setup, I can now see the tank level as a percentage and in liters, and even get a notification when the water is low.
🧩 Hardware Used
- ESP32 Dev Board
- AJ-SR04M waterproof ultrasonic sensor (4-pin version: VCC, GND, Trig, Echo)
- A couple of resistors (1.8kΩ and 3.3kΩ for a voltage divider)
- Dupont cables and a power source (USB or 5V supply)
⚡ Wiring the AJ-SR04M to the ESP32
AJ-SR04M Pin | ESP32 Pin | Note |
---|---|---|
VCC | VIN or 5V | Sensor needs 5V |
GND | GND | Shared ground |
Trig | GPIO23 (example) | Can be any GPIO |
Echo | GPIO22 (example) | Needs voltage divider to 3.3V |
Since the Echo pin outputs 5V, you need to use a voltage divider to drop it to ~3.3V to avoid damaging the ESP32.
Voltage divider circuit:
- Echo → 1.8kΩ → ESP32 GPIO22
- Same point → 3.3kΩ → GND
🧠 ESPHome Configuration
Here’s the YAML I used in ESPHome:
esphome:
name: water_level_sensor
platform: ESP32
board: esp32dev
wifi:
ssid: "your_wifi"
password: "your_password"
logger:
api:
ota:
esp32_ble_tracker:
bluetooth_proxy:
active: true
sensor:
- platform: ultrasonic
trigger_pin: GPIO23
echo_pin: GPIO22
name: "Water Tank Distance"
id: water_tank_distance
update_interval: 60s
timeout: 4.0m
unit_of_measurement: "m"
accuracy_decimals: 2
This publishes the distance from the sensor to the water surface to Home Assistant.
📊 Creating Calculated Sensors in Home Assistant
My tank is 38 cm deep and holds 30 liters. Based on the raw distance, I created two template sensors in Home Assistant: percentage full and liters of water remaining.
Add this to configuration.yaml
or create helpers via the UI:
template:
- sensor:
- name: "Water Level Percent"
unit_of_measurement: "%"
state: >
{% set depth = 0.38 %}
{% set distance = states('sensor.water_level_sensor_water_tank_distance') | float(0) %}
{% set percent = ((depth - distance) / depth * 100) %}
{{ [percent | round(0), 0] | max }}
- name: "Water Volume Liters"
unit_of_measurement: "L"
state: >
{% set depth = 0.38 %}
{% set volume = 30 %}
{% set distance = states('sensor.water_level_sensor_water_tank_distance') | float(0) %}
{% set level = ((depth - distance) / depth) %}
{% set liters = level * volume %}
{{ [liters | round(1), 0] | max }}
🔔 Optional: Notification When Water Is Low
Set up an automation to notify you if the water drops below 5 liters:
alias: "Notify: Low Water Level"
trigger:
- platform: numeric_state
entity_id: sensor.water_volume_liters
below: 5
action:
- service: notify.mobile_app_yourdevice
data:
message: "Warning: water tank is below 5L!"
📱 Dashboard Display
Add a simple gauge to your Lovelace dashboard:
type: gauge
entity: sensor.water_level_percent
min: 0
max: 100
severity:
green: 50
yellow: 20
red: 10
🧼 Results
With this setup:
- I can monitor the water level in real-time.
- I get alerts before the tank runs dry.
This is a small but practical DIY project that’s perfect for rainwater tanks, toilet water tanks, livestock waterers, or just keeping an eye on that water butt in the garden.