A sprinkler zone controller using ESP32 enables multi-zone irrigation management with individual timing, flow control, and remote operation for farms of any size. Manual irrigation scheduling wastes water and labour, while a smart multi-zone controller can reduce water usage by 40-60% through precision timing and soil moisture feedback. This guide covers building a complete 8-zone sprinkler controller with ESP32, solenoid valves, and a web-based dashboard.
Table of Contents
- Why Multi-Zone Irrigation Matters
- System Design Overview
- Components Required
- Circuit and Wiring
- ESP32 Zone Controller Code
- Web Dashboard
- Indian Farm Applications
- Frequently Asked Questions
Why Multi-Zone Irrigation Matters
Different crop areas have different water requirements based on soil type, sun exposure, crop variety, and growth stage. A single-zone irrigation system either over-waters shaded areas or under-waters exposed areas. With zone control:
- Sandy soil zones receive more frequent, shorter watering cycles
- Clay soil zones receive longer intervals to allow drainage
- Seedling beds receive gentle misting while mature plants get full flow
- High-value crops (capsicum, cucumber) get priority when water is scarce
- Rain sensors can pause specific zones while others continue (different canopy coverage)
System Design Overview
The ESP32 controls up to 8 zones via relay-driven solenoid valves. A single main pump supplies the header pipe, and each zone’s solenoid valve opens/closes to direct water flow. Soil moisture sensors in each zone provide feedback for data-driven scheduling.
Components Required
Products from Zbotic
- Capacitive Soil Moisture Sensor v1.2 — one per zone for feedback
- 5V/12V Relay Control Module — for solenoid valve control
- 12V DC Mini Submersible Water Pump — for small area systems
- Raindrops Detection Sensor Module — auto-pause irrigation during rain
Full parts list:
- ESP32 WROOM-32 development board
- 8-channel relay module (5V, active LOW)
- 8x 12V DC solenoid valves (normally closed, 3/4 inch)
- 8x Capacitive soil moisture sensors
- 1x Rain detection sensor module
- 12V 5A power supply (for solenoid valves)
- DS3231 RTC module (for scheduled watering)
- Waterproof project enclosure (IP65)
- DIN rail terminal blocks for wiring
Circuit and Wiring
Relay connections:
- Relay IN1-IN8 -> ESP32 GPIO pins 26, 27, 14, 12, 13, 15, 2, 4
- Relay COM -> 12V+, Relay NO -> solenoid valve+ (each valve)
- Solenoid valve- -> 12V power supply negative (common ground)
- Soil sensors AOUT -> ESP32 ADC1 pins: GPIO32, 33, 34, 35, 36, 39 (and I2C MUX for more)
- Rain sensor AOUT -> GPIO34 (or digital DOUT -> any GPIO)
- DS3231 SDA -> GPIO21, SCL -> GPIO22
Use flyback diodes (1N4007) across solenoid coils to protect relay contacts. Run solenoid wiring in separate conduit from data/signal wiring to avoid electrical interference.
ESP32 Zone Controller Code
#include <WiFi.h>
#include <WebServer.h>
#include <Wire.h>
#include <RTClib.h>
const char* ssid = "FarmNet";
const char* password = "farmpassword";
WebServer server(80);
RTC_DS3231 rtc;
// Zone relay pins
const int zonePins[8] = {26, 27, 14, 12, 13, 15, 2, 4};
// Soil moisture pins
const int soilPins[6] = {32, 33, 34, 35, 36, 39};
// Zone configuration
struct Zone {
String name;
int durationMin; // Minutes to run
int startHour; // Hour to start (24h)
int startMin; // Minute to start
bool active; // Currently running
bool enabled; // Zone enabled
int soilTarget; // Target soil moisture %
};
Zone zones[8] = {
{"Tomato Bed 1", 20, 6, 0, false, true, 60},
{"Tomato Bed 2", 20, 6, 25, false, true, 60},
{"Capsicum Row", 15, 6, 50, false, true, 55},
{"Seedling Nursery", 5, 7, 0, false, true, 70},
{"Cucumber Trellis", 25, 6, 0, false, true, 65},
{"Beans Row", 15, 17, 0, false, true, 50},
{"Onion Bed", 10, 6, 0, false, true, 45},
{"Fruit Trees", 30, 5, 30, false, true, 40}
};
bool rainDetected = false;
unsigned long zoneEndTimes[8] = {0};
void allZonesOff() {
for (int i = 0; i < 8; i++) {
digitalWrite(zonePins[i], HIGH); // Relay off
zones[i].active = false;
}
}
void activateZone(int zone, int durationMin) {
if (rainDetected) { Serial.println("Rain detected - skipping zone"); return; }
zones[zone].active = true;
digitalWrite(zonePins[zone], LOW); // Relay on
zoneEndTimes[zone] = millis() + (durationMin * 60000UL);
Serial.println("Zone " + String(zone+1) + " ON for " + String(durationMin) + " min");
}
int readSoilPct(int pinIndex) {
if (pinIndex >= 6) return 50; // No sensor for zones 7-8
int raw = analogRead(soilPins[pinIndex]);
return map(raw, 4095, 1500, 0, 100);
}
String buildHTML() {
DateTime now = rtc.now();
String html = "<!DOCTYPE html><html><head><title>Irrigation Controller</title>";
html += "<meta name='viewport' content='width=device-width,initial-scale=1'>";
html += "<style>body{font-family:sans-serif;max-width:800px;margin:0 auto;padding:16px}";
html += ".zone{border:1px solid #ddd;border-radius:8px;padding:12px;margin:8px 0}";
html += ".active{background:#e8f5e9} button{padding:8px 16px;cursor:pointer}</style></head><body>";
html += "<h1>Farm Irrigation Controller</h1>";
html += "<p>Time: " + String(now.hour()) + ":" + String(now.minute(), DEC) + "</p>";
html += rainDetected ? "<p style='color:red'>Rain detected - irrigation paused</p>" : "";
for (int i = 0; i < 8; i++) {
html += "<div class='zone" + String(zones[i].active ? " active" : "") + "'>";
html += "<b>" + zones[i].name + "</b> | Soil: " + String(readSoilPct(i)) + "%";
html += " | Status: " + String(zones[i].active ? "RUNNING" : "Idle");
html += " <a href='/on?z=" + String(i) + "'><button>Run 5min</button></a>";
html += " <a href='/off?z=" + String(i) + "'><button>Stop</button></a></div>";
}
html += "<a href='/alloff'><button style='background:red;color:white'>ALL ZONES OFF</button></a>";
html += "</body></html>";
return html;
}
void setup() {
Serial.begin(115200);
for (int i = 0; i < 8; i++) {
pinMode(zonePins[i], OUTPUT);
digitalWrite(zonePins[i], HIGH);
}
Wire.begin(21, 22);
rtc.begin();
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
Serial.println("nIP: " + WiFi.localIP().toString());
server.on("/", []() { server.send(200, "text/html", buildHTML()); });
server.on("/on", []() {
int z = server.arg("z").toInt();
if (z >= 0 && z < 8) activateZone(z, 5);
server.sendHeader("Location", "/"); server.send(302);
});
server.on("/off", []() {
int z = server.arg("z").toInt();
if (z >= 0 && z < 8) { digitalWrite(zonePins[z], HIGH); zones[z].active = false; }
server.sendHeader("Location", "/"); server.send(302);
});
server.on("/alloff", []() { allZonesOff(); server.sendHeader("Location", "/"); server.send(302); });
server.begin();
}
void loop() {
server.handleClient();
DateTime now = rtc.now();
rainDetected = (analogRead(34) < 1000);
// Check zone end times
for (int i = 0; i < 8; i++) {
if (zones[i].active && millis() > zoneEndTimes[i]) {
digitalWrite(zonePins[i], HIGH);
zones[i].active = false;
Serial.println("Zone " + String(i+1) + " OFF (timer)");
}
}
// Scheduled activation (check every minute)
static int lastCheckMin = -1;
if (now.minute() != lastCheckMin) {
lastCheckMin = now.minute();
for (int i = 0; i < 8; i++) {
if (zones[i].enabled && now.hour() == zones[i].startHour
&& now.minute() == zones[i].startMin) {
int soilPct = readSoilPct(i);
if (soilPct < zones[i].soilTarget) {
activateZone(i, zones[i].durationMin);
} else {
Serial.println("Zone " + String(i+1) + " skip - soil OK: " + String(soilPct) + "%");
}
}
}
}
delay(100);
}
Web Dashboard
The ESP32 hosts a web interface accessible from any device on the farm WiFi network. Features:
- Live soil moisture reading for each zone
- Manual run (5 minutes) and stop buttons for each zone
- Emergency all-zones-off button
- Rain detection status indicator
- Current RTC time display
For remote access from outside the farm, use ngrok or a VPN, or integrate with Blynk IoT platform for mobile app control.
Indian Farm Applications
- Vegetable farms (Maharashtra, Karnataka): 6-8 zone controllers for polyhouse rows with different crops at different growth stages
- Horticulture (Himachal, J&K): Apple orchard zone management for petal fall, fruit set, and colour development stages
- Onion farms (Nasik): Critical bulbing stage irrigation control — over-watering during bulbing causes splitting
- Floriculture (Pune, Bengaluru): Rose and chrysanthemum zones with precise moisture targets
Frequently Asked Questions
How many zones can a single ESP32 control?
Directly, 8-10 zones via GPIO pins. With an I2C port expander (PCF8574 provides 8 more GPIOs), you can reach 16-20 zones. For commercial systems above 20 zones, use a dedicated industrial irrigation controller with Modbus interface.
Can the system run without WiFi in the field?
Yes. The RTC module maintains the schedule without internet. WiFi is only needed for the web dashboard and remote control. The system will continue to run scheduled irrigation based on soil moisture thresholds even if WiFi is unavailable.
What solenoid valve size do I need?
For drip irrigation laterals, 3/4 inch (20mm) solenoid valves at 12V/24V DC are standard. Ensure the valve is “normally closed” (NC) type — this means irrigation stops automatically on power failure, preventing waterlogging.
Add comment