← All projects

Baxter International · May–August 2026

ESP32 irrigation system

A distributed irrigation system that measures soil moisture, schedules watering, and reports what happened—combining battery-powered sensing, wireless coordination, and 12 V valve control across three ESP32s.

C++ESP32ESP-NOWCircuit design3D printing

My contribution

I led component research, designed the three-board architecture and control circuit, developed C++ firmware, soldered the electronics, created custom 3D-printed parts, and integrated and debugged the hardware and software.

Mentorship: Naren Suri developed the Transmitter’s staged wake-up algorithm and provided periodic supervision, software troubleshooting, and feasibility guidance.

What I built and tested

A three-board irrigation system combining soil sensing, independent valve control, and Ethernet email monitoring.

I tested the system indoors and outside to check that it could read soil moisture, send messages between the boards, turn the water valve on and off, and send email updates.

Watch the garden demonstration →

Project status: The electronics and software are complete and have been tested together. Irrigation tubing testing remains to be finished next growing season; full-season performance has not yet been validated. Read the project status →

Every 12 seconds
1 / 10
Transmitter ESP32 with two soil sensors and soldered circuit boards inside its open enclosure
Transmitter ESP32: soil sensors, soldered wiring, and electronics inside the open waterproof protective enclosure.

Problem

Outdoor garden beds at Baxter International needed regular watering. With guidance and approval from my supervisor, Naren Suri, who helped assess whether the design would work, I developed a soil-aware irrigation system with the goal of reducing manual watering and unnecessary water use. The challenge was coordinating a battery-powered sensor that spends most of its time asleep with an always-ready valve controller, while protecting electronics near soil and plumbing.

System architecture

Sense, decide, and report are separate jobs. Separating these responsibilities lets the battery-powered sensor sleep without making valve control wait for it, and keeps physical irrigation control independent of email delivery.

See the daily sequence and control logic →

Physical layout · Garden beds & irrigation tubing

This top view shows the six garden beds, irrigation tubing, and wireless communication between the three ESP32s. The blue main line feeds the black drip tubing; yellow dashed lines show the data connections.

Top view of six garden beds: a half-inch irrigation main feeds quarter-inch drip tubing and emitters. The Receiver ESP32 controls water at the inlet, the Transmitter ESP32 measures soil moisture near Garden Bed 4, and the Ethernet ESP32 provides time and email services from the office. Yellow dashed paths show wireless data connections.
Garden-bed layout and component overview. Open full-size diagram ↗

ESP32 communication & GPIO connections

This diagram takes a closer look at the three-board system: ESP-NOW messages on channel 1, time synchronization, watering events, and the sensor and valve-control pins. It shows the later daily-schedule architecture, separate from the early V1 tests.

Three-ESP32 communication diagram: the Transmitter reads soil sensors on GPIO32 and GPIO33 and sends soil status to the Receiver. The Receiver acknowledges messages and controls the solenoid through GPIO21 and an XY MOSFET driver, with two-hour watering-enabled runs and moist-soil reports skipping watering. The Transmitter requests time using its scheduling algorithm, while the Receiver requests time hourly from the Ethernet ESP32. The Ethernet ESP32 uses a W5500 network adapter and sends watering-event emails. Dashed arrows show ESP-NOW communication on channel 1.
Current V3 architecture: soil sensing on GPIO32/GPIO33, valve control on GPIO21, and W5500 networking for time and notifications. Watering-enabled runs last two hours; a valid moist-soil report skips watering. Open full-size diagram ↗

Explore the board wiring and fabrication details →

Each board has a distinct job. The same names are used throughout the firmware and this case study.

Transmitter ESP32 and its two soil sensors

Transmitter ESP32

Soil sensing

Reads two sensors, averages their voltages, and sends soil status to the Receiver ESP32. Sleeps between scheduled wakeups.

Receiver ESP32 mounted inside its open waterproof enclosure, wired to the external solenoid valve

Receiver ESP32

Valve control

Stays awake, receives soil status, and switches the solenoid through a MOSFET circuit. Owns the daily watering schedule.

Full Ethernet ESP32 and W5500 network adapter, shown sideways

Ethernet ESP32

Time & notifications

Uses a W5500 adapter for wired internet, retrieves time through NTP, and sends email notifications for watering events.

Transmitter → Receiver: soil status. Receiver → Transmitter: acknowledgement.

Ethernet → Transmitter + Receiver: accurate time, requested by each board.

Receiver → Ethernet: watering events. Ethernet → Receiver: event acknowledgements.

All three use ESP-NOW on channel 1 for local radio communication. Only the Ethernet ESP32 connects to the wired network.

Software & firmware

The daily sequence below describes the current V3 configuration. For the earlier control designs, see the V1 tests and V2 Ethernet integration.

  1. ~7:40 p.m.Measure & report

    The Transmitter samples both sensors and sends soil status, giving a nominal 20-minute lead before watering.

  2. 8:00 p.m.Decide & water

    The Receiver evaluates soil status and either skips watering or starts the configured run.

  3. After each eventNotify

    The Ethernet ESP32 queues Gmail updates for valve-on, valve-off, or skipped watering.

Times use the installation’s America/New_York local time, including daylight saving time.

Why we chose an 8:00 p.m. schedule →

Transmitter ESP32 · Low-power sensing

The battery-powered Transmitter requests time from the Ethernet ESP32 on each wake, then uses staged deep sleeps to approach the 7:40 p.m. target. It combines the two sensors’ averaged readings into one voltage. See the sampling method and placement tests →

The voltage is rounded to two decimal places before deciding and sending. Above 1.75 V means needsWater = true; at or below 1.75 V means false. Both dry and moist conditions are reported, so “no watering needed” is different from “no report received.”

How Naren’s staged wake-up algorithm addresses sleep-clock drift →

Shared sensor data and consistent decisions

The SOIL_STATUS message carries the needs-water flag and averaged voltage in a shared 24-byte structure. Both boards check the structure’s size at compile time. Normalizing once prevents a value such as 1.995 V from being treated differently when displayed as 2.00 V downstream.

See the air/water endpoint tests and threshold research →

Receiver ESP32 · Watering authority

The wall-powered Receiver stays awake and requests fresh Ethernet time every hour; it does not sleep between requests. It accepts soil reports from 6:00 p.m. until just before 8:00 p.m. At the scheduled decision, a valid moist-soil report skips watering. Otherwise, the garden configuration runs the valve for two hours, including when no report arrives. The needs-water flag controls the decision; voltage is retained for notification context.

How the original variable-duration bands became two-hour runs →

The missing-report fallback prioritizes keeping plants watered, but can water unnecessarily. It requires a valid Receiver clock. Daily state resets at midnight so a previous day’s moist reading does not silently carry over.

Ethernet ESP32 · Time and monitoring

A W5500 Ethernet module obtains a network connection through DHCP. The Ethernet ESP32 gets time through NTP and answers the other boards’ REQUEST_TIME messages with seconds since midnight. It also turns Receiver events into readable Gmail notifications with event time, soil condition, and expected timing.

Acknowledgements, retries, and event queues

A successful radio send is not the same as the receiving application accepting the data. Application acknowledgements and separate queues distinguish those steps.

  • Soil report: the Transmitter makes up to three delivery attempts, waiting about five seconds for an application acknowledgement on each attempt.
  • Watering events: the Receiver stores up to 16 events in a first-in, first-out queue. It retries the oldest event every five seconds until a matching EVENT_ACK arrives.
  • Email delivery: the Ethernet ESP32 acknowledges an event only after accepting it into its separate 16-event queue. It suppresses duplicate events and re-acknowledges them. Failed email sends stay queued for retry at 60-second intervals when connected, and leave the queue after SMTP success.

An event acknowledgement confirms the Ethernet board accepted the event—not that an email reached someone’s inbox. These finite, in-memory queues help with temporary interruptions, but do not guarantee recovery through unlimited outages, queue overflow, or power loss.

What a notification actually means

Events are “Turned On,” “Turned Off,” or “Did Not Activate.” For example, a pre-watering reading of 2.13 V is described as moderately dry and selects a two-hour run in the deployed configuration. The early variable-duration concept would have selected 1.5 hours instead. The later valve-off email carries that same pre-watering reading; it is not a new measurement of the watered soil.

A missing reading is explicitly sent as NO_SOIL_DATA, rather than an invented voltage. Moisture labels in emails are descriptive; the needs-water flag controls watering. A “next watering” time means the next scheduled decision opportunity, not a guarantee that the valve will open.

What happens if time updates or email stop working?
  • The Receiver does not know the time yet: it waits for the correct time before starting scheduled watering.
  • The Receiver stops getting time updates: if its clock was already set, it can keep following the watering schedule using its own clock. That clock may become less accurate over time.
  • The Transmitter cannot get the time: if it is checking when to wake next, it sleeps for an hour and tries again. If it has already reached the wake-up step for taking a soil reading, it still takes the reading and tries to send it. See how the wake-up steps work →
  • Gmail cannot send an email: the system saves the notification and tries again later. Watering does not have to wait for the email to send.

Result & project status

The individual board tests progressed to an assembled system and an outdoor demonstration. The recordings and email history document the integration work, with the configuration and evidence limits explained alongside each example.

The electronics and firmware were completed and integration-tested. Testing of the irrigation tubing layout was still underway when I left for college. We plan to finish that testing and evaluate the complete system in the garden next growing season. Full-season performance has not yet been validated.

The current daily behavior follows the V3 documentation and updated project brief. The V1 tests and demonstration videos document earlier build stages; they are not evidence of every later reliability feature or quantified water and battery savings.

Next: V1–V3 · How the system evolved →