A houseplant is the lowest-stakes IoT project you can build and also the one with the most direct feedback: the system either keeps the plant alive or it does not. We have built variations of this three times now, and each iteration has taught us a specific lesson about what fails in the field — corroded sensors, dry pumps, overwatered roots, algae growing in the reservoir. This article is the version we would build today, with the lessons baked in.
What we are building
soil moisture
sensor] -->|analog| MCU[[ESP32]] MCU -->|GPIO HIGH
drives gate| MOSFET[N-channel
MOSFET] Power[5V supply] --> MOSFET MOSFET --> Pump[5V submersible
pump] Pump -->|tubing| Plant[(Plant pot)] Reservoir[(Water reservoir)] --> Pump MCU -->|WiFi| Cloud[MQTT broker
or webhook] Cloud --> Phone[Alerts on
phone]
System block diagram: ESP32 reads moisture, switches a MOSFET to drive the pump, and reports state over WiFi.
Bill of materials
- ESP32 DevKit (any variant) — $8
- Capacitive soil moisture sensor v1.2 — $3 (do not buy the resistive kind, explained below)
- 5V DC submersible mini pump (JT-100 or similar, 200–400 L/h) — $3
- N-channel logic-level MOSFET (IRLB3034, AO3400, or a small relay module) — $2
- Silicone tubing, 5 mm ID — $2 for a meter
- 5V 2A power supply (phone charger works) — $5
- Any container for the reservoir — free
Around $23 total. A resistive soil sensor is $1 cheaper but corrodes visibly within a week; skip it.
Wiring
Soil sensor ESP32
----------- -----
VCC --> 3.3V
GND --> GND
AOUT --> GPIO 34 (ADC input)
MOSFET
------
Gate --> GPIO 25 (through 220 ohm resistor)
Gate --> GND (through 10 kohm pull-down)
Source --> GND
Drain --> Pump -
Pump + --> 5V supply +
5V supply GND --> ESP32 GND (common ground)Two non-obvious details. First, the 10 kOhm pull-down on the MOSFET gate is essential — without it, the pump can flicker on during ESP32 boot or reset because the GPIO pin floats before it is configured. Second, the pump's ground must share ground with the ESP32; a common mistake is to run the pump from a separate supply without tying grounds together, which gives the MOSFET no reference.
Calibration
The soil sensor returns a raw ADC value that depends on the specific sensor, the humidity of the air, and where in the pot you pushed it. Calibrate before writing the threshold logic.
- Power up the sensor with the probe in dry air. Record the ADC value — this is your dry baseline, typically around 3000 on an ESP32's 12-bit ADC.
- Submerge the probe (up to the warning line, not past it) in a glass of water. Record this value — your wet baseline, typically around 1300.
- Your threshold is roughly halfway between, around 2200 for "time to water". Soil that is still moist reads around 1500–1800.
Write these numbers into the firmware as named constants. Every sensor is slightly different.
The state machine
AND daily limit not hit CheckMoisture --> Alert: soil dry AND
daily limit hit Watering --> Cooldown: pump runtime
limit reached Cooldown --> CheckMoisture: 5 min wait
(let water soak in) Alert --> Idle: manual reset
or next day
The state machine. Every safety rail lives as an explicit transition, not an if statement buried elsewhere.
The safety rails matter. Without them, a broken sensor returning "dry" indefinitely will run the pump until it damages itself, the plant, or your floor. With them, even pathological inputs produce bounded behaviour.
The firmware
Roughly 100 lines. Every behaviour is explicit; each safety limit is one constant to change.
Failure modes worth knowing
- Pump runs dry. Submersible pumps rely on water to cool the motor. Running dry can melt the impeller within minutes. Mitigate with a float switch at the bottom of the reservoir that disables the pump circuit when water is low, or cap total daily runtime.
- Sensor stays dry-reading forever. A disconnected probe reads around 4095 on the ADC — above the DRY threshold. Without the
MAX_WATERINGS_PER_DAYguard, the pump would run continuously until the reservoir drained. Always cap. - Overwatering. More plants are killed by overwatering than underwatering. If the cooldown is too short, the system sees the surface still looking dry and waters again before moisture reaches the probe. Five minutes is a safe lower bound; longer is safer.
- Algae in the reservoir. Still water plus light equals green sludge in a week. Keep the reservoir covered, and add a drop of 3% hydrogen peroxide per litre once a week — harmless to plants, kills algae.
- Capacitive sensor still corrodes, eventually. The electronics are sealed but the exposed gold pads on the probe can oxidise after six to twelve months in humid soil. Plan to replace probes annually.
Frequently Asked Questions
Can I use one ESP32 for multiple plants?
Yes. An ESP32 has multiple ADC channels and plenty of GPIO. For each plant, add a moisture sensor and a MOSFET/pump pair. The firmware scales linearly; keep each plant's state in an array and run the same state machine per entry.
Will this work with a battery?
Poorly. Pumps draw 200–500 mA while running, which is fine but adds up. The bigger issue is that the ESP32 cannot usefully sleep while expecting a moisture reading every 30 minutes without adding complexity. This is a mains-powered project.
What about using a relay instead of a MOSFET?
Relays work and are simpler to wire for beginners. Downsides: audible click every cycle (annoying indoors), mechanical wear over thousands of activations, and slightly higher current draw from the 5V rail when energised. A logic-level MOSFET is silent, solid-state, and cheaper at scale. For a single houseplant project either is fine.
How do I integrate with Home Assistant?
Publish to an MQTT broker Home Assistant is listening on. In your Home Assistant configuration.yaml, add an mqtt.sensor for moisture and an mqtt.switch for manual pump control. The plant then becomes a device with a dashboard card showing moisture trend and a button to water manually.
Is there a ready-made kit I can buy instead of building?
Yes, several. Xiaomi's Flower Care puck, Parrot Flower Power, and various Tuya-based plant sensors exist. None of them are as customisable, and most send your data through the vendor's cloud. If you want to own the system end-to-end, building is the path.
Get the complete project package
The article above shows the core firmware and the principles behind it. The complete project package — assembled, tested, and ready to flash — is available by email request. We send it manually, and we read every request.
- Complete Arduino sketch (.ino) with full error handling
- List of required libraries with version numbers
- Printable wiring diagram (PDF)
- Bill of materials with current part numbers
- Build guide and troubleshooting tips
- Configuration template (WiFi, MQTT, etc.)
Share your thoughts
Worked with this in production and have a story to share, or disagree with a tradeoff? Email us at support@mybytenest.com — we read everything.