An automatic water tank level controller is one of the most useful home automation projects for Indian households. Every home with an overhead tank faces the same problem — someone has to remember to switch the pump on when the tank is empty and off when it is full. Forget to switch it off, and you waste water and electricity. Forget to switch it on, and you run out of water at the worst possible time. An Arduino-based water tank level controller solves this problem permanently, for under ₹800 in components.
This guide covers everything from sensor selection to complete wiring and code for Indian overhead tank installations.
The Water Tank Problem in Indian Homes
Most Indian homes, whether in cities or towns, rely on overhead water tanks fed by electric water pumps. The typical setup involves:
- A sump (underground tank) that gets filled by municipal water supply or borewell
- A 0.5 HP to 1 HP water pump that pushes water up to the overhead tank
- An overhead tank (500–2000 litres) on the terrace
Problems with manual control:
- Overflow wastage: Running the pump too long wastes 50–100 litres per overflow incident
- Dry running: If the sump is empty and the pump runs dry, it can burn out the motor — a ₹3,000–₹8,000 repair
- Inconvenience: Someone has to climb to the terrace or listen for overflow sounds
- Power cut complications: If power goes and comes back while you are asleep, the pump may run unattended all night
A ₹800 Arduino controller solves all these problems permanently.
How the System Works
- An ultrasonic sensor mounted at the top of the overhead tank measures the distance to the water surface
- Arduino calculates the water level percentage from this distance
- When the level drops below 20%, Arduino turns ON the pump via a relay
- When the level reaches 95%, Arduino turns OFF the pump
- If the sump level is too low (optional second sensor), the pump is kept OFF to prevent dry running
- An LCD display shows the current water level percentage
Components Required
| Component | Price (₹) |
|---|---|
| Arduino Uno / Nano | 250–400 |
| HC-SR04 or AJ-SR04M (waterproof) | 50–200 |
| 1-Channel 5V Relay (30A rated) | 60–100 |
| 16×2 LCD with I2C adapter | 120–180 |
| Buzzer | 15–25 |
| 12V power adapter | 80–120 |
| Wires, enclosure | 50–80 |
| Total | ₹625–₹1,105 |
Wiring Diagram
// Ultrasonic Sensor (HC-SR04)
HC-SR04 VCC → Arduino 5V
HC-SR04 GND → Arduino GND
HC-SR04 TRIG → Arduino Pin 9
HC-SR04 ECHO → Arduino Pin 10
// Relay (for pump control)
Relay VCC → Arduino 5V
Relay GND → Arduino GND
Relay IN → Arduino Pin 7
// Relay output (pump side)
Pump Live Wire → Relay COM
Relay NO → Mains Live (from MCB)
Pump Neutral → Mains Neutral (direct)
// Buzzer
Buzzer (+) → Arduino Pin 6
Buzzer (-) → Arduino GND
// I2C LCD
LCD SDA → Arduino A4
LCD SCL → Arduino A5
LCD VCC → Arduino 5V
LCD GND → Arduino GND
Arduino Code with Hysteresis
Hysteresis is crucial — without it, the pump would rapidly switch on and off when the water level hovers near the threshold. Our code uses a 20% low threshold and 95% high threshold to prevent this:
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
#define TRIG_PIN 9
#define ECHO_PIN 10
#define RELAY_PIN 7
#define BUZZER_PIN 6
// Tank dimensions (adjust for your tank)
#define TANK_HEIGHT 100 // cm - distance from sensor to tank bottom
#define SENSOR_OFFSET 10 // cm - distance from sensor to full water level
#define EMPTY_DIST (TANK_HEIGHT) // Distance when tank is empty
#define FULL_DIST (SENSOR_OFFSET) // Distance when tank is full
// Thresholds
#define LOW_THRESHOLD 20 // Start pump when level drops below 20%
#define HIGH_THRESHOLD 95 // Stop pump when level reaches 95%
bool pumpRunning = false;
unsigned long pumpStartTime = 0;
#define MAX_PUMP_TIME 1800000 // 30 minutes max pump run time (safety)
void setup() {
Serial.begin(9600);
lcd.init();
lcd.backlight();
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
pinMode(RELAY_PIN, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);
digitalWrite(RELAY_PIN, HIGH); // Pump OFF
lcd.setCursor(0, 0);
lcd.print("Water Tank Ctrl");
lcd.setCursor(0, 1);
lcd.print("Initializing...");
delay(2000);
}
float measureDistance() {
// Take 5 readings and average to reduce noise
float total = 0;
int validReadings = 0;
for (int i = 0; i 0) {
float dist = duration * 0.034 / 2.0;
if (dist > 2 && dist < 400) { // Valid range
total += dist;
validReadings++;
}
}
delay(50);
}
if (validReadings == 0) return -1; // Sensor error
return total / validReadings;
}
int calculateLevel(float distance) {
if (distance EMPTY_DIST) return 0;
float level = ((EMPTY_DIST - distance) / (EMPTY_DIST - FULL_DIST)) * 100.0;
return constrain((int)level, 0, 100);
}
void loop() {
float distance = measureDistance();
if (distance < 0) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("SENSOR ERROR!");
lcd.setCursor(0, 1);
lcd.print("Check wiring");
// Safety: turn off pump on sensor error
digitalWrite(RELAY_PIN, HIGH);
pumpRunning = false;
delay(2000);
return;
}
int level = calculateLevel(distance);
// Pump control with hysteresis
if (level = HIGH_THRESHOLD && pumpRunning) {
// Stop pump - tank full
digitalWrite(RELAY_PIN, HIGH);
pumpRunning = false;
// Alert buzzer - 1 long beep
tone(BUZZER_PIN, 2000, 1000);
}
// Safety: max pump run time
if (pumpRunning && (millis() - pumpStartTime > MAX_PUMP_TIME)) {
digitalWrite(RELAY_PIN, HIGH);
pumpRunning = false;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("PUMP TIMEOUT!");
lcd.setCursor(0, 1);
lcd.print("Check supply");
// Alarm
for (int i = 0; i < 5; i++) {
tone(BUZZER_PIN, 3000, 500);
delay(600);
}
delay(60000); // Wait 1 minute before resuming
return;
}
// Update LCD display
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Level: ");
lcd.print(level);
lcd.print("%");
// Draw a simple bar graph
int bars = map(level, 0, 100, 0, 10);
lcd.setCursor(0, 1);
lcd.print("Pump:");
lcd.print(pumpRunning ? "ON " : "OFF");
lcd.print(" ");
for (int i = 0; i < bars; i++) lcd.print((char)255);
Serial.print("Dist: ");
Serial.print(distance);
Serial.print("cm | Level: ");
Serial.print(level);
Serial.print("% | Pump: ");
Serial.println(pumpRunning ? "ON" : "OFF");
delay(2000); // Check every 2 seconds
}
Dry-Run Protection for Pump
Dry running (operating the pump when the sump is empty) is one of the most common causes of pump motor burnout in Indian homes. Add a second ultrasonic sensor or a simple float switch in the sump for protection:
#define SUMP_SENSOR_TRIG 3
#define SUMP_SENSOR_ECHO 4
#define SUMP_MIN_LEVEL 10 // Minimum 10% sump level to run pump
// In loop(), before starting pump:
float sumpDist = measureSumpDistance();
int sumpLevel = calculateSumpLevel(sumpDist);
if (level SUMP_MIN_LEVEL) {
// Safe to start pump
startPump();
} else if (sumpLevel <= SUMP_MIN_LEVEL && pumpRunning) {
// EMERGENCY: sump empty, stop pump immediately
stopPump();
showAlert("SUMP EMPTY!", "Pump stopped");
}
Adding LCD Display and Buzzer Alerts
The code above already includes LCD and buzzer support. Here are the alert conditions:
| Event | LCD Message | Buzzer |
|---|---|---|
| Pump starts | Pump: ON | 2 short beeps |
| Tank full | Level: 95% Pump: OFF | 1 long beep |
| Sensor error | SENSOR ERROR! | Continuous alarm |
| Pump timeout | PUMP TIMEOUT! | 5 alarm beeps |
| Sump empty | SUMP EMPTY! | Continuous alarm |
Frequently Asked Questions
Can the ultrasonic sensor work reliably inside a water tank?
The standard HC-SR04 works well if mounted above the water surface (not in contact with water). For humid environments, use the waterproof AJ-SR04M or JSN-SR04T. Mount the sensor at least 10 cm above the maximum water level to avoid splashing.
What about the long wire run from the terrace to the pump switch?
For distances over 5 metres, use shielded cable for the sensor wires to avoid electrical interference. Alternatively, use an ESP32 version with WiFi — place the sensor unit on the terrace and the pump relay near the switchboard, communicating wirelessly.
Will this work with a submersible pump?
Yes. The relay switches the pump’s 230V AC supply regardless of pump type — whether centrifugal, submersible, or booster. Just ensure the relay is rated for the pump’s starting current (typically 3–5x the running current).
How do I mount the sensor on the tank?
Drill a small hole in the tank lid and mount the sensor pointing downward. Use silicone sealant around the hole to prevent rain water from entering. For concrete tanks, mount a small bracket inside the inspection opening.
Can I add WiFi and check the tank level from my phone?
Yes. Replace the Arduino with an ESP32 and add a web server (similar to the energy monitor article). You can check the water level from your phone and even get notifications when the tank is full or the pump has an issue.
Conclusion
An automatic water tank level controller is perhaps the most practical Arduino project for Indian homes. It eliminates water wastage from overflow, prevents expensive pump burnouts from dry running, and removes the daily chore of manually monitoring the tank. At under ₹1,000 in components, it pays for itself by saving water and extending your pump’s lifespan.
Build yours today with components from Zbotic.in. Browse our ultrasonic sensors, Arduino boards, and relay modules — all available with fast delivery across India.
Add comment