Measuring Water Level in a Tank Using ESPHome and Home Assistant

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 PinESP32 PinNote
VCCVIN or 5VSensor needs 5V
GNDGNDShared ground
TrigGPIO23 (example)Can be any GPIO
EchoGPIO22 (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.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.