Sprinkler automation with ESPHome, a complete project

Alaric:
Thank ou for sharing your hard work (and surely countless nights) with us!!
I am going to attempt to run this at home to replace my aging RainBird Controller, by “tapping” the control wires directly to the rainbird.
I do have two small questions/concerns… I’m using an esp32 instead of an 8266. Do I just swap out names, etc…??
Also, I need to run 5 zones (plus the rain sensor), can I edit the "don’t edit anyitng below this line’ to add one more zone??

Thanks in advance

Mike

Hi!

why multiplier 1 and not 60?

TIA

I’ve gotten hung up on adding a 5th zone. It shows, and it can be activate it, but it is also activating zone 4 at the same time. I’m going to try to install over the weekend if possible.

Also, can 'schedules" be pre-built using automations/?

Please find code attached;

##ALARIC SPRINKLERS BELOW
# Based on ESPHome Sprinkler Controller - https://esphome.io/components/sprinkler.html
# Change Log
# 2023 01 XX
  # Initial version
  
# 2023 04 09 V03
  # fix run duration to seconds 
# 2023 04 22 V04
  # fix GPIO order to match relay 1- 4
  # added % at the lambda return for progress sensor return value
# 2023 04 25 V05
  # added nodemcu as sensor to display in HA ui
  # added includes for api key en ota password
# 2023 05 07 V06
  # added a NTC temp sensor to  watch the enclosure temperature
# 2023 05 10 V07
  # addjusted settings reference voltage to adjust to actual temp (default 3.3)
# 2023 09 11 v08
  # adjusted number of valves to 5 Changed temp sensor to dht, as i had in hand (by mgamache)
  # also adjusted for esp32, and added switch for rain sensor
# Establish Substitutions
substitutions:
### Modify only the following 6 lines.
  zone_1_name: Sprinkler Zone 1
  zone_2_name: Sprinkler Zone 2
  zone_3_name: Sprinkler Zone 3
  zone_4_name: Sprinkler Zone 4
  zone_5_name: Sprinkler Zone 5
  software_version: 2023 09 11 V08
  sensor_update_frequency: 1s
  log_level: warn # Enable levels logging https://esphome.io/components/logger.html
  # none, error, warn, info, debug (default), verbose, very_verbose
  # changed log level from debug to warn 11/13 by mgamache
##############################################
#  DO NOT CHANGE ANYTHING BELOW THIS LINE  ###
##############################################
  zone_1_valve_id: valve_0
  zone_2_valve_id: valve_1
  zone_3_valve_id: valve_2
  zone_4_valve_id: valve_3
  zone_5_valve_id: valve_4
  esphome_name: irrigation
  esphome_platform: ESP32
  esphome_board: esp32dev
  esphome_comment: Five Valve Irrigation Control
  esphome_project_name: JAYA.Five Valve Irrigation Control
  esphome_project_version: Irrigation Controller, $software_version
  devicename: irrigation_controller
  upper_devicename: "Irrigation Controller"
  uom: Min # this overrides the uom in sprinkler -> run_duration 


#Define Project Deatils and ESP Board Type
esphome:
  name: $esphome_name
  platform: $esphome_platform
  board: $esphome_board
  comment: $esphome_comment
  project:
    name: $esphome_project_name
    version: $esphome_project_version
  on_boot:
    priority: -100
    then:
      # Set default state for Valve Status
      - text_sensor.template.publish:
          id: valve_status
          state: "Idle"
      # Set multiplier to 60, convert seconds to minutes
      - sprinkler.set_multiplier:
          id: $devicename
          multiplier: 60

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "$esphome_name Fallback Hotspot"
    password: !secret esphome_ap_password
  
logger:
  level: ${log_level}
  logs:
    text_sensor: ERROR
  
ota:
  password: !secret esphome_ota_password

# Enable Web server.
#web_server:
#  port: 80
web_server:
  port: 80
  auth:
    username: !secret webserver_username
    password: !secret webserver_password
  js_include: "./v2/www.js"
  js_url: ""
  version: 2 
# Sync time with Home Assistant.
time:
  - platform: homeassistant
    id: homeassistant_time
    
###############################################
# Enable Home Assistant API
###############################################
api:
  encryption:
    key: !secret esphome_api_encrypt_key
  reboot_timeout: 0s

###############################################
# Binary Sensor.
###############################################
binary_sensor:
  - platform: homeassistant
    # prevent deep sleep - Needs further investigation on usefullness
    id: prevent_deep_sleep
    name: "$upper_devicename Prevent Deep Sleep"
    entity_id: input_boolean.prevent_deep_sleep 
  - platform: gpio
    pin:
      number: GPIO25
      inverted: false
      mode:
        input: true
        pullup: true 
    name: Rain Sensor


###############################################
# Text sensors with general information.
###############################################
text_sensor:
  - platform: version # Expose ESPHome version as sensor.
    name: $esphome_name ESPHome Version
    hide_timestamp: false
  - platform: wifi_info
    ip_address:
      name: "$esphome_name IP"
    ssid:
      name: "$esphome_name SSID"
    bssid:
      name: "$esphome_name BSSID"
  
# Expose Time Remaining as a sensor.
  - platform: template
    id: time_remaining
    name: $upper_devicename Time Remaining
    update_interval: $sensor_update_frequency
    icon: "mdi:timer-sand"
    lambda: |-
      int seconds = round(id($devicename).time_remaining_active_valve().value_or(0));
      int days = seconds / (24 * 3600);
      seconds = seconds % (24 * 3600);
      int hours = seconds / 3600;
      seconds = seconds % 3600;
      int minutes = seconds /  60;
      seconds = seconds % 60;
        return {
          ((days ? String(days) + "d " : "") + 
          (hours ? String(hours) + "h " : "") +
          (minutes ? String(minutes) + "m " : "") +
          (String(seconds) + "s")).c_str()};


  # Expose Progress Percent as a sensor.
  - platform: template
    id: progress_percent
    name: $upper_devicename Progress %
    update_interval: $sensor_update_frequency
    icon: "mdi:progress-clock"
    lambda: |-
      int progress_percent = round(((id($devicename).valve_run_duration_adjusted(id($devicename).active_valve().value_or(0)) - id($devicename).time_remaining_active_valve().value_or(0)) * 100 / id($devicename).valve_run_duration_adjusted(id($devicename).active_valve().value_or(0))));
      std::string progress_percent_as_string = std::to_string(progress_percent);
      return progress_percent_as_string +"%";

  # Expose Valve Status as a sensor.
  - platform: template
    id: valve_status
    name: $upper_devicename Status
    update_interval: never
    icon: "mdi:information-variant"

  - platform: template # Expose the board type as a sensor
    id: espboard_type
    icon: "mdi:developer-board"
    name: $esphome_name ESPBoard
    lambda: |-
      return to_string("${esphome_board}");

# https://esphome.io/devices/nodemcu_esp32.html
# Enable On-Board Status LED.
status_led:
  pin:
    # Pin D2 / GPIO4
    number: GPIO04
    inverted: false

sensor:
  # Uptime sensor.
  - platform: uptime
    name: $upper_devicename Uptime

  # WiFi Signal sensor.
  - platform: wifi_signal
    name: $upper_devicename WiFi Signal
    update_interval: 60s

  # temperature sensor https://esphome.io/components/sensor/ntc.html using  a switch every 1 minute. Pull Upp GPIO16 (3.3V). prevents self-heating NTC
  - platform: ntc
    sensor: resistance_sensor
    name: $upper_devicename Temperature
    calibration:
      b_constant: 3950
      reference_temperature: 25°C
      reference_resistance: 10kOhm
  - platform: resistance
    id: resistance_sensor
    sensor: source_sensor
    configuration: DOWNSTREAM
    resistor: 10kOhm
    name: Resistance Sensor
    reference_voltage: 3.1V
  - platform: adc
    pin: A0
    id: source_sensor
    # Added:
    update_interval: never
    filters:
      - multiply: 3.3

interval:
  - interval: 60s
    then:
      - switch.turn_on: ntc_vcc
      - component.update: source_sensor
      - switch.turn_off: ntc_vcc
      - logger.log: "Measure Temp"

###############################################
# Configuration to set multiplier via number 
############################################### 
number:
  - platform: template
    id: $zone_1_valve_id
    name: $zone_1_name
    min_value: 1
    max_value: 60
    step: 1
    unit_of_measurement: $uom
    icon: "mdi:timer-outline"
    mode: box # Defines how the number should be displayed in the UI
    lambda: "return id($devicename).valve_run_duration(0);"
    set_action:
      - sprinkler.set_valve_run_duration:
          id: $devicename
          valve_number: 0
          run_duration: !lambda 'return x;'
  - platform: template
    id: $zone_2_valve_id
    name: $zone_2_name
    min_value: 1
    max_value: 60
    step: 1
    unit_of_measurement: $uom
    icon: "mdi:timer-outline"
    mode: box # Defines how the number should be displayed in the UI
    lambda: "return id($devicename).valve_run_duration(1);"
    set_action:
      - sprinkler.set_valve_run_duration:
          id: $devicename
          valve_number: 1
          run_duration: !lambda 'return x;'
  - platform: template
    id: $zone_3_valve_id
    name: $zone_3_name
    min_value: 1
    max_value: 60
    step: 1
    unit_of_measurement: $uom
    icon: "mdi:timer-outline"
    mode: box # Defines how the number should be displayed in the UI
    lambda: "return id($devicename).valve_run_duration(2);"
    set_action:
      - sprinkler.set_valve_run_duration:
          id: $devicename
          valve_number: 2
          run_duration: !lambda 'return x;'
  - platform: template
    id: $zone_4_valve_id
    name: $zone_4_name
    min_value: 1
    max_value: 60
    step: 1
    unit_of_measurement: $uom
    icon: "mdi:timer-outline"
    mode: box # Defines how the number should be displayed in the UI
    lambda: "return id($devicename).valve_run_duration(3);"
    set_action:
      - sprinkler.set_valve_run_duration:
          id: $devicename
          valve_number: 3
          run_duration: !lambda 'return x;'
  - platform: template
    id: $zone_5_valve_id
    name: $zone_5_name
    min_value: 1
    max_value: 60
    step: 1
    unit_of_measurement: $uom
    icon: "mdi:timer-outline"
    mode: box # Defines how the number should be displayed in the UI
    lambda: "return id($devicename).valve_run_duration(4);"
    set_action:
      - sprinkler.set_valve_run_duration:
          id: $devicename
          valve_number: 4
          run_duration: !lambda 'return x;'
###############################################
# Main Sprinkler Controller
###############################################
sprinkler:
  - id: $devicename
    main_switch:
      name: "Start/Stop/Resume"
      id: main_switch
    auto_advance_switch: "Auto Advance"
    valve_open_delay: 2s
    valves:
      - valve_switch: $zone_1_name
        enable_switch: Enable $zone_1_name
        run_duration: 15s
        valve_switch_id: ${devicename}_1
      - valve_switch: $zone_2_name
        enable_switch: Enable $zone_2_name
        run_duration: 15s
        valve_switch_id: ${devicename}_2
      - valve_switch: $zone_3_name
        enable_switch: Enable $zone_3_name
        run_duration: 15s
        valve_switch_id: ${devicename}_3
      - valve_switch: $zone_4_name
        enable_switch: Enable $zone_4_name
        run_duration: 15s
        valve_switch_id: ${devicename}_4
      - valve_switch: $zone_5_name
        enable_switch: Enable $zone_5_name
        run_duration: 15s
        valve_switch_id: ${devicename}_5 
 
button:
  - platform: template
    id: sprinkler_pause
    name: "Pause"
    icon: "mdi:pause"
    on_press:
      then:
        - text_sensor.template.publish:
            id: valve_status
            state: "Paused"
        - sprinkler.pause: $devicename


####################################################
# Switch Control to restart the irrigation system.   
####################################################
switch:
  - platform: restart
    name: "Restart $devicename"

# Switch for the NTC https://esphome.io/components/sensor/ntc.html, Prevent self heating by switching the voltage on a GPIO
  - platform: gpio
    pin: 
      number: GPIO5 #GPIO16 # Pin D0
      inverted: false
    id: ntc_vcc

####################################################
# Hidden I/O  Switches to control irrigation valve relays
####################################################
  - platform: gpio
    name: Relay Board Pin IN1
    restore_mode: RESTORE_DEFAULT_OFF # Prevents GPIO pin from going high during boot
    internal: true # Prevents GPIO switch NAME from showing up in Home Assistant
    id: ${devicename}_1
    on_turn_on:
      - text_sensor.template.publish:
          id: valve_status
          state: "$zone_1_name Active"
    on_turn_off:
      - text_sensor.template.publish:
          id: valve_status
          state: "Idle"
    pin: GPIO14 # D5
    inverted: true
  - platform: gpio
    name: Relay Board Pin IN2
    restore_mode: RESTORE_DEFAULT_OFF # Prevents GPIO pin from going high during boot
    internal: true # Prevents GPIO switch NAME from showing up in Home Assistant
    id: ${devicename}_2
    on_turn_on:
      - text_sensor.template.publish:
          id: valve_status
          state: "$zone_2_name Active"
    on_turn_off:
      - text_sensor.template.publish:
          id: valve_status
          state: "Idle"
    pin: GPIO12 # D6
    inverted: true
  - platform: gpio
    name: Relay Board Pin IN3
    restore_mode: RESTORE_DEFAULT_OFF # Prevents GPIO pin from going high during boot
    internal: true # Prevents GPIO switch NAME from showing up in Home Assistant
    id: ${devicename}_3
    on_turn_on:
      - text_sensor.template.publish:
          id: valve_status
          state: "$zone_3_name Active"
    on_turn_off:
      - text_sensor.template.publish:
          id: valve_status
          state: "Idle"
    pin: GPIO13 # D7
    inverted: true
  - platform: gpio
    name: Relay Board Pin IN4
    restore_mode: RESTORE_DEFAULT_OFF # Prevents GPIO pin from going high during boot
    internal: true # Prevents GPIO switch NAME from showing up in Home Assistant
    id: ${devicename}_4
    on_turn_on:
      - text_sensor.template.publish:
          id: valve_status
          state: "$zone_4_name Active"
    on_turn_off:
      - text_sensor.template.publish:
          id: valve_status
          state: "Idle"
    pin: GPIO15 # D8
    inverted: true
  - platform: gpio
    name: Relay Board Pin IN5
    restore_mode: RESTORE_DEFAULT_OFF # Prevents GPIO pin from going high during boot
    internal: true # Prevents GPIO switch NAME from showing up in Home Assistant
    id: ${devicename}_5
    on_turn_on:
      - text_sensor.template.publish:
          id: valve_status
          state: "$zone_5_name Active"
    on_turn_off:
      - text_sensor.template.publish:
          id: valve_status
          state: "Idle"
    pin: GPIO27 # D8
    inverted: true  

    # Example configuration entry v2

Hi Hermie,
Looking at your code, I don’t see any strange things.
I’m not familiar to the esp32 devkit, but assume it it should work fine too. Just keep track of the gpio pinning numbering and physical.
Please make sure that the gpio match the board you use, I used a ESP8266MOD. (this has no gpio27 pin) and check the wiring (GPIO to relay board)

Hope this helps a bit.

Hi @Cav-X
I think its not needed to set new schedule times by an external mechanisme, although I like the idea. Why not set the schedules at a minimum time and let the total time be regulated by the numbers of repeating?

Got thru the 5th Valve issue if anyone wants the code, let me know!

Do have to ask a favor of anyone on this thread, to see if they could verify my wiring off my diagram.
I am using “what I have at home” for now, that is why I’m using two Power Supplies (a 12v to run esp and relay board) and a 24v to run the valves.
I’m mainly concerned that I’m wiring up the 24v correctly, to the common wire that hits all valves, and the other to the relay board (again, all relays).
I have benched tested it an appears OK, but wanted a second set of eyes if at all possible to make sure.
I am going to replace (put along side of) aging rainbird controller (about 15 years old).
I’ll mock up my enclosure so i can post some pics for critique sake.
I also added the rain sensor pin, just don’t know how to add it to the sytem (not to run if the pin is off(or on)!
Pics are enclosure open and enclosure closed.


Thanks in advance!

@Alaric, thank you so much for the nice project.

@hermie thx for your efforts.

Could you please share the 5 channel code? I’m about to try to extend to 8 channel, as i will have a huge yard (almost 5 hectar) with different zones to irrigate.

@terryhonn, why multiplier: 1, insted of 60?

Paulo, plase see attached.
Thank you!

##ALARIC SPRINKLERS BELOW
# Based on ESPHome Sprinkler Controller - https://esphome.io/components/sprinkler.html
# Change Log
# 2023 01 XX
  # Initial version
  
# 2023 04 09 V03
  # fix run duration to seconds 
# 2023 04 22 V04
  # fix GPIO order to match relay 1- 4
  # added % at the lambda return for progress sensor return value
# 2023 04 25 V05
  # added nodemcu as sensor to display in HA ui
  # added includes for api key en ota password
# 2023 05 07 V06
  # added a NTC temp sensor to  watch the enclosure temperature
# 2023 05 10 V07
  # addjusted settings reference voltage to adjust to actual temp (default 3.3)
# 2023 09 11 v08
  # adjusted number of valves to 5 Changed temp sensor to dht, as i had in hand (by mgamache)
  # also adjusted for esp32, and added switch for rain sensor, but not set to do anything (yet!)
# Establish Substitutions
substitutions:
### Modify only the following 6 lines.
  zone_1_name: Sprinkler Zone 1
  zone_2_name: Sprinkler Zone 2
  zone_3_name: Sprinkler Zone 3
  zone_4_name: Sprinkler Zone 4
  zone_5_name: Sprinkler Zone 5
  software_version: 2023 09 11 V08
  sensor_update_frequency: 1s
  log_level: warn # Enable levels logging https://esphome.io/components/logger.html
  # none, error, warn, info, debug (default), verbose, very_verbose
  # changed log level from debug to warn 11/13 by mgamache
##############################################
#  DO NOT CHANGE ANYTHING BELOW THIS LINE  ###
##############################################
  zone_1_valve_id: valve_0
  zone_2_valve_id: valve_1
  zone_3_valve_id: valve_2
  zone_4_valve_id: valve_3
  zone_5_valve_id: valve_4
  esphome_name: irrigation
  esphome_platform: ESP32
  esphome_board: esp32dev
  esphome_comment: Five Valve Irrigation Control
  esphome_project_name: JAYA.Five Valve Irrigation Control
  esphome_project_version: Irrigation Controller, $software_version
  devicename: irrigation_controller
  upper_devicename: "Irrigation Controller"
  uom: Min # this overrides the uom in sprinkler -> run_duration 


#Define Project Deatils and ESP Board Type
esphome:
  name: $esphome_name
  platform: $esphome_platform
  board: $esphome_board
  comment: $esphome_comment
  project:
    name: $esphome_project_name
    version: $esphome_project_version
  on_boot:
    priority: -100
    then:
      # Set default state for Valve Status
      - text_sensor.template.publish:
          id: valve_status
          state: "Idle"
      # Set multiplier to 60, convert seconds to minutes
      - sprinkler.set_multiplier:
          id: $devicename
          multiplier: 60

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "$esphome_name Fallback Hotspot"
    password: !secret esphome_ap_password
  
logger:
  level: ${log_level}
  logs:
    text_sensor: ERROR
  
ota:
  password: !secret esphome_ota_password

# Enable Web server.
#web_server:
#  port: 80
web_server:
  port: 80
  auth:
    username: !secret webserver_username
    password: !secret webserver_password
  js_include: "./v2/www.js"
  js_url: ""
  version: 2 
# Sync time with Home Assistant.
time:
  - platform: homeassistant
    id: homeassistant_time
    
###############################################
# Enable Home Assistant API
###############################################
api:
  encryption:
    key: !secret esphome_api_encrypt_key
  reboot_timeout: 0s

###############################################
# Binary Sensor.
###############################################
binary_sensor:
  - platform: homeassistant
    # prevent deep sleep - Needs further investigation on usefullness
    id: prevent_deep_sleep
    name: "$upper_devicename Prevent Deep Sleep"
    entity_id: input_boolean.prevent_deep_sleep 
  - platform: gpio
    pin:
      number: GPIO25
      inverted: false
      mode:
        input: true
        pullup: true 
    name: Rain Sensor


###############################################
# Text sensors with general information.
###############################################
text_sensor:
  - platform: version # Expose ESPHome version as sensor.
    name: $esphome_name ESPHome Version
    hide_timestamp: false
  - platform: wifi_info
    ip_address:
      name: "$esphome_name IP"
    ssid:
      name: "$esphome_name SSID"
    bssid:
      name: "$esphome_name BSSID"
  
# Expose Time Remaining as a sensor.
  - platform: template
    id: time_remaining
    name: $upper_devicename Time Remaining
    update_interval: $sensor_update_frequency
    icon: "mdi:timer-sand"
    lambda: |-
      int seconds = round(id($devicename).time_remaining_active_valve().value_or(0));
      int days = seconds / (24 * 3600);
      seconds = seconds % (24 * 3600);
      int hours = seconds / 3600;
      seconds = seconds % 3600;
      int minutes = seconds /  60;
      seconds = seconds % 60;
        return {
          ((days ? String(days) + "d " : "") + 
          (hours ? String(hours) + "h " : "") +
          (minutes ? String(minutes) + "m " : "") +
          (String(seconds) + "s")).c_str()};


  # Expose Progress Percent as a sensor.
  - platform: template
    id: progress_percent
    name: $upper_devicename Progress %
    update_interval: $sensor_update_frequency
    icon: "mdi:progress-clock"
    lambda: |-
      int progress_percent = round(((id($devicename).valve_run_duration_adjusted(id($devicename).active_valve().value_or(0)) - id($devicename).time_remaining_active_valve().value_or(0)) * 100 / id($devicename).valve_run_duration_adjusted(id($devicename).active_valve().value_or(0))));
      std::string progress_percent_as_string = std::to_string(progress_percent);
      return progress_percent_as_string +"%";

  # Expose Valve Status as a sensor.
  - platform: template
    id: valve_status
    name: $upper_devicename Status
    update_interval: never
    icon: "mdi:information-variant"

  - platform: template # Expose the board type as a sensor
    id: espboard_type
    icon: "mdi:developer-board"
    name: $esphome_name ESPBoard
    lambda: |-
      return to_string("${esphome_board}");

# https://esphome.io/devices/nodemcu_esp32.html
# Enable On-Board Status LED.
status_led:
  pin:
    # Pin D2 / GPIO4
    number: GPIO04
    inverted: false

sensor:
  # Uptime sensor.
  - platform: uptime
    name: $upper_devicename Uptime

  # WiFi Signal sensor.
  - platform: wifi_signal
    name: $upper_devicename WiFi Signal
    update_interval: 60s

  # temperature sensor https://esphome.io/components/sensor/ntc.html using  a switch every 1 minute. Pull Upp GPIO16 (3.3V). prevents self-heating NTC
  - platform: ntc
    sensor: resistance_sensor
    name: $upper_devicename Temperature
    calibration:
      b_constant: 3950
      reference_temperature: 25°C
      reference_resistance: 10kOhm
  - platform: resistance
    id: resistance_sensor
    sensor: source_sensor
    configuration: DOWNSTREAM
    resistor: 10kOhm
    name: Resistance Sensor
    reference_voltage: 3.1V
  - platform: adc
    pin: A0
    id: source_sensor
    # Added:
    update_interval: never
    filters:
      - multiply: 3.3

interval:
  - interval: 60s
    then:
      - switch.turn_on: ntc_vcc
      - component.update: source_sensor
      - switch.turn_off: ntc_vcc
      - logger.log: "Measure Temp"

###############################################
# Configuration to set multiplier via number 
############################################### 
number:
  - platform: template
    id: $zone_1_valve_id
    name: $zone_1_name
    min_value: 1
    max_value: 60
    step: 1
    unit_of_measurement: $uom
    icon: "mdi:timer-outline"
    mode: box # Defines how the number should be displayed in the UI
    lambda: "return id($devicename).valve_run_duration(0);"
    set_action:
      - sprinkler.set_valve_run_duration:
          id: $devicename
          valve_number: 0
          run_duration: !lambda 'return x;'
  - platform: template
    id: $zone_2_valve_id
    name: $zone_2_name
    min_value: 1
    max_value: 60
    step: 1
    unit_of_measurement: $uom
    icon: "mdi:timer-outline"
    mode: box # Defines how the number should be displayed in the UI
    lambda: "return id($devicename).valve_run_duration(1);"
    set_action:
      - sprinkler.set_valve_run_duration:
          id: $devicename
          valve_number: 1
          run_duration: !lambda 'return x;'
  - platform: template
    id: $zone_3_valve_id
    name: $zone_3_name
    min_value: 1
    max_value: 60
    step: 1
    unit_of_measurement: $uom
    icon: "mdi:timer-outline"
    mode: box # Defines how the number should be displayed in the UI
    lambda: "return id($devicename).valve_run_duration(2);"
    set_action:
      - sprinkler.set_valve_run_duration:
          id: $devicename
          valve_number: 2
          run_duration: !lambda 'return x;'
  - platform: template
    id: $zone_4_valve_id
    name: $zone_4_name
    min_value: 1
    max_value: 60
    step: 1
    unit_of_measurement: $uom
    icon: "mdi:timer-outline"
    mode: box # Defines how the number should be displayed in the UI
    lambda: "return id($devicename).valve_run_duration(3);"
    set_action:
      - sprinkler.set_valve_run_duration:
          id: $devicename
          valve_number: 3
          run_duration: !lambda 'return x;'
  - platform: template
    id: $zone_5_valve_id
    name: $zone_5_name
    min_value: 1
    max_value: 60
    step: 1
    unit_of_measurement: $uom
    icon: "mdi:timer-outline"
    mode: box # Defines how the number should be displayed in the UI
    lambda: "return id($devicename).valve_run_duration(4);"
    set_action:
      - sprinkler.set_valve_run_duration:
          id: $devicename
          valve_number: 4
          run_duration: !lambda 'return x;'
###############################################
# Main Sprinkler Controller
###############################################
sprinkler:
  - id: $devicename
    main_switch:
      name: "Start/Stop/Resume"
      id: main_switch
    auto_advance_switch: "Auto Advance"
    valve_open_delay: 2s
    valves:
      - valve_switch: $zone_1_name
        enable_switch: Enable $zone_1_name
        run_duration: 15s
        valve_switch_id: ${devicename}_1
      - valve_switch: $zone_2_name
        enable_switch: Enable $zone_2_name
        run_duration: 15s
        valve_switch_id: ${devicename}_2
      - valve_switch: $zone_3_name
        enable_switch: Enable $zone_3_name
        run_duration: 15s
        valve_switch_id: ${devicename}_3
      - valve_switch: $zone_4_name
        enable_switch: Enable $zone_4_name
        run_duration: 15s
        valve_switch_id: ${devicename}_4
      - valve_switch: $zone_5_name
        enable_switch: Enable $zone_5_name
        run_duration: 15s
        valve_switch_id: ${devicename}_5 
 
button:
  - platform: template
    id: sprinkler_pause
    name: "Pause"
    icon: "mdi:pause"
    on_press:
      then:
        - text_sensor.template.publish:
            id: valve_status
            state: "Paused"
        - sprinkler.pause: $devicename


####################################################
# Switch Control to restart the irrigation system.   
####################################################
switch:
  - platform: restart
    name: "Restart $devicename"

# Switch for the NTC https://esphome.io/components/sensor/ntc.html, Prevent self heating by switching the voltage on a GPIO
  - platform: gpio
    pin: 
      number: GPIO5 #GPIO16 # Pin D0
      inverted: false
    id: ntc_vcc

####################################################
# Hidden I/O  Switches to control irrigation valve relays
####################################################
  - platform: gpio
    name: Relay Board Pin IN1
    restore_mode: RESTORE_DEFAULT_OFF # Prevents GPIO pin from going high during boot
    internal: true # Prevents GPIO switch NAME from showing up in Home Assistant
    id: ${devicename}_1
    on_turn_on:
      - text_sensor.template.publish:
          id: valve_status
          state: "$zone_1_name Active"
    on_turn_off:
      - text_sensor.template.publish:
          id: valve_status
          state: "Idle"
    pin: GPIO14 # D5
    inverted: true
  - platform: gpio
    name: Relay Board Pin IN2
    restore_mode: RESTORE_DEFAULT_OFF # Prevents GPIO pin from going high during boot
    internal: true # Prevents GPIO switch NAME from showing up in Home Assistant
    id: ${devicename}_2
    on_turn_on:
      - text_sensor.template.publish:
          id: valve_status
          state: "$zone_2_name Active"
    on_turn_off:
      - text_sensor.template.publish:
          id: valve_status
          state: "Idle"
    pin: GPIO12 # D6
    inverted: true
  - platform: gpio
    name: Relay Board Pin IN3
    restore_mode: RESTORE_DEFAULT_OFF # Prevents GPIO pin from going high during boot
    internal: true # Prevents GPIO switch NAME from showing up in Home Assistant
    id: ${devicename}_3
    on_turn_on:
      - text_sensor.template.publish:
          id: valve_status
          state: "$zone_3_name Active"
    on_turn_off:
      - text_sensor.template.publish:
          id: valve_status
          state: "Idle"
    pin: GPIO13 # D7
    inverted: true
  - platform: gpio
    name: Relay Board Pin IN4
    restore_mode: RESTORE_DEFAULT_OFF # Prevents GPIO pin from going high during boot
    internal: true # Prevents GPIO switch NAME from showing up in Home Assistant
    id: ${devicename}_4
    on_turn_on:
      - text_sensor.template.publish:
          id: valve_status
          state: "$zone_4_name Active"
    on_turn_off:
      - text_sensor.template.publish:
          id: valve_status
          state: "Idle"
    pin: GPIO15 # D8
    inverted: true
  - platform: gpio
    name: Relay Board Pin IN5
    restore_mode: RESTORE_DEFAULT_OFF # Prevents GPIO pin from going high during boot
    internal: true # Prevents GPIO switch NAME from showing up in Home Assistant
    id: ${devicename}_5
    on_turn_on:
      - text_sensor.template.publish:
          id: valve_status
          state: "$zone_5_name Active"
    on_turn_off:
      - text_sensor.template.publish:
          id: valve_status
          state: "Idle"
    pin: GPIO27 # D8
    inverted: true  

    # Example configuration entry v2

@Alaric ,

hi! after building, i find out that only one of the valves can be active. enabling all, and drip A - ON make drip B OFF and Start/Stop/Resume ON.

is it possible to have all active at the same time for different minutes for each?

thx in advance!

Update!
I actually installed the Controller yesterday, so it is ONLINE!


I have not done permanent mounting, wire cleanup yet, but I do have it working.

Comments/Questions:
I have setup the on-board LED as a “light”, and set up automations, that when each zone is running, led will flash x number of times (corresponding to the zone), then wait 2 seconds, and do it over and over until that zone stops, then next zone, etc… (ie: Zone 5, light turn on/off 5x, then pause and start again).

I have noted for a switch for the rain sensor, but the one I have appears to be dead (at least from checing w/multimeter). No biggie. What I am thinking of doing, is to build an automation that if precipitation = raining or > 0 in last two days (according to accuweather, etc…), then Pause/Stop irrigation system.

i have Scheduler setup to turn on controller on given day/set time…
Will system use whatever time i have setup the controller timers? If not, how can i setup th escheduled run giwith hard - coded timers by zone?

Ths

Lastly, OT (but kind of is on topic)… Is it me, or is Home Assistant like a “Black Hole”?
Hear me out (I don’t mean it in a bad way).
I had persisted testing it out for a while, but now that I am playing w/it, it can do so many things, that I can’t finish one thing I wan to try before I start downloading/setting up another feature, and next thing you know, I’ve been at it all day long!!!

That’s how the controller started… I had one zone that was not kicking on my existing system… had to dig ou the shovel to find the valves (what fun that was!!)… Anyway, Valve rebuild kit and new solenoid later, the valve is running, but the expansion module on the controller keeps going off-line… new modules are about $80.00.
I decided i could do this myself… i have time… jumpered the bad zone (5) onto zone 4 (run both valves at the same time)… and place order for what I was missing on Ali (relays, esp32’s)… got them within 2 weeks…

Now i want to throw the kitchen sink into HA… Any ideas for fun ESP32 projects for HA???

thanks all!

is there a way to start all valves at the same time or is the sequential necessary?

I’m staring in irrigation and am also a complete newbie in ESPHome. (used to mke it C or ESPEasy), so i have a lot of doubts…

thx in advance!

If your asking if all values can be operational at the same time, then I believe the answer would be no.

I just didn’t see where the water pump is triggered.

There are four valves, but water pump?

Hi can anyone help me to adapt this code for controlling 4 zones but I need to send a pulse (of 24V AC 2-3 Seconds) to turn on the valve and after the end of irrigation time send another pulse (of 24V AC 2-3 Seconds) to turn off the valve. Thank you!

Super
I tried to install it on a esp8266 , but when i tried to create the bin file with esphome i got a eror: max resor. Peaked, i dont know what is the problem .
Thanks for the help.

Regarding the ESP8266, i’m going on ESP32,more useable GPIO’s, more powerfull and almost the same price… will become my standard.

You know there is documentation for this, right? You dont have to rely on other people’s configs. You can do your own…

Sending a 24VAC pulse or any pulse is seperate from Sprinkler. How are you or how do you plan to physically send this pulse? These are locking solenoids? They dont turn off when you stop power? They lock open? There are locking and non locking available, just making sure you know which you got. Also, I assume you already have a transformer thats supplying the 24vac?

If you just take a step back and think about it. You nave an esp board with 3.3v gpio. You need to use a 3.3v to turn on/activate another switch thats controlling 24vac.
The most common way to do just that is with a relay, atleast in the DIY community. If you want to do it like professional irrigation controllers, then you could use a triac. They market it as an AC dimmer, which it can do but it also operates like an on/off switch.

Solid state relays
They come in single, 2 channel, 4, 8, and 16 channel too.
https://www.amazon.com/NOYITO-High-level-Automation-Industrial-Modification/dp/B07BLKJQYR/ref=asc_df_B07BLKJQYR/?tag=hyprod-20&linkCode=df0&hvadid=242027088707&hvpos=&hvnetw=g&hvrand=12740975851461331509&hvpone=&hvptwo=&hvqmt=&hvdev=m&hvdvcmdl=&hvlocint=&hvlocphy=9016042&hvtargid=pla-490223879492&psc=1&mcid=c5b91a4c0b113ec6a1b7e292f102a87f&gclid=CjwKCAiArfauBhApEiwAeoB7qDWKLo4ZxWhGeFgMx5O8iKGTtQtHAnZszvOFWGNQ9JvgLk9Byub7FxoCgfcQAvD_BwE

Mechanical relays.

Triac. Comes single, double, 4, 8 channel too.
https://www.amazon.com/GENUINE-RobotDYN-Programmable-Controller-Compatible/dp/B071X19VL1/ref=mp_s_a_1_2?crid=735GA5RRAVS5&dib=eyJ2IjoiMSJ9.0JTGterHb7XQmi1yNXK3xoI4LQQzptBoTG8c3AHX-_FO6bm-BPJzGWEgsprUMWpKRVyJgm5TpJtzY1dp33MafrpefX0lbBLzhcrTVDR3jF5I2TJ3fPQe3K4SgrZ19Cu6Kell5qFi9tjsdxlgwk1hkhwawkBiIKOgKyJ09UtP7_qVyyobNzzd2xRBcuoL18WF-bJhs4AXISMt-ofe2_umSQ.dHXDwk_BiRpBs4BpzaQG3IEirfAklVm7ZLI36rLZuEg&dib_tag=se&keywords=triac+dimmer+module+arduino&qid=1709058214&sprefix=arduino+triac%2Caps%2C191&sr=8-2

Now you know your hardware options. Next configure it in esphome. You need a…gpio…switch…makes sense, right? They even give you examples for adding delays wirh the turn on and turn off action, exactly what you need.

1 Like

can you post the error log?

I only have some drip irrigation zones i made for my flower beds. It was only meant to be a trial and then id permanently install it but, you know how those things go… So, if it helps someone or gives someone an idea… here you go.
Its 5 zones controlled by 5 12v solenoids. Theres a “main valve/solenoid” under the house and it feeds water to the valve hub and additional garden hose hookups. Theres also a flow meter at the beginning and that serves two purposes. I can see how much water im using in the summer and keep the water company honest! It also serves as a sensor so that if for whatever reason the water doesnt get turned off, it will shut it off after a time period and send me an alert.

I used to have my lighting and valve coltrols together but i wanted to redo my control box because it was a mess and i didnt have room to expand it. I havnt gotten around to rebuilding it this winter but it will be similar to my outside light controller. Something else people might find useful is a 7 day rainfall sensor. This tracks the last 7 days and then resets. This is so im not watering the day after a 2" rain event or increase watering during summer droubts.


Hi, my name is Antonio and I’m Italian with “medium” English, so… sorry.
I’ve found this project and I build it with an ESP32 and a 8 relay module. I have a problem that I try to solve: when I give power to the system, the ESP32 does not connect to WiFi and, on the relay board, the LEDs of two zones light up. The ESP32 is seen by Home Assistant when I disconnect 5v, that go to VCC on relay board, from the ESP32: once it’s connected, I can reconnect the 5v. The problem is in case of restart after a blackout. Connection is very similar to @hermie project (one power supply for the relay board and one for the ESP32).
I’m just starting out with ESPHome and its hardware, so, like a newbie, I’m asking for your help.
Hoping to read you, thanks in advance.
Antonio

P.S. link to the 8 relay board https://www.amazon.it/dp/B06XQYFSHR?ref=ppx_yo2ov_dt_b_product_details&th=1