Project: a smart plant watering system
In short: This project reads soil moisture with a capacitive probe and runs a small pump when the soil is dry. Decisions are made locally on the ESP32, with strict limits on pump run time so a fault cannot flood the room. It teaches calibration, actuator control and why safety limits belong in the device itself.
What you will build and what you need
You will build a controller that waters one or two pots. It measures soil moisture every ten minutes, runs a pump for a few seconds if the soil is too dry, and publishes the moisture level and pump activity over MQTT. It keeps working even if Wi-Fi is down, because the decision happens on the device.
| Part | Notes |
|---|---|
| ESP32 board | Use an ADC1 pin (such as GPIO 34), as ADC2 pins clash with Wi-Fi |
| Capacitive soil moisture sensor | Avoid resistive probes, which corrode quickly |
| Small 5 V submersible pump and tubing | Sits in a water reservoir |
| Logic-level N-channel MOSFET module | Or a relay module; switches the pump from a GPIO |
| Flyback diode | Across the pump motor to absorb voltage spikes |
| Separate 5 V supply | Shares ground with the ESP32; the pump draws more than a GPIO can |
| Optional float switch | Detects an empty reservoir |
Design
Keep all electronics above and away from the water, and mount the board in a box with cable entry from below so drips cannot run into it. Use only low-voltage parts; never build this with a mains-powered pump unless you are qualified. The GPIO drives the MOSFET gate, the MOSFET switches the pump's negative lead, and the diode sits across the pump terminals.
Build and calibrate
- Connect the moisture sensor to 3.3 V, ground and GPIO 34. Print raw readings in dry air and in a glass of water.
- Push the probe into dry soil and note the value (
DRY), then water thoroughly and note it again (WET). Capacitive probes read higher when drier. - Wire the pump through the MOSFET and test it for one second from the REPL.
- Upload the code, choose a threshold suitable for your plant, and watch it for a few days before trusting it.
import time
from machine import ADC, Pin
soil = ADC(Pin(34)); soil.atten(ADC.ATTN_11DB)
pump = Pin(26, Pin.OUT, value=0) # pump off at boot
DRY, WET = 2600, 1450 # from your calibration
THRESHOLD = 35 # percent
RUN_S = 5 # seconds per watering
MAX_PER_DAY = 6 # hard safety limit
MIN_GAP_S = 3600 # wait for water to soak in
runs_today, last_run, day_start = 0, 0, time.time()
def moisture_pct():
raw = sum(soil.read() for _ in range(16)) // 16
pct = (DRY - raw) * 100 // (DRY - WET)
return max(0, min(100, pct))
def water():
pump.value(1)
try:
time.sleep(RUN_S)
finally:
pump.value(0) # always switch off, even on error
while True:
now = time.time()
if now - day_start > 86400:
runs_today, day_start = 0, now
m = moisture_pct()
if m < THRESHOLD and runs_today < MAX_PER_DAY and now - last_run > MIN_GAP_S:
water()
runs_today, last_run = runs_today + 1, now
# publish m and runs_today over MQTT here (see the temperature monitor project)
time.sleep(600)
Safety and security checklist
- Fail safe: pump off at boot, off in a
finallyblock, and a hard daily limit in firmware. - Remote commands are requests: if you add an MQTT "water now" command, the device must still apply its own limits.
- Authenticate commands: only your controller account may publish to the command topic; sensors and dashboards are read-only.
- Detect faults: alert if moisture does not rise after watering (empty reservoir, blocked tube) or if readings jump to 0 or 100 per cent (sensor fault).
- Electrical safety: low voltage only, drip loops on cables and a fuse on the pump supply.
- Usual device hygiene: TLS, unique credentials, IoT VLAN, no debug services left on.
Tip: this project shows an important IoT principle in miniature. Any actuator that can cause physical harm must enforce its safety limits locally, so that a network attacker, a software bug or a stuck message cannot drive it beyond safe bounds.
Practice
Why use an ADC1 pin on the ESP32 for the moisture sensor?
Why is the pump switched through a MOSFET or relay rather than directly from a GPIO pin?
What stops an attacker who gains MQTT access from flooding the room?
Key takeaways
- Capacitive probes last longer than resistive ones; calibrate dry and wet values.
- Drive the pump through a MOSFET or relay with a flyback diode and separate supply.
- Make watering decisions locally so the system works without Wi-Fi.
- Enforce run-time and daily limits in firmware, whatever commands arrive.
- Keep electronics above the water and use low voltage only.
Original content written by Mohamed Fayas for FM TecHub. © 2026 FM TecHub. You're welcome to share a link to this page; please don't copy the text elsewhere without permission.