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.
Some of the links in this article are "affiliate links", a link with a special tracking code. This means if you click on an affiliate link and purchase the item, we will receive an affiliate commission. The price of the item is the same whether it is an affiliate link or not. Regardless, we only recommend products or services we believe will add value to our readers. By using the affiliate links, you are helping support our Website, and we genuinely appreciate your support.