Parts list
| Part | Qty | Approx. | Buy |
|---|---|---|---|
| ESP32 DevKit V1 (30-pin) | 1 | ₹380 | Buy ESP32 DevKit V1 (30-pin) |
| Capacitive soil moisture sensor v1.2 | 1 | ₹80 | Buy Capacitive soil moisture sensor v1.2 |
| 1-channel relay module, 5 V coil, 3.3 V-trigger (active-LOW) | 1 | ₹70 | Buy 1-channel relay module, 5 V coil, 3.3 V-trigger (active-LOW) |
| 5 V submersible mini pump + 1 m silicone tube | 1 | ₹150 | Buy 5 V submersible mini pump + 1 m silicone tube |
| 5 V 2 A adapter for the pump | 1 | ₹150 | Buy 5 V 2 A adapter for the pump |
| Jumper wires | 1 | ₹30 | Buy Jumper wires |
| Total | ₹860 |
Affiliate disclosure: “Buy” links may earn FlashReady a small commission at no extra cost to you. Prices are indicative.
Wiring
| ESP32 DevKit V1 | Part · pin | Wire | Notes |
|---|---|---|---|
| — | 1-channel relay module (5 V coil) · NO | — | To Pump + (pump − to the adapter’s GND) (not drawn) |
| 3V3 | Capacitive soil moisture sensor v1.2 · VCC | red | 3.3 V keeps AOUT inside the ESP32’s ADC range |
| GND | Capacitive soil moisture sensor v1.2 · GND | black | |
| D34 | Capacitive soil moisture sensor v1.2 · AOUT | purple | ADC1 — works with Wi-Fi on |
| VIN | 1-channel relay module (5 V coil) · DC+ | red | |
| GND | 1-channel relay module (5 V coil) · DC− | black | |
| D26 | 1-channel relay module (5 V coil) · IN | green | Active-LOW |
| 5 V 2 A pump adapter · +5V | 1-channel relay module (5 V coil) · COM | red | Relay NO → pump +; pump − → the adapter’s GND. Low voltage only |
Board quirks: Calibrate <code>RAW_DRY</code> and <code>RAW_WET</code> for your sensor: print the raw value in air and in water. The relay switches the pump’s own 5 V supply — low voltage only. Don’t run the pump from the ESP32’s pins.
Code
// Plant watering system — ESP32 DevKit V1 + capacitive soil sensor + relay module + 5 V DC pump.
// Waters in short bursts when the soil is dry, then waits for the water to soak in.
// Soil AOUT → D34 (ADC1, works with Wi-Fi on). Relay IN → D26 (active-LOW). The relay switches the
// pump's own 5 V supply — low voltage only, never mains.
constexpr uint8_t SOIL_PIN = 34;
constexpr uint8_t RELAY_PIN = 26;
constexpr bool RELAY_ACTIVE_LOW = true;
// Calibrate: read the raw value with the probe in dry air and in a glass of water.
constexpr int RAW_DRY = 3000;
constexpr int RAW_WET = 1300;
constexpr int WATER_BELOW_PERCENT = 35;
constexpr unsigned long PUMP_MS = 5000; // one watering burst
constexpr unsigned long SOAK_MS = 60UL * 1000; // let it soak before measuring again
constexpr uint8_t MAX_BURSTS_PER_HOUR = 6; // safety: a broken sensor can't flood the pot
unsigned long hourStart = 0;
uint8_t burstsThisHour = 0;
void setPump(bool on) {
digitalWrite(RELAY_PIN, (on != RELAY_ACTIVE_LOW) ? HIGH : LOW);
}
int moisturePercent() {
long sum = 0;
for (int i = 0; i < 16; i++) {
sum += analogRead(SOIL_PIN);
delay(5);
}
int raw = sum / 16;
return constrain(map(raw, RAW_DRY, RAW_WET, 0, 100), 0, 100);
}
void setup() {
digitalWrite(RELAY_PIN, HIGH); // pump off before the pin becomes an output
pinMode(RELAY_PIN, OUTPUT);
setPump(false);
analogReadResolution(12);
Serial.begin(115200);
}
void loop() {
if (millis() - hourStart > 3600UL * 1000) {
hourStart = millis();
burstsThisHour = 0;
}
int moisture = moisturePercent();
Serial.printf("Soil moisture: %d%%\n", moisture);
if (moisture < WATER_BELOW_PERCENT && burstsThisHour < MAX_BURSTS_PER_HOUR) {
Serial.println("Dry — watering");
setPump(true);
delay(PUMP_MS);
setPump(false);
burstsThisHour++;
delay(SOAK_MS);
} else {
if (burstsThisHour >= MAX_BURSTS_PER_HOUR) Serial.println("Burst limit reached — check the sensor and tank");
delay(10000);
}
}// Plant watering system — ESP32 DevKit V1 + capacitive soil sensor + relay module + 5 V DC pump.
// Waters in short bursts when the soil is dry, then waits for the water to soak in.
// Soil AOUT → D34 (ADC1, works with Wi-Fi on). Relay IN → D26 (active-LOW). The relay switches the
// pump's own 5 V supply — low voltage only, never mains.
constexpr uint8_t SOIL_PIN = 34;
constexpr uint8_t RELAY_PIN = 26;
constexpr bool RELAY_ACTIVE_LOW = true;
// Calibrate: read the raw value with the probe in dry air and in a glass of water.
constexpr int RAW_DRY = 3000;
constexpr int RAW_WET = 1300;
constexpr int WATER_BELOW_PERCENT = 35;
constexpr unsigned long PUMP_MS = 5000; // one watering burst
constexpr unsigned long SOAK_MS = 60UL * 1000; // let it soak before measuring again
constexpr uint8_t MAX_BURSTS_PER_HOUR = 6; // safety: a broken sensor can't flood the pot
unsigned long hourStart = 0;
uint8_t burstsThisHour = 0;
void setPump(bool on) {
digitalWrite(RELAY_PIN, (on != RELAY_ACTIVE_LOW) ? HIGH : LOW);
}
int moisturePercent() {
long sum = 0;
for (int i = 0; i < 16; i++) {
sum += analogRead(SOIL_PIN);
delay(5);
}
int raw = sum / 16;
return constrain(map(raw, RAW_DRY, RAW_WET, 0, 100), 0, 100);
}
void setup() {
digitalWrite(RELAY_PIN, HIGH); // pump off before the pin becomes an output
pinMode(RELAY_PIN, OUTPUT);
setPump(false);
analogReadResolution(12);
Serial.begin(115200);
}
void loop() {
if (millis() - hourStart > 3600UL * 1000) {
hourStart = millis();
burstsThisHour = 0;
}
int moisture = moisturePercent();
Serial.printf("Soil moisture: %d%%\n", moisture);
if (moisture < WATER_BELOW_PERCENT && burstsThisHour < MAX_BURSTS_PER_HOUR) {
Serial.println("Dry — watering");
setPump(true);
delay(PUMP_MS);
setPump(false);
burstsThisHour++;
delay(SOAK_MS);
} else {
if (burstsThisHour >= MAX_BURSTS_PER_HOUR) Serial.println("Burst limit reached — check the sensor and tank");
delay(10000);
}
}Compiled for esp32 on esp32 3.3.12 · 3 Nov 2026
How it works
A capacitive soil sensor measures how well the soil stores charge, which rises with water content. Unlike the cheap two-prong resistive probes, it has no exposed metal to corrode, so it lasts for months in a pot.
The ESP32 reads the sensor on GPIO34 (an ADC1 pin, so it still works when you add Wi-Fi later), averages 16 readings and maps them onto 0–100 % using two calibration numbers. Below 35 % it runs the pump for five seconds, then waits a minute for the water to soak in before measuring again — otherwise it would keep pumping while the water was still on its way down.
A burst limit caps watering at six bursts an hour. If the sensor falls out of the pot or breaks, the worst case is a little extra water rather than a flooded balcony.
The pump runs on its own 5 V adapter through the relay’s COM and NO contacts. It’s all low voltage — no mains anywhere in this build.
Troubleshooting
Moisture jumps around
Push the probe in up to its line and keep the electronics above the soil — water on the top of the board gives wild readings.
The pump runs but no water comes out
Mini pumps can’t self-prime: it must sit under water in the tank. Check for air in the tube.
It waters too much
Raise SOAK_MS so water has time to spread before the next measurement, or lower WATER_BELOW_PERCENT.
Upgrades
- Add a float switch so the pump never runs a dry tank.
- Send a phone notification when the tank needs refilling.
- Water several pots with a second sensor and pump.



