Building a 4-Zone Irrigation Controller with ESPHome - Part 2

Building a 4-Zone Irrigation Controller with ESPHome - Part 2

ESPHome Configuration

Here’s a sample YAML config for a 4-zone irrigation controller:

esphome:
  name: esphome-web-806180
  friendly_name: ESPHome Garden Irrigation Controller
  min_version: 2025.5.0
  name_add_mac_suffix: false

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

# Enable logging
logger:

# Enable Home Assistant API
# Enable Home Assistant API
api:

# Allow Over-The-Air updates
ota:
- platform: esphome

text_sensor:
  - platform: version
    name: "ESPHome Version"
    hide_timestamp: true

wifi:
  ap: {}

globals:
  - id: selected_index
    type: int
    restore_value: no
    initial_value: '0'

one_wire:
  - platform: gpio
    pin: GPIO16

i2c:
  sda: GPIO23
  scl: GPIO22

binary_sensor:
  - platform: gpio
    pin:
      number: GPIO0
      mode:
        input: true
        pullup: true
      inverted: true
    id: mode_button
    on_press:
      then:
        - select.next: run_mode
light:
  - platform: status_led
    name: run_led
    id: run_led
    pin: GPIO15

sensor:
  - platform: internal_temperature
    name: "Internal Temperature"
    id: ic_temp
  - platform: dallas_temp
    name: "Temperature"
    id: outside_temp

select:
  - platform: template
    name: "mode"
    id: run_mode
    options:
      - "OFF"
      - "AUTO"
      - "MANUAL"
    initial_option: "OFF"
    optimistic: true
  - platform: template
    name: "run_state"
    id: run_state
    options:
      - "READY"
      - "RUNNING"
    initial_option: "READY"
    optimistic: true
    on_value:
      then:
        - if:
            condition:
              lambda: 'return id(run_state).state == "RUNNING";'
            then:
              - light.turn_on: run_led
            else:
              - light.turn_off: run_led




switch:
  - platform: gpio
    pin: GPIO5
    name: "Irrigation Zone 1"
    inverted: true
    interlock: &interlock_group [zone_1, zone_2, zone_3, zone_4]
    id: zone_1
    on_turn_on:
      then:
        - select.set_index:
            id: run_state
            index: 1
    on_turn_off: 
      then:
        - select.set_index:
            id: run_state
            index: 0
  - platform: gpio
    pin: GPIO18
    name: "Irrigation Zone 2"
    inverted: true
    interlock: *interlock_group
    id: zone_2
    on_turn_on:
      then:
        - select.set_index:
            id: run_state
            index: 1
    on_turn_off: 
      then:
        - select.set_index:
            id: run_state
            index: 0
  - platform: gpio
    pin: GPIO19
    name: "Irrigation Zone 3"
    inverted: true
    interlock: *interlock_group
    id: zone_3
    on_turn_on:
      then:
        - select.set_index:
            id: run_state
            index: 1
    on_turn_off: 
      then:
        - select.set_index:
            id: run_state
            index: 0
  - platform: gpio
    pin: GPIO21
    name: "Irrigation Zone 4"
    inverted: true
    interlock: *interlock_group
    id: zone_4
    on_turn_on:
      then:
        - select.set_index:
            id: run_state
            index: 1
    on_turn_off: 
      then:
        - select.set_index:
            id: run_state
            index: 0

time:
  - platform: homeassistant
    id: homeassistant_time

font:
  - file: "https://github.com/IdreesInc/Monocraft/releases/download/v3.0/Monocraft.ttf"
    id: web_font_title
    size: 16
  - file: "https://github.com/IdreesInc/Monocraft/releases/download/v3.0/Monocraft.ttf"
    id: web_font_time
    size: 10
  - file: "https://github.com/IdreesInc/Monocraft/releases/download/v3.0/Monocraft.ttf"
    id: web_font_text
    size: 9
    
display:
  - platform: ssd1306_i2c
    model: "SSD1306 128x64"
    address: 0x3C
    lambda: |-
      it.printf(0, 0, id(web_font_title), "%s", id(run_state).state.c_str());
      it.strftime(it.get_width(), 0, id(web_font_time), TextAlign::TOP_RIGHT, "%H:%M", id(homeassistant_time).now());
      it.printf(0, 16, id(web_font_text), "Zne1: %s", id(zone_1).state ? "ON" : "OFF");
      it.printf(it.get_width(), 16, id(web_font_text), TextAlign::TOP_RIGHT, "Zne2: %s", id(zone_2).state ? "ON" : "OFF");
      it.printf(0, 25, id(web_font_text), "Zne3: %s", id(zone_3).state ? "ON" : "OFF");
      it.printf(it.get_width(), 25, id(web_font_text), TextAlign::TOP_RIGHT, "Zne4: %s", id(zone_4).state ? "ON" : "OFF");
      it.printf(0, 34, id(web_font_text), "Mode: %s", id(run_mode).state.c_str());
      it.printf(0, 53, id(web_font_text), "Out:%.1f°C", id(outside_temp).state);
      it.printf(it.get_width(), 52, id(web_font_text), TextAlign::TOP_RIGHT, "IC:%.1f°C", id(ic_temp).state);

Upload this config via ESPHome, and you’ll see four switches in Home Assistant — one for each irrigation zone.


Adding Automations

While you can toggle zones manually, automation makes irrigation shine. Examples:

  • Time-based schedule: Run Zone 1 for 10 minutes every morning at 6 AM.
  • Weather-aware watering: Skip irrigation if rain is forecast.
  • Soil-moisture integration: Only water if soil is below a threshold.

Example Home Assistant automation (YAML):

alias: Irrigation Morning Run
trigger:
  - platform: time
    at: "06:00:00"
action:
  - service: switch.turn_on
    target:
      entity_id: switch.zone_1
  - delay: "00:10:00"
  - service: switch.turn_off
    target:
      entity_id: switch.zone_1
  - service: switch.turn_on
    target:
      entity_id: switch.zone_2
  - delay: "00:10:00"
  - service: switch.turn_off
    target:
      entity_id: switch.zone_2
  # repeat for zones 3 & 4

Benefits of DIY Irrigation Controller

  • Flexible – Adjust zones and schedules without proprietary controllers.
  • Smart – Integrates with sensors, weather APIs, and voice assistants.
  • Affordable – Uses inexpensive ESP hardware and relays.
  • Fun – A practical project that improves your home and teaches you electronics.

Conclusion

With ESPHome and a simple 4-channel relay, you can build a smart irrigation controller that rivals commercial products — but with much more flexibility. Once set up, your garden or lawn can be watered automatically, intelligently, and efficiently.

This project is a great example of how home automation can move beyond lights and switches to something tangible, useful, and rewarding.