Introduction
Imagine having a daily routine of filling up a 5000-liter farm tank every morning, sounds simple, right? But here’s the catch: you need to make sure the water doesn’t overflow and flood the whole farm. You don’t want to keep guessing how long it will take to fill, and honestly, standing there watching it fill up is boring.
As an electrical and electronic engineering student (and a bit of a lazy and extremely curious one with some free time), I figured, why not automate it? That’s exactly how this small but fun project started. I needed something to alert me when the tank was about to fill, so I could turn off the tap before the floodgates opened. And no, a basic level switch wasn’t on the table. I wanted to do something a little more creative (and let’s be honest, wiring those things can be a hassle).
Requirements/Materials
- Ultrasonic sensor
- Raspberry Pi 4B
- LED indicators (Green, Yellow, Red)
- Buzzer
- LCD Display
- GSM module
- Mobile phone
- Breadboard and jumper wires
How It Works: The Basics
The ultrasonic sensor is at the heart of this setup. It sends out high-frequency sound waves and listens for the echo that bounces back from the water surface. The time taken for the echo to return helps determine the distance using the formula:
Distance = (Speed of Sound × Time) / 2
Why divide by 2? Because the sound wave travels to the water surface and back.
This distance data is captured using a Python script running on the Raspberry Pi. Based on the reading, the Pi controls LEDs, a buzzer, and even sends a text message via the GSM module. The entire system is divided into four notification levels:
- Normal (N)
- Green (G)
- Yellow (Y)
- Red (R)
Each level reflects how close the water is to the tank’s top
Setup and Implementation
To simulate the system, I used a container with a depth of 45cm, represents my real tank when empty – though the tank is 2.1 meters. The ultrasonic sensor was mounted at the top, and as the container filled, the sensor measured the decreasing distance to the water surface.
The Raspberry Pi processed these readings, displayed them on an LCD in real time (every 10 seconds), and determined which notification level to activate based on predefined distance thresholds:
- > 35 cm - Normal (no alerts)
- < 35 cm and ≥ 25 cm - Green LED
- < 25 cm and ≥ 15 cm - Yellow LED
- < 15 cm - Red LED, buzzer, and SMS alert
The script
import RPi.GPIO as GPIO
import time, os
import serial
from signal import signal, SIGTERM, SIGHUP, pause
from rpi_lcd import LCD
GPIO.setwarnings(False)
port = serial.Serial("/dev/ttyS0", baudrate=9600, timeout=1)
port.write(b'AT'+b'\r')
rcv = port.read(10)
print (rcv)
time.sleep(1)
port.write(b'AT+CMGF=1'+b'\r') # Select Message format as Text mode
rcv = port.read(10)
print (rcv)
time.sleep(1)
# Sending a message to a particular Number
port.write(b'AT+CMGS="07XXXXXXXX"'+b'\r')
rcv = port.read(10)
print (rcv)
time.sleep(1)
port.write(b'Please turn off the farm Roto tank pump; flooding is imminent\n<Emergency Response>'+b'\r') # Message
rcv = port.read(10)
print (rcv)
lcd = LCD()
def safe_exit(signum, frame):
exit(1)
#GPIO Mode (BOARD / BCM)
#GPIO.setmode(GPIO.BCM)
GPIO.setmode(GPIO.BOARD)
GPIO.setup(37, GPIO.OUT)
GPIO.setup(35, GPIO.OUT)
GPIO.setup(33, GPIO.OUT)
#set GPIO Pins
TRIG = 16
ECHO = 18
try:
signal(SIGTERM, safe_exit)
signal (SIGHUP, safe_exit)
while True:
print("distance measurement in progress")
GPIO.setup(TRIG, GPIO.OUT)
GPIO.setup(ECHO, GPIO.IN)
GPIO.output(TRIG, 0)
print("Waiting for sensor to settle")
time.sleep(0.2)
GPIO.output(TRIG,1)
time.sleep(0.00001)
GPIO.output(TRIG, 0)
while GPIO.input(ECHO) == 0:
StartTime = time.time()
# save time of arrival
while GPIO.input(ECHO) == 1:
StopTime = time.time()
# time difference between start and arrival
TimeElapsed = StopTime - StartTime
# multiply with the sonic speed (34300 cm/s)
# and divide by 2, because there and back
distance = round((17000*TimeElapsed),2)
print("Distance:", distance, "cm")
lcd.text("DISTANCE:,", 1)
if float(distance) <= 15:
GPIO.output(37, True) #Red light activation
GPIO.output(35, False)
GPIO.output(33, False)
GPIO.output(31, True) #Buzzer activation
lcd.text(str(distance)+ " RED", 2)
port.write(b"\x1A") # Enable to send SMS
for i in range(10):
rcv = port.read(10)
print (rcv)
elif float(distance) > 15 and float(distance) <= 25:
GPIO.output(37, False)
GPIO.output(35, True) #Amber light activation
GPIO.output(33, False)
GPIO.output(31, False)
lcd.text(str(distance) + " AMBER", 2)
elif float(distance) > 25 and float(distance) <= 35:
GPIO.output(37, False)
GPIO.output(35, False)
GPIO.output(33, True) #Green light activation
GPIO.output(31, False)
lcd.text(str(distance)+ " GREEN", 2)
else:
GPIO.output(37, False)
GPIO.output(35, False)
GPIO.output(33, False)
GPIO.output(31, False)
lcd.text(str(distance) + " NORMAL", 2)
time.sleep(5)
except KeyboardInterrupt:
pass
finally:
lcd.clear()
System Behavior Observations
1. Normal Zone (distance > 35 cm)
At this level, the tank is relatively empty. The LCD displays the current distance, but no alert is triggered. All indicators remain off.
2. Green Zone (35 cm > distance ≥ 25 cm)
This indicates the water level has started to rise. The Green LED turns on; this is just a heads-up that things are progressing.
3. Yellow Zone (25 cm > distance ≥ 15 cm)
Now we’re getting close. The Yellow LED turns on, signalling that the water level is nearing the top.
4. Red Zone (distance < 15 cm)
Time to act! At this point, the Red LED, buzzer, and GSM module all activate. I get a loud warning and an SMS alert on my phone. That’s my cue to rush over and shut off the water.
SMS Notification Example
Figure showing SMS alert when tank level reaches critical.
Conclusion
The goal of this project was simple, get notified before the tank overflows. What I ended up with was not only a practical solution but also a fun and rewarding hands-on learning experience. The system could be improved by adding flow rate sensors or integrating it with a mobile app, but for now, it gets the job done. And most importantly, no more early morning sprints to stop a mini flood.