An ESP32 reads soil moisture every few seconds, shows it on a small OLED screen, and runs a 5 V pump through a relay when the soil gets too dry. The pump has its own 5 V supply so it never resets the board.
- Board
- ESP32 DevKit V1
- Difficulty
- Beginner
- Build time
- ~2 hours
- Parts cost
- ~₹2,795
Self-watering plant monitor
Electrical6₹2,288
Microcontroller1₹704
Sensor1₹220
Display1₹352
Actuator2₹484
Power1₹528
Mechanical20₹507
3D printed1₹141
Hardware19₹366
How it works
Plants die from forgetting more than from anything else. This monitor checks the soil every few seconds and waters only when it is actually dry, so you can leave for a week without worrying.
A capacitive probe measures moisture without corroding. The ESP32 converts the reading into a percentage, shows it on a small OLED screen and, when the soil drops below 35%, clicks a relay that runs a small submersible pump for four seconds. It then waits ten minutes so the water can soak in before checking again.
The pump runs from its own 5 V adapter. Pumps cause voltage dips when they start, and keeping them off the board's supply stops random resets.
Typical online prices in USD; they vary by supplier and quantity. Shop links search for the exact part number.
Drag to pan, scroll to zoom, hover a wire to trace it.
Pin map
| From | To | Wire | Purpose |
|---|---|---|---|
| 3V3 ESP32 DevKit V1 | VCC Capacitive soil moisture sensor v1.2 | Red | Power |
| GND ESP32 DevKit V1 | GND Capacitive soil moisture sensor v1.2 | Black | Ground |
| GPIO34 ESP32 DevKit V1 | AOUT Capacitive soil moisture sensor v1.2 | Yellow | Moisture reading |
| 3V3 ESP32 DevKit V1 | VCC 0.96" OLED display (SSD1306, I²C) | Red | Power |
| GND ESP32 DevKit V1 | GND 0.96" OLED display (SSD1306, I²C) | Black | Ground |
| GPIO21 ESP32 DevKit V1 | SDA 0.96" OLED display (SSD1306, I²C) | Blue | I²C data |
| GPIO22 ESP32 DevKit V1 | SCL 0.96" OLED display (SSD1306, I²C) | Green | I²C clock |
| VIN ESP32 DevKit V1 | VCC 1-channel 5 V relay module | Red | Power |
| GND ESP32 DevKit V1 | GND 1-channel 5 V relay module | Black | Ground |
| GPIO26 ESP32 DevKit V1 | IN 1-channel 5 V relay module | Orange | Pump on/off |
| 5V 5 V 2 A power adapter with DC jack breakout | COM 1-channel 5 V relay module | Red | Power |
| NO 1-channel 5 V relay module | + 5 V mini submersible pump + 1 m tubing | Red | Power |
| - 5 V mini submersible pump + 1 m tubing | GND 5 V 2 A power adapter with DC jack breakout | Black | Ground |
| GND 5 V 2 A power adapter with DC jack breakout | GND ESP32 DevKit V1 | Black | Common ground |
Tools & assumptions
Tools
- USB data cable (micro-USB)
- Wire stripper
- Small Phillips screwdriver
- Multimeter (recommended)
- 3D printer or a local printing service
Assumptions
- Arduino IDE 2 with the ESP32 board package installed
- A cup of water to test the pump
Prepare
0/1- 1.1
Lay out the parts
Main controllerESP32 DevKit V10.96" OLED display (SSD1306, I²C)SSD1306 0.96in I2C OLED1-channel 5 V relay moduleSRD-05VDC-SL-C relay module5 V mini submersible pump + 1 m tubingJT-DC3L 5V submersible pumpBreadboard jumper wiresMechanical
Wire
0/4- 2.1
Wire the power rails
Main controllerESP32 DevKit V1Capacitive soil moisture sensor v1.2Capacitive Soil Moisture Sensor v1.20.96" OLED display (SSD1306, I²C)SSD1306 0.96in I2C OLED5 V 2 A power adapter with DC jack breakout5V 2A adapter + DC 5.5×2.1 mm jack breakoutBreadboard jumper wiresMechanical - 2.2
Connect the soil sensor and display
Capacitive soil moisture sensor v1.2Capacitive Soil Moisture Sensor v1.20.96" OLED display (SSD1306, I²C)SSD1306 0.96in I2C OLED5 V 2 A power adapter with DC jack breakout5V 2A adapter + DC 5.5×2.1 mm jack breakout - 2.3
Connect the relay module
Main controllerESP32 DevKit V11-channel 5 V relay moduleSRD-05VDC-SL-C relay module - 2.4
Wire the pump through the relay
Main controllerESP32 DevKit V11-channel 5 V relay moduleSRD-05VDC-SL-C relay module5 V mini submersible pump + 1 m tubingJT-DC3L 5V submersible pump5 V 2 A power adapter with DC jack breakout5V 2A adapter + DC 5.5×2.1 mm jack breakout
Test
0/1- 3.1
Upload the code and calibrate
Main controllerESP32 DevKit V1
Assemble
0/1- 4.1
Fit everything in the case
Small Phillips screwdriver3D printer or a local printing service5 V mini submersible pump + 1 m tubingJT-DC3L 5V submersible pumpM3 × 6 mm brass standoffsMechanicalPG7 cable glandMechanicalBreadboard jumper wiresMechanical
Install first: Adafruit SSD1306, Adafruit GFX Library
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// ---- Pins ----
const int SOIL_PIN = 34; // analog input
const int RELAY_PIN = 26; // relay IN
// ---- Calibration (update after step 6) ----
const int DRY_READING = 3200; // sensor in dry air
const int WET_READING = 1300; // sensor in water
const int WATER_BELOW_PERCENT = 35;
const unsigned long PUMP_SECONDS = 4;
const unsigned long REST_MINUTES = 10; // wait before watering again
Adafruit_SSD1306 display(128, 64, &Wire, -1);
unsigned long lastWatered = 0;
int moisturePercent() {
long total = 0;
for (int i = 0; i < 10; i++) { total += analogRead(SOIL_PIN); delay(5); }
int raw = total / 10;
int pct = map(raw, DRY_READING, WET_READING, 0, 100);
return constrain(pct, 0, 100);
}
void show(int pct, const char* status) {
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
display.setTextSize(1);
display.setCursor(0, 0);
display.print("Soil moisture");
display.setTextSize(3);
display.setCursor(0, 18);
display.print(pct);
display.print("%");
display.setTextSize(1);
display.setCursor(0, 54);
display.print(status);
display.display();
}
void setup() {
Serial.begin(115200);
pinMode(RELAY_PIN, OUTPUT);
digitalWrite(RELAY_PIN, LOW);
Wire.begin(21, 22);
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println("OLED not found - check SDA/SCL wiring");
}
}
void loop() {
int pct = moisturePercent();
Serial.printf("Moisture: %d%%\n", pct);
bool rested = millis() - lastWatered > REST_MINUTES * 60UL * 1000UL || lastWatered == 0;
if (pct < WATER_BELOW_PERCENT && rested) {
show(pct, "Watering...");
digitalWrite(RELAY_PIN, HIGH);
delay(PUMP_SECONDS * 1000);
digitalWrite(RELAY_PIN, LOW);
lastWatered = millis();
} else {
show(pct, pct < WATER_BELOW_PERCENT ? "Dry - resting pump" : "All good");
}
delay(3000);
}
After flashing, open the serial monitor to see live readings from your board.
- Every wire lands on a real pin14 connections checked against the ESP32 DevKit V1 pinout.
- Pins match what each part needsPWM, analog, I²C and input-only rules all hold.
- No pin is double-bookedEach signal pin drives one part; shared buses are wired correctly.
- Supply voltages matchEvery part is on a rail it is rated for.
- Signal levels are compatibleAll parts work with 3.3 V logic.
- Everything shares a common groundAll parts with a GND pin are connected.
- Current draw is within limits~95 mA from the board, 19% of what the ESP32 DevKit V1 can supply.
- Everything fits in the enclosure4 parts placed inside a 110 × 80 × 45 mm case with no overlaps.
Before you buy parts in bulk or sell what you build, have a qualified engineer review the design.