ESP32 Smart Irrigation Controller with ESPHome and Home Assistant

Build a multi-zone ESP32 irrigation controller with ESPHome and Home Assistant. Covers 24V valves, pump/master valve control, rain lockout, soil moisture, adjustable run times and safe automation.

An ESP32 can replace a surprisingly capable commercial irrigation controller when ESPHome handles the valves locally and Home Assistant handles the scheduling and weather logic. The important part is not simply connecting four relays to four GPIOs. A reliable controller needs safe valve sequencing, pump or master-valve coordination, sensible reboot behaviour, rain shutdown, adjustable run times and a clear boundary between local control and Home Assistant automation.

ESPHome already includes a dedicated sprinkler controller that behaves much more like a Rain Bird or Hunter controller than a collection of unrelated switches. It supports multiple zones, pumps or upstream master valves, full cycles, individual-zone runs, adjustable duration multipliers, repeats, pause/resume, valve queues and timing options designed to avoid pressure problems and water hammer.

This guide builds a four-zone controller around a classic ESP32 and ESPHome, then adds Home Assistant scheduling, rain lockout and soil-moisture logic.

Recommended Architecture

A good smart irrigation system separates responsibilities:

FunctionBest place
Actually energise/de-energise valvesESPHome
Zone sequencingESPHome sprinkler controller
Pump/master-valve timingESPHome
Immediate rain shutdownESPHome local input
Maximum valve run durationESPHome
Weekly scheduleHome Assistant
Weather forecast decisionHome Assistant
Soil-moisture thresholdHome Assistant or ESPHome
Seasonal watering adjustmentHome Assistant → ESPHome multiplier
History, dashboards and notificationsHome Assistant

This keeps the safety-critical water control on the ESP32 while letting Home Assistant use richer data when deciding whether a scheduled cycle should start.

Hardware You Need

  • ESP32 development board.
  • Four-channel or larger relay/driver board.
  • 24 V AC irrigation transformer for conventional sprinkler solenoid valves.
  • One irrigation valve per zone.
  • Optional pump relay/contactor or master valve.
  • Optional rain sensor with dry-contact output.
  • Optional capacitive soil-moisture sensors.
  • Weatherproof enclosure, fuses and suitable terminals.

A classic ESP32-WROOM DevKit is ideal because it offers plenty of GPIOs and ESPHome support. C3/C6/S3 boards also work if you choose pins appropriate to the exact board.

Do Not Drive Irrigation Valves from ESP32 GPIO

Most residential irrigation valves use a 24 V AC solenoid. The ESP32 GPIO is a 3.3 V logic output and cannot drive the valve directly.

For a conventional 24 V AC system:

24 VAC transformer common
        |
        +---------------- common to every valve

24 VAC switched side
        |
      relay contact
        |
      valve wire

The ESP32 operates the low-voltage input side of the relay module. The relay contacts switch the irrigation transformer output.

For a 12/24 V DC solenoid, a suitable MOSFET driver can be more efficient than a relay, but it needs correct flyback suppression. Do not put an ordinary flyback diode directly across a 24 V AC solenoid; AC coils require an AC-compatible suppression method such as an appropriately specified MOV or RC network if suppression is needed.

Pump and Master Valve Safety

Some irrigation systems use a pump or an upstream master valve that must run whenever any zone is active.

This is exactly what ESPHome’s sprinkler controller pump_switch_id is for. In ESPHome terminology, the “pump” can be a real pump or simply another upstream valve.

A mains-powered pump should not normally be switched directly by a tiny PCB relay unless the relay, wiring and enclosure are genuinely rated for its motor load and inrush current. In a permanent system, let the ESP32 relay drive a correctly sized pump contactor or approved control input.

Example GPIO Assignment

For a normal ESP32-WROOM DevKit:

FunctionESP32 GPIO
Zone 1 relayGPIO16
Zone 2 relayGPIO17
Zone 3 relayGPIO18
Zone 4 relayGPIO19
Pump/master relayGPIO23
Rain sensorGPIO27
Optional soil ADCGPIO34

GPIO34 is input-only, which is fine for an analogue sensor. If your exact ESP32 board uses PSRAM or has board-specific pin reservations, verify its pinout before copying these assignments.

Base ESPHome Configuration

esphome:
  name: garden-irrigation
  friendly_name: Garden Irrigation

esp32:
  board: esp32dev
  framework:
    type: esp-idf

logger:

api:

ota:
  - platform: esphome

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  ap:
    ssid: "Irrigation Fallback"
    password: !secret ap_password

captive_portal:

For an outdoor installation, reliable Wi-Fi matters less than reliable local valve control. Do not design the system so a Wi-Fi dropout leaves a raw relay stuck on indefinitely.

Define the Physical Outputs

The relay outputs themselves should remain internal. Home Assistant should normally control the sprinkler controller entities rather than directly overriding the GPIO switches underneath them.

switch:
  - platform: gpio
    id: zone_1_relay
    pin: GPIO16
    internal: true
    restore_mode: ALWAYS_OFF

  - platform: gpio
    id: zone_2_relay
    pin: GPIO17
    internal: true
    restore_mode: ALWAYS_OFF

  - platform: gpio
    id: zone_3_relay
    pin: GPIO18
    internal: true
    restore_mode: ALWAYS_OFF

  - platform: gpio
    id: zone_4_relay
    pin: GPIO19
    internal: true
    restore_mode: ALWAYS_OFF

  - platform: gpio
    id: irrigation_pump
    pin: GPIO23
    internal: true
    restore_mode: ALWAYS_OFF

ALWAYS_OFF is deliberate: after a reboot or power failure, the physical outputs start off instead of unexpectedly re-energising a valve.

If your relay board is active-low, use the appropriate inverted pin configuration rather than reversing logic throughout the rest of the project.

For relay wiring and safe output design, see our ESP32 Smart Relay for Home Assistant guide.

Four-Zone ESPHome Sprinkler Controller

sprinkler:
  - id: garden_irrigation

    main_switch: "Irrigation Cycle"
    auto_advance_switch: "Irrigation Auto Advance"

    multiplier_number:
      name: "Irrigation Multiplier"
      id: irrigation_multiplier
      initial_value: 1.0
      min_value: 0.0
      max_value: 2.0
      step: 0.1
      restore_value: true

    repeat_number:
      name: "Irrigation Repeat"
      initial_value: 0
      min_value: 0
      max_value: 3
      step: 1
      restore_value: true

    pump_start_pump_delay: 2s
    pump_stop_valve_delay: 2s

    valves:
      - valve_switch: "Front Lawn"
        enable_switch: "Enable Front Lawn"
        valve_switch_id: zone_1_relay
        pump_switch_id: irrigation_pump
        run_duration_number:
          name: "Front Lawn Run Time"
          initial_value: 12
          min_value: 1
          max_value: 60
          step: 1
          unit_of_measurement: min
          restore_value: true

      - valve_switch: "Back Lawn"
        enable_switch: "Enable Back Lawn"
        valve_switch_id: zone_2_relay
        pump_switch_id: irrigation_pump
        run_duration_number:
          name: "Back Lawn Run Time"
          initial_value: 12
          min_value: 1
          max_value: 60
          step: 1
          unit_of_measurement: min
          restore_value: true

      - valve_switch: "Hedges"
        enable_switch: "Enable Hedges"
        valve_switch_id: zone_3_relay
        pump_switch_id: irrigation_pump
        run_duration_number:
          name: "Hedges Run Time"
          initial_value: 8
          min_value: 1
          max_value: 60
          step: 1
          unit_of_measurement: min
          restore_value: true

      - valve_switch: "Vegetable Beds"
        enable_switch: "Enable Vegetable Beds"
        valve_switch_id: zone_4_relay
        pump_switch_id: irrigation_pump
        run_duration_number:
          name: "Vegetable Beds Run Time"
          initial_value: 10
          min_value: 1
          max_value: 60
          step: 1
          unit_of_measurement: min
          restore_value: true

This creates a much more useful Home Assistant interface than four raw relay switches. You get individual zone controls, zone enable switches, run-time settings, a complete-cycle switch, repeat count and a global multiplier.

Why Use the Irrigation Multiplier?

The multiplier adjusts every configured zone proportionally without rewriting individual times.

Base zone timeMultiplierActual run
12 min0.56 min
12 min0.89.6 min
12 min1.012 min
12 min1.518 min

This is ideal for seasonal adjustment. Home Assistant can reduce the multiplier after cool weather or increase it during a hot dry period while the relative balance between zones stays unchanged.

ESPHome’s sprinkler-number values can persist across reboots when restore_value: true is used, so changing a zone from 12 to 15 minutes in Home Assistant does not have to disappear at the next restart.

Pump Timing Matters

A pump should not normally run against a completely closed irrigation system. ESPHome provides dedicated timing controls for this.

In the example:

pump_start_pump_delay: 2s
pump_stop_valve_delay: 2s

the distribution valve opens first, then the pump starts two seconds later. At shutdown, the pump stops first and the valve remains open for another two seconds.

That avoids running the pump into closed downstream valves. The correct sequence depends on your actual hydraulic system, so do not copy delays blindly if your valves require pressure to close properly.

Valve Overlap vs Valve Open Delay

When moving from one zone to the next, sudden closure can cause water hammer.

ESPHome offers two strategies:

OptionBehaviour
valve_overlapNext zone opens before current zone closes
valve_open_delayCurrent zone closes, then controller waits before opening next zone

They are alternatives; ESPHome does not allow both on the same controller.

For a normal pressurised municipal-water sprinkler system, a few seconds of overlap can soften pressure transients. For systems where simultaneous valves would reduce pressure too much, an open delay may be better.

Add a Local Rain Sensor

A traditional irrigation rain sensor is often just a normally-open or normally-closed dry contact. Connect it to an ESP32 input with a pull-up and use it as a local safety input.

binary_sensor:
  - platform: gpio
    id: rain_sensor
    name: "Irrigation Rain Sensor"
    device_class: moisture

    pin:
      number: GPIO27
      mode:
        input: true
        pullup: true
      inverted: true

    filters:
      - delayed_on_off: 1s

    on_press:
      - sprinkler.shutdown: garden_irrigation

The exact inverted setting depends on whether your physical sensor contact closes or opens when wet.

The important point is that active rain can shut the controller down locally. Home Assistant does not need to notice the rain, send an API command and hope Wi-Fi is still working.

Rain Shutdown Is Not the Same as Rain Start Lockout

The local action above stops a cycle if the rain sensor becomes wet. You should also prevent a scheduled cycle from starting while the sensor is already wet.

That second decision is easy in Home Assistant: put the rain-sensor state into the automation conditions before turning on the irrigation-cycle switch.

Add Soil Moisture

A capacitive soil-moisture sensor gives Home Assistant another reason to skip watering. Use a 3.3 V-compatible analogue output and calibrate it against your own soil rather than trusting the percentage printed by somebody else’s project.

sensor:
  - platform: adc
    pin: GPIO34
    name: "Garden Soil Moisture"
    id: garden_soil
    update_interval: 60s
    attenuation: auto

    filters:
      - calibrate_linear:
          - 2.75 -> 0
          - 1.35 -> 100
      - clamp:
          min_value: 0
          max_value: 100

    unit_of_measurement: "%"
    device_class: moisture
    state_class: measurement

The example assumes a sensor whose voltage falls as moisture rises. Your own dry/wet voltages will be different, so replace 2.75 V and 1.35 V with actual measurements from your installation.

Our upcoming dedicated Capacitive Soil Moisture Sensor with ESP32, ESPHome and Home Assistant guide will cover corrosion, calibration, mounting depth and long-term drift in detail.

Keep the Moisture Sensor Representative

One sensor in one flower pot should not decide whether a 200 m² lawn needs water.

For useful irrigation control:

  • Use a sensor in a representative root zone.
  • Do not place it directly beside a dripper.
  • Avoid positions permanently shaded or unusually wet.
  • Use separate sensors for genuinely different irrigation zones where needed.
  • Use threshold hysteresis rather than one exact percentage.

Home Assistant Schedule Example

The simplest useful Home Assistant automation is: at the scheduled time, start the full ESPHome cycle only when the rain sensor is dry and the soil is below a chosen threshold.

alias: Garden Irrigation Morning Cycle
triggers:
  - trigger: time
    at: "05:30:00"

conditions:
  - condition: state
    entity_id: binary_sensor.irrigation_rain_sensor
    state: "off"

  - condition: numeric_state
    entity_id: sensor.garden_soil_moisture
    below: 35

actions:
  - action: switch.turn_on
    target:
      entity_id: switch.irrigation_cycle

mode: single

Entity IDs are generated from your actual ESPHome/Home Assistant names, so confirm them in Home Assistant rather than assuming they will exactly match the example.

Add Weather Forecast Logic Carefully

Weather-aware irrigation sounds clever, but the best rule is often simple:

Do not water when:
soil is already wet
OR rain sensor is active
OR meaningful rain is expected soon

Use forecast rain as a scheduling decision in Home Assistant rather than a safety interlock inside the ESP32. Online weather data can be wrong or unavailable; a local physical rain sensor remains more appropriate for immediate shutdown.

Similarly, do not build an elaborate evapotranspiration model unless you actually have the inputs and need the precision. A seasonal multiplier plus rain/moisture lockouts is often more reliable than a complicated model fed by poor weather data.

Manual Zone Control

The ESPHome sprinkler component automatically creates individual valve switches. Turning on a zone from Home Assistant runs that zone for its configured duration and disables auto-advance for that manual run.

This is ideal for:

  • Testing sprinkler heads.
  • Checking for leaks.
  • Watering one dry zone.
  • Commissioning new pipework.

Do not expose the underlying physical relay switches as separate user controls. Bypassing the sprinkler controller would also bypass its sequencing and pump coordination.

Pause, Resume and Shutdown

ESPHome provides actions for:

  • sprinkler.pause
  • sprinkler.resume
  • sprinkler.shutdown
  • sprinkler.start_full_cycle
  • sprinkler.start_single_valve
  • next/previous zone actions
  • zone queuing

The queue can be useful for advanced Home Assistant automations: instead of starting a complete cycle, Home Assistant can build a custom sequence of only the zones that actually need water.

A Flow Meter Makes the System Much Smarter

If your irrigation supply has a pulse-output water meter, Home Assistant can detect conditions that a valve-state sensor cannot.

Valve stateMeasured flowPossible problem
All valves offFlow presentLeak or stuck valve
Zone onZero flowClosed supply, failed pump or valve
Zone onMuch higher than normalBroken pipe or sprinkler head
Zone onMuch lower than normalBlocked filter/nozzle or low pressure

See our ESP32 Water Meter for Home Assistant guide for pulse-meter configuration and total water tracking.

Optional Tank-Level Interlock

If irrigation is supplied from a rainwater tank, do not let the pump run dry. A Home Assistant condition can block scheduled irrigation when the tank level is low, while a hard low-level switch wired locally can provide an even stronger pump interlock.

Our ESP32 Water Tank Level Monitor guide covers ultrasonic and hydrostatic level measurement.

Fail-Safe Behaviour

A smart irrigation controller should fail toward water off.

Recommended behaviour:

  • Relay GPIOs boot off.
  • A restarted ESP32 does not blindly restore an active valve.
  • Every manual zone has a finite configured duration.
  • Rain input can stop the controller locally.
  • Pump never runs intentionally with no valid downstream water path.
  • Underlying relay switches are internal.
  • Home Assistant being offline prevents smart scheduling, not valve shutdown.

Outdoor Installation

Do not put an ESP32 DevKit and open relay board into an ordinary plastic food box beside the irrigation manifold.

A permanent installation should use:

  • A proper weather-resistant enclosure.
  • Cable glands.
  • Fused transformer output.
  • Terminal blocks rather than loose jumpers.
  • Separation between mains and extra-low-voltage wiring.
  • Surge/transient consideration for long outdoor cables.
  • Antenna placement that does not bury the ESP32 inside a metal cabinet.

Long valve wires outdoors can collect electrical transients. Relay isolation does not magically protect every part of the PCB, so enclosure grounding, surge protection and good cable routing matter on a permanent system.

Commissioning Checklist

  1. Power the ESP32 with all valve outputs disconnected.
  2. Confirm every physical relay starts OFF.
  3. Test each relay with no valve connected.
  4. Connect and test one valve at a time.
  5. Verify zone names match the actual pipework.
  6. Test pump/master-valve timing.
  7. Run a complete automatic cycle while watching transitions.
  8. Trigger the rain sensor during watering and confirm immediate shutdown.
  9. Restart the ESP32 during a test run and confirm outputs return safely off.
  10. Only then enable Home Assistant schedules.

Common Problems

SymptomLikely cause / first check
Valve never opensCheck 24 VAC at valve and relay contact wiring; GPIO cannot power it directly
Relay LED changes but valve does nothingTransformer/common wiring or contact terminal error
Valve stays on after ESP rebootWrong relay restore/polarity configuration or hardware wiring
Pump starts before water path is openConfigure pump start/stop delays
Pipes bang when changing zonesConsider valve overlap or different hydraulic sequencing
All valves run manually but full cycle skips oneZone’s enable switch is off
Run times reset unexpectedlyUse sprinkler number entities with restore enabled
Rain sensor stops cycle but morning schedule restarts itAdd rain condition to Home Assistant start automation
Soil percentage is backwardsSwap/calibrate dry and wet ADC reference points
Wi-Fi loss breaks active wateringDo not put valve sequencing in HA delays; keep it in ESPHome

Why ESPHome’s Sprinkler Component Is Better Than Four Relay Automations

You could create four switches in Home Assistant and write an automation containing:

zone 1 on
delay 10 min
zone 1 off
zone 2 on
delay 10 min
...

That looks simple but pushes hydraulic sequencing and output state into a network-dependent automation. A Home Assistant restart, automation reload or logic error can leave behaviour harder to reason about.

ESPHome’s sprinkler controller already knows that zones belong to one controller. It manages the run timers, cycle progression, pump/master output and transitions locally. Home Assistant only needs to say “start the irrigation cycle” or “run zone 3”.

Recommended Final Design

For a typical four-zone home installation, I would build it like this:

  • ESP32-WROOM controller.
  • Four isolated/appropriate relay channels for 24 V AC valves.
  • One additional relay for a master valve or contactor input if required.
  • ESPHome sprinkler controller for all sequencing.
  • Per-zone run-time number entities.
  • One global seasonal multiplier.
  • Local rain sensor that can immediately call sprinkler.shutdown.
  • Home Assistant schedule with rain and moisture conditions.
  • Optional pulse water meter for leak/flow verification.
  • Optional tank-level interlock when using stored water.

That gives you the useful flexibility of a smart irrigation platform without making a cloud service or Home Assistant connection responsible for keeping a physical valve safe.

Related ESP32 Home Automation Guides

Official Resources

Share your love