Preview build — page text is a draft awaiting human review. Code badges come from real compiles. The flasher is real but not yet hardware-tested; the Playground is still a preview.
Irrigation Timer: the finished build
ESP32India utility230 V

Irrigation pump timer with RTC (ESP32 + DS3231)

Pump runs at 6 am and 6 pm every day — the DS3231 keeps time through power cuts.

Difficulty
Medium
Build time
2 h
Parts cost
₹1,620 · $19
Verified — core esp32 3.3.12, RTClib 2.1.4, 3 Nov 2026Compile-only

Community draft — report a mistake

Mains voltage (230 V) — can kill. The low-voltage side (board, sensors, display, relay module) is safe to build yourself. The mains side must be wired by a licensed electrician, and tested with the circuit switched off at the MCB.

  • Never switch a motor with a relay module. Motors pull several times their running current at start-up; hobby relay contacts weld or overheat. The relay only drives a contactor’s coil (or your pump starter’s coil input).
  • Contactor rated for motors (AC-3) at or above the load’s nameplate current.
  • Protect and earth: MCB on live, RCCB/ELCB on the circuit, metal bodies earthed. Switch live only — never neutral or earth.
  • Keep the two worlds apart: mains and low-voltage wiring in separate compartments of a closed, non-metallic enclosure; no bare 230 V terminals.
  • Fail safe: the code switches the load off when a sensor stops answering. Still fit a manual override at the starter.

Parts list

PartQtyApprox.Buy
ESP32 DevKit V1 (30-pin)1₹380Buy ESP32 DevKit V1 (30-pin)
DS3231 RTC module + CR2032 cell1₹150Buy DS3231 RTC module + CR2032 cell
1-channel relay module, 5 V coil, 3.3 V-trigger1₹70Buy 1-channel relay module, 5 V coil, 3.3 V-trigger
Contactor rated for the pump (230 V AC coil) — or your starter’s coil input1₹650Buy Contactor rated for the pump (230 V AC coil) — or your starter’s coil input
5 V 1 A adapter1₹120Buy 5 V 1 A adapter
IP65 enclosure1₹250Buy IP65 enclosure
Total₹1,620

Affiliate disclosure: “Buy” links may earn FlashReady a small commission at no extra cost to you. Prices are indicative.

Wiring

ESP32 DevKit V1Only the pins used are shown · 3.3 V logicContactor coil circuit, 230 V (electrician)DS3231 real-time clock (RTC) module1-channel relay module (5 V coil)LA1D26GNDVIND22D213V332K (not connected)SQW (not connected)SCLSDAVCCGNDDC+DC−INCOMNONC (not connected)
Every connection
ESP32 DevKit V1Part · pinWireNotes
D22DS3231 real-time clock (RTC) module · SCLyellow
D21DS3231 real-time clock (RTC) module · SDAblue
3V3DS3231 real-time clock (RTC) module · VCCred
GNDDS3231 real-time clock (RTC) module · GNDblack
D261-channel relay module (5 V coil) · INorangeCOM/NO switch the contactor coil — never the pump itself
VIN1-channel relay module (5 V coil) · DC+red
GND1-channel relay module (5 V coil) · DC−black
Contactor coil circuit, 230 V (electrician) · L1-channel relay module (5 V coil) · COMbrownLive from the MCB to COM — 230 V, wired by an electrician
Contactor coil circuit, 230 V (electrician) · A11-channel relay module (5 V coil) · NObrownNO to the contactor coil A1; coil A2 goes to neutral

Board quirks: The relay module only switches the contactor’s coil. The pump’s current goes through the contactor, which an electrician wires with the right MCB and overload protection. Set the clock once over Serial: <code>SET 2026 10 31 06 00 00</code>. The DS3231’s coin cell keeps it running for years without power. If the RTC loses power, the sketch refuses to run the pump until the time is set again — a clock stuck at the year 2000 would run at the wrong hour. Some cheap DS3231 boards have a charging circuit meant for a rechargeable LIR2032. With a normal CR2032, remove the small diode or resistor next to the cell holder.

Code

irrigation-timer.inoArduino C++Open in PlaygroundOpen in PlaygroundFlash
// Irrigation timer with RTC — ESP32 DevKit V1 + DS3231 + relay module
// DS3231 on I2C D21/D22 (powered from 3V3), relay module IN on D26.
// The relay drives a CONTACTOR coil (or the pump starter's coil input), never the pump.
// Set the clock once: send "SET 2026 10 31 06 00 00" in the Serial Monitor (115200).
#include <Wire.h>
#include <RTClib.h>

constexpr uint8_t RELAY_PIN = 26;
constexpr bool RELAY_ACTIVE_LOW = true;

struct Window {
  uint8_t hour, minute, minutes;  // start time + duration
};
Window schedule[] = {
  {6, 0, 20},   // 06:00 for 20 minutes
  {18, 0, 20},  // 18:00 for 20 minutes
};

RTC_DS3231 rtc;
bool pumpOn = false;

void setPump(bool on) {
  if (on == pumpOn) return;
  pumpOn = on;
  digitalWrite(RELAY_PIN, (on != RELAY_ACTIVE_LOW) ? HIGH : LOW);
  Serial.println(on ? "Pump ON" : "Pump OFF");
}

bool inWindow(const DateTime& now) {
  int nowMin = now.hour() * 60 + now.minute();
  for (const auto& w : schedule) {
    int start = w.hour * 60 + w.minute;
    if (nowMin >= start && nowMin < start + w.minutes) return true;
  }
  return false;
}

void readSerialCommand() {
  if (!Serial.available()) return;
  String cmd = Serial.readStringUntil('\n');
  int y, mo, d, h, mi, s;
  if (sscanf(cmd.c_str(), "SET %d %d %d %d %d %d", &y, &mo, &d, &h, &mi, &s) == 6) {
    rtc.adjust(DateTime(y, mo, d, h, mi, s));
    Serial.println("Clock set");
  }
}

void setup() {
  digitalWrite(RELAY_PIN, RELAY_ACTIVE_LOW ? HIGH : LOW);
  pinMode(RELAY_PIN, OUTPUT);
  Serial.begin(115200);
  Wire.begin(21, 22);
  if (!rtc.begin()) Serial.println("DS3231 not found — check SDA/SCL and power");
  if (rtc.lostPower()) Serial.println("RTC lost power — set the time with SET YYYY MM DD hh mm ss");
}

void loop() {
  readSerialCommand();
  DateTime now = rtc.now();
  // A clock that lost power reads year 2000: never run the pump on a wrong clock.
  bool clockOk = now.year() >= 2025 && !rtc.lostPower();
  setPump(clockOk && inWindow(now));

  static uint8_t lastSecond = 99;
  if (now.second() != lastSecond && now.second() % 10 == 0) {
    Serial.printf("%04d-%02d-%02d %02d:%02d:%02d pump=%s\n", now.year(), now.month(), now.day(), now.hour(), now.minute(), now.second(),
                  pumpOn ? "on" : "off");
  }
  lastSecond = now.second();
  delay(200);
}

Compiled for esp32 on esp32 3.3.12 with RTClib 2.1.4 · 3 Nov 2026

How it works

Many farmers start the borewell pump at the same times every day — early morning and evening. This timer does it for them. An ESP32 checks a DS3231 clock and switches the pump through a relay and contactor for 20 minutes at 06:00 and 18:00.

The DS3231 is a temperature-compensated clock accurate to about a minute a year, with a coin cell that keeps it running through power cuts. When the power comes back, the ESP32 reads the correct time and carries on with the schedule, unlike a plain millis() timer.

The schedule is a small list of start times and durations. Add or change entries in schedule[] to match your crop. Each loop the sketch checks whether the current minute falls inside any window and switches the relay accordingly, so a restart in the middle of a window resumes watering.

The relay module never carries pump current. It switches the coil of a contactor sized for the motor, and the contactor, MCB and earthing are wired by a licensed electrician.

Troubleshooting

"DS3231 not found"

Check SDA is on D21 and SCL on D22, and the module has 3.3 V. Run the I2C scanner — the DS3231 answers at 0x68.

The pump didn’t run at the set time

Open the Serial Monitor: the sketch prints the time every 10 seconds. If the time is wrong, set it again; if it says "lost power", replace the coin cell.

The relay clicks but the pump doesn’t start

Make sure the relay is switching the contactor coil through COM and NO (not NC), and that the contactor’s coil voltage matches its supply. Have the electrician check the starter.

Upgrades

  • Add a soil-moisture sensor and skip a watering when the soil is already wet.
  • Add a float switch so the pump never runs a dry well.
  • Set the schedule from your phone with a small web page on the ESP32.

↑↓ to move · Enter to open