Cześć,
Can you share the valves you used? Looking for models available in Poland.
Hi Paul,
Thx for the feedback. Glad it’s working.
Please select the post that fixed it / solution.
Thx
The valves were installed a few years ago by a company specializing in irrigation systems. When my controller broke, I made my own and used what was already in the ground. So I’m not really sure what kind of valves they are. I had a Hunter Hydrawise controller.
Thanks, I also used your project, I added a schedule to it at the ESP level, I actually copied it from another project, if anyone wants I’ll be happy to share because I made such a “hybrid”.
it will work on any valves, it’s a matter of what you give to the COM of the relay. You have valves for 24VAC, you give 24VAC, you have 24VDC, you give 24VDC… etc.
I will be grateful for sharing
Siema! Of course we want you to share!
Hey there,
I’m using the sprinkler component in ESPHome as well. I’ve organized my 9 valves into 2 main controllers: one with 5 valves (no pump) and another with 4 valves (no pump). So far, everything works fine.
Within each main controller, there’s something like an “interlock,” so only one valve can be active at a time — perfect.
The issue comes when, by mistake, someone manually activates a valve or a full cycle in the other main controller. There’s no “interlock” between the two main controllers.
What I’d like is this:
If main controller 1 is active, and something on main controller 2 is turned on (a valve or the full cycle), then:
Pause main controller 1
Let main controller 2 run
Once everything on main controller 2 turns off, resume main controller 1
And the same the other way around.
I tried using the on_turn_on and on_turn_off triggers on the main controllers, but I’m getting this error:
ERROR Circular dependency detected! Please run with -v option to see what functions failed to complete.
Do you have any ideas on how to achieve this behavior?
Thank you so much!
EDIT: this is my code for the sprinkler
sprinkler:
- id: irrigatori_giardino
main_switch:
name: "Irrigatori"
id: "irrigatori_main"
icon: mdi:sprinkler
on_turn_on:
- light.turn_on: led_blue
on_turn_off:
- light.turn_off: led_blue
auto_advance_switch:
name: "Attiva Ciclo Irrigatori"
icon: mdi:fast-forward
multiplier_number:
name: "Moltiplica Durata Irrigatori"
min_value: 0.25
max_value: 2
step: 0.25
# repeat_number:
# name: "Ripetizioni Ciclo Irrigatori"
# min_value: 0
# max_value: 2
# step: 1
# icon: mdi:repeat-variant
next_prev_ignore_disabled: True
valves:
- valve_switch:
name: "Scale"
icon: mdi:sprinkler
enable_switch:
name: "Abilita Scale"
icon: mdi:water-check
run_duration_number:
name: "Minuti Scale"
unit_of_measurement: min
min_value: 10
step: 10
icon: mdi:wrench-clock
valve_switch_id: valve8
- valve_switch:
name: "Portici Dietro"
icon: mdi:sprinkler
enable_switch:
name: "Abilita Portici Dietro"
icon: mdi:water-check
run_duration_number:
name: "Minuti Portici Dietro"
unit_of_measurement: min
min_value: 10
step: 10
icon: mdi:wrench-clock
valve_switch_id: valve4
- valve_switch:
name: "Portici Davanti"
icon: mdi:sprinkler
enable_switch:
name: "Abilita Portici Davanti"
icon: mdi:water-check
run_duration_number:
name: "Minuti Portici Davanti"
unit_of_measurement: min
min_value: 10
step: 10
icon: mdi:wrench-clock
valve_switch_id: valve3
- valve_switch:
name: "Prato Davanti"
icon: mdi:sprinkler
enable_switch:
name: "Abilita Prato Davanti"
icon: mdi:water-check
run_duration_number:
name: "Minuti Prato Davanti"
unit_of_measurement: min
min_value: 10
step: 10
icon: mdi:wrench-clock
valve_switch_id: valve2
- valve_switch:
name: "Prato Dietro"
icon: mdi:sprinkler
enable_switch:
name: "Abilita Prato Dietro"
icon: mdi:water-check
run_duration_number:
name: "Minuti Prato Dietro"
unit_of_measurement: min
min_value: 10
step: 10
icon: mdi:wrench-clock
valve_switch_id: valve1
- id: goccia_giardino
main_switch:
name: "Goccia a Goccia"
id: "goccia_main"
on_turn_on:
- light.turn_on: led_blue
on_turn_off:
- light.turn_off: led_blue
icon: mdi:water
auto_advance_switch:
name: "Attiva Ciclo Goccia a Goccia"
icon: mdi:fast-forward
multiplier_number:
name: "Moltiplica Durata Goccia a Goccia"
min_value: 0.25
max_value: 2
step: 0.25
# repeat_number:
# name: "Ripetizioni Ciclo Goccia a Goccia"
# min_value: 0
# max_value: 2
# step: 1
# icon: mdi:repeat-variant
next_prev_ignore_disabled: True
valves:
- valve_switch:
name: "Scalinata SX"
icon: mdi:water
enable_switch:
name: "Abilita Scalinata SX"
icon: mdi:water-check
run_duration_number:
name: "Minuti Scalinata SX"
unit_of_measurement: min
min_value: 10
step: 10
icon: mdi:wrench-clock
valve_switch_id: valve5
- valve_switch:
name: "Scalinata DX"
icon: mdi:water
enable_switch:
name: "Abilita Scalinata DX"
icon: mdi:water-check
run_duration_number:
name: "Minuti Scalinata DX"
unit_of_measurement: min
min_value: 10
step: 10
icon: mdi:wrench-clock
valve_switch_id: valve6
- valve_switch:
name: "Orto"
icon: mdi:water
enable_switch:
name: "Abilita Orto"
icon: mdi:water-check
run_duration_number:
name: "Minuti Orto"
unit_of_measurement: min
min_value: 10
step: 10
icon: mdi:wrench-clock
valve_switch_id: valve7
- valve_switch:
name: "Circuito"
icon: mdi:water
enable_switch:
name: "Abilita Circuito"
icon: mdi:water-check
run_duration_number:
name: "Minuti Circuito"
unit_of_measurement: min
min_value: 10
step: 10
icon: mdi:wrench-clock
valve_switch_id: valve9
Why did you split it up? Is it due to a hardware limitation?
I think your best approach is to have a supervisor outside of the two devices. That is, control the behaviour from HA.
Did you post the code you’re getting the error for? I only see lights turned on and off for the handlers you’ve mentioned.
hey @parautenbach thank you for your reply!
I split it up because the first 5 valves are 1 hour each minimum and it takes the whole night. The second main controller runs the following night.
The code I got the error is:
sprinkler:
- id: irrigatori_giardino
main_switch:
name: "Irrigatori"
id: "irrigatori_main"
icon: mdi:sprinkler
on_turn_on:
- light.turn_on: led_blue
- sprinkler.pause: goccia_giardino
on_turn_off:
- light.turn_off: led_blue
- sprinkler.resume: goccia_giardino
.....
- id: goccia_giardino
main_switch:
name: "Goccia a Goccia"
id: "goccia_main"
on_turn_on:
- light.turn_on: led_blue
- sprinkler.pause: irrigatori_giardino
on_turn_off:
- light.turn_off: led_blue
- sprinkler.resume: irrigatori_giardino
icon: mdi:water
It is just a call of sprinkler.pause and sprinkler.resume and I don’t really see how they could generate a loop.
I have an input_boolean in Home Assistant linked to esphome and it controls the pause for both the controllers.
- platform: homeassistant
id: pause_irrigation
entity_id: input_boolean.pausa_irrigazione
on_turn_on:
then:
- sprinkler.pause: irrigatori_giardino
- sprinkler.pause: goccia_giardino
on_turn_off:
then:
- sprinkler.resume: irrigatori_giardino
- sprinkler.resume: goccia_giardino
if there is nothing to pause/resume, it just doesn’t do anything and the log shows “no valve to resume”, so… I don’t get what it could be the problem.
Anyway, I can of course handle it with Home Assistant, but I would like to understand what is the problem and how to address it.
I’ve glanced at the code. It uses an FSM (finite state machine). You can see that there’s no paused state really as such.
Also note the comment on the pause() function. It’s the same as shutting down, but just saving some additional state, which you can see here.
So, what I think is happening, is that when you invoke sprinkler.pause for the first sprinkler, it triggers the on_turn_off automation for the first sprinkler, which then causes the first to pause the second, but the second will now trigger the first, etc.
The only way to really resolve a tie like this is as I said before: conceptually, you need to control this independently. I would personally not use your alternative of the ESPHome device accessing an HA helper – this seems backwards to me. Just have an automation in HA to monitor the sprinkler states and act accordingly: If the one turns on, turn the other off and you’re done.
Btw, did you try this with the -v option to get more details?
EDIT: One more point. If you want to insist on doing it on the device, you could try to write a lambda that checks if there is a paused valve to break the loop. Search for " …determine if the sprinkler controller is paused and, if so, which valve is paused?" in the docs.
thank you very much for your explanation
it makes a lot of sense now.
I am not that good in coding, actually I never studied it nor tried to learn it in a proper way. I just try to make my things work.
I don’t want to insist on doing it on the device, I thought it was easier to invoce directly the sprinkler.pause inside esphome. I will work on HA. I am very new in esphome, actually this is my first project.
so, I ended up with 2 separated switch template to pause the main controllers:
switch:
- platform: template
name: "Pausa Irrigatori"
id: pausa_irrigatori
optimistic: True
icon: mdi:play-pause
turn_on_action:
- sprinkler.pause: irrigatori_giardino
turn_off_action:
- sprinkler.resume: irrigatori_giardino
- platform: template
name: "Pausa Goccia a Goccia"
id: pausa_goccia
optimistic: True
icon: mdi:play-pause
turn_on_action:
- sprinkler.pause: goccia_giardino
turn_off_action:
- sprinkler.resume: goccia_giardino
and a simple automation in home assistant that takes care of the “interlock”:
alias: Interlock irrigazione
description: ""
triggers:
- trigger: state
entity_id:
- switch.4ch_pro_goccia_a_goccia
to: "on"
id: goccia_on
- trigger: state
entity_id:
- switch.4ch_pro_goccia_a_goccia
to: "off"
id: goccia_off
- trigger: state
entity_id:
- switch.4ch_pro_irrigatori
to: "on"
id: irrigatori_on
- trigger: state
entity_id:
- switch.4ch_pro_irrigatori
to: "off"
id: irrigatori_off
conditions: []
actions:
- choose:
- conditions:
- condition: trigger
id:
- goccia_on
- condition: state
entity_id: switch.4ch_pro_irrigatori
state: "on"
sequence:
- action: switch.turn_on
metadata: {}
data: {}
target:
entity_id: switch.4ch_pro_pausa_irrigatori
- choose:
- conditions:
- condition: trigger
id:
- goccia_off
- condition: state
entity_id: switch.4ch_pro_pausa_irrigatori
state: "on"
sequence:
- action: switch.turn_off
metadata: {}
data: {}
target:
entity_id: switch.4ch_pro_pausa_irrigatori
- choose:
- conditions:
- condition: trigger
id:
- irrigatori_on
- condition: state
entity_id: switch.4ch_pro_goccia_a_goccia
state: "on"
sequence:
- action: switch.turn_on
metadata: {}
data: {}
target:
entity_id: switch.4ch_pro_pausa_goccia_a_goccia
- choose:
- conditions:
- condition: trigger
id:
- irrigatori_off
- condition: state
entity_id: switch.4ch_pro_pausa_goccia_a_goccia
state: "on"
sequence:
- action: switch.turn_off
metadata: {}
data: {}
target:
entity_id: switch.4ch_pro_pausa_goccia_a_goccia
mode: single
thanks for your help ![]()
You’re welcome.
You did very well.
I get why you wanted to do it that way, and normally I’d agree it’s best to keep your logic on the device to allow it to work standalone (in this case, without HA). It’s just that this is a tricky scenario.
that was the reason, exactly. But… since the schedules to run the sprinklers are inside home assistant, there is no webserver on the device and no phisical buttons to start the cycles, it is impossible to run the 2 main controllers or any valves if HA in not running. And if HA is running, there is the HA automation to take care of it.
# Processing irrigation (board: nodemcuv2; framework: arduino; platform: platformio/[email protected])
# --------------------------------------------------------------------------------
# HARDWARE: ESP8266 80MHz, 80KB RAM, 4MB Flash
# 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 06 06 V08
# adjusted settings for valves corresponding to switches
# added repeat function
# 2024 04 04 V09
# Corrected the value of KEY ESPHOME_PROJECT_VERSION due to compiling error esphome v2024.3.1
# initializer-string for 'char [30]' is too long
# changed 2023 06 06 V08 to 20240404_V09
# removed the text "Irrigation Controller.,"
# 2025 03 12 V10
# breaking change, configure platform explicitly
# Establish Substitutions
substitutions:
### Modify only the following 6 lines.
zone_1_name: Zraszacze A
zone_2_name: Zraszacze B
zone_3_name: Zraszacze C
zone_4_name: Linia kroplujaca
software_version: 20240404_V09
sensor_update_frequency: 1s
log_level: debug # Enable levels logging https://esphome.io/components/logger.html
# none, error, warn, info, debug (default), verbose, very_verbose
##############################################
# 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
esphome_name: nawadnianie
esphome_board: esp32dev
esphome_comment: Czterozaworowy sterownik nawadniania
esphome_project_name: jaya.Irrigation Controller
esphome_project_version: $software_version
devicename: ESP32_sterownik
upper_devicename: "Podlewanie"
uom: Min # this overrides the uom in sprinkler -> run_duration
#Define Project Deatils and ESP Board Type
esphome:
name: $esphome_name
friendly_name: ESP32 Nawadnianie
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
esp32:
board: $esphome_board
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: "PhsY6ZYdhDyg"
logger:
level: ${log_level}
logs:
text_sensor: WARN
ota:
- platform: esphome
password: "3a27fcf74514c0454edf0e1110f6bd56"
# Enable Web server.
web_server:
port: 80
###############################################
# Enable Home Assistant API
###############################################
api:
encryption:
key:
###############################################
# 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
###############################################
# Text sensors with general information.
###############################################
text_sensor:
- platform: version # Expose ESPHome version as sensor.
name: $upper_devicename ESPHome Version
hide_timestamp: false
- platform: wifi_info
ip_address:
name: "$upper_devicename IP"
ssid:
name: "$upper_devicename SSID"
bssid:
name: "$upper_devicename BSSID"
# Expose Time Remaining as a sensor.
- platform: template
id: time_remaining
name: $upper_devicename Pozostały Czas
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 Postęp %
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"
entity_category: "diagnostic"
name: $upper_devicename ESPBoard
lambda: |-
return to_string("${esphome_board}");
sensor:
- platform: wifi_signal # Reports the WiFi signal strength/RSSI in dB
name: "WiFi Signal dB"
id: wifi_signal_db
update_interval: 60s
entity_category: "diagnostic"
- platform: copy # Reports the WiFi signal strength in %
source_id: wifi_signal_db
name: "WiFi Signal Percent"
filters:
- lambda: return min(max(2 * (x + 100.0), 0.0), 100.0);
unit_of_measurement: "%"
entity_category: "diagnostic"
- platform: uptime
name: Uptime
entity_category: "diagnostic"
###############################################
# 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: sprinkler_ctrlr_repeat_cycles
name: "Sprinkler Repeat Cycles"
min_value: 0
max_value: 4
step: 1
mode: box
icon: "mdi:water-sync"
lambda: "return id($devicename).repeat();"
set_action:
- sprinkler.set_repeat:
id: $devicename
repeat: !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
repeat_number: "Repeat"
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: 10s
valve_switch_id: ${devicename}_3
- valve_switch: $zone_4_name
enable_switch: Enable $zone_4_name
run_duration: 10s
valve_switch_id: ${devicename}_4
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:
# day of week toggle switches
- platform: template
id: ${devicename}_sunday
name: Sunday
icon: "mdi:calendar-range"
entity_category: config
restore_mode: RESTORE_DEFAULT_ON
optimistic: true
- platform: template
id: ${devicename}_monday
name: Monday
icon: "mdi:calendar-range"
entity_category: config
restore_mode: RESTORE_DEFAULT_ON
optimistic: true
- platform: template
id: ${devicename}_tuesday
name: Tuesday
icon: "mdi:calendar-range"
entity_category: config
restore_mode: RESTORE_DEFAULT_ON
optimistic: true
- platform: template
id: ${devicename}_wednesday
name: Wednesday
icon: "mdi:calendar-range"
entity_category: config
restore_mode: RESTORE_DEFAULT_ON
optimistic: true
- platform: template
id: ${devicename}_thursday
name: Thursday
icon: "mdi:calendar-range"
entity_category: config
restore_mode: RESTORE_DEFAULT_ON
optimistic: true
- platform: template
id: ${devicename}_friday
name: Friday
icon: "mdi:calendar-range"
entity_category: config
restore_mode: RESTORE_DEFAULT_ON
optimistic: true
- platform: template
id: ${devicename}_saturday
name: Saturday
icon: "mdi:calendar-range"
entity_category: config
restore_mode: RESTORE_DEFAULT_ON
optimistic: true
- platform: restart
name: "Restart $upper_devicename"
# scheduled time enable switches
- platform: template
id: ${devicename}_schedule1_enabled
name: Enable Schedule 1
icon: "mdi:clock-outline"
entity_category: config
restore_mode: RESTORE_DEFAULT_ON
optimistic: true
- platform: template
id: ${devicename}_schedule2_enabled
name: Enable Schedule 2
icon: "mdi:clock-outline"
entity_category: config
restore_mode: RESTORE_DEFAULT_ON
optimistic: true
- platform: template
id: ${devicename}_schedule3_enabled
name: Enable Schedule 3
icon: "mdi:clock-outline"
entity_category: config
restore_mode: RESTORE_DEFAULT_ON
optimistic: true
# rain delay switches (can be cancelled, auto-resetting)
- platform: template
id: ${devicename}_raindelay_24h_enabled
name: Enable 24h Rain Delay
icon: "mdi:weather-cloudy-clock"
restore_mode: RESTORE_DEFAULT_OFF
optimistic: true
turn_on_action:
then:
- delay:
hours: 24
- switch.turn_off: ${devicename}_raindelay_24h_enabled
- platform: template
id: ${devicename}_raindelay_48h_enabled
name: Enable 48h Rain Delay
icon: "mdi:weather-cloudy-clock"
restore_mode: RESTORE_DEFAULT_OFF
optimistic: true
turn_on_action:
then:
- delay:
hours: 48
- switch.turn_off: ${devicename}_raindelay_48h_enabled
####################################################
# 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 Aktywne"
on_turn_off:
- text_sensor.template.publish:
id: valve_status
state: "Brak"
pin: GPIO16 # D5
- 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 Aktywne"
on_turn_off:
- text_sensor.template.publish:
id: valve_status
state: "Brak"
pin: GPIO17 # D6
- 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 Aktywne"
on_turn_off:
- text_sensor.template.publish:
id: valve_status
state: "Brak"
pin: GPIO18 # D7
- 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 Aktywne"
on_turn_off:
- text_sensor.template.publish:
id: valve_status
state: "Brak"
pin: GPIO19 # D8
datetime:
- platform: template
name: Schedule 1 Start Time
entity_category: config
id: ${devicename}_s1t
type: time
optimistic: true
restore_value: true
- platform: template
name: Schedule 2 Start Time
entity_category: config
id: ${devicename}_s2t
type: time
optimistic: true
restore_value: true
- platform: template
name: Schedule 3 Start Time
entity_category: config
id: ${devicename}_s3t
type: time
optimistic: true
restore_value: true
# set up time and check every minute (or second) for scheduled actions
time:
- platform: homeassistant
id: ha_time
on_time:
# Every 1 minute
- seconds: 0
minutes: /1
then:
- script.execute: ${devicename}_script1
on_time_sync:
then:
- logger.log: "Synchronized system clock"
script:
# check what day of the week it is currently, and if we have the schedule enabled today
- id: ${devicename}_script1
then:
lambda: |-
int dow = id(ha_time).now().day_of_week;
if ((dow == 1 && id(${devicename}_sunday).state == true)
|| (dow == 2 && id(${devicename}_monday).state == true)
|| (dow == 3 && id(${devicename}_tuesday).state == true)
|| (dow == 4 && id(${devicename}_wednesday).state == true)
|| (dow == 5 && id(${devicename}_thursday).state == true)
|| (dow == 6 && id(${devicename}_friday).state == true)
|| (dow == 7 && id(${devicename}_saturday).state == true)) {
id(${devicename}_script2).execute();
}
# if current time is equal to any of the scheduled start times, start the sprinkler cycle
- id: ${devicename}_script2
then:
lambda: |-
int hour = id(ha_time).now().hour;
int minute = id(ha_time).now().minute;
if ((hour == id(${devicename}_s1t).hour && minute == id(${devicename}_s1t).minute && id(${devicename}_schedule1_enabled).state == true && id(${devicename}_raindelay_24h_enabled).state == false && id(${devicename}_raindelay_48h_enabled).state == false)
|| (hour == id(${devicename}_s2t).hour && minute == id(${devicename}_s2t).minute && id(${devicename}_schedule2_enabled).state == true && id(${devicename}_raindelay_24h_enabled).state == false && id(${devicename}_raindelay_48h_enabled).state == false)
|| (hour == id(${devicename}_s3t).hour && minute == id(${devicename}_s3t).minute && id(${devicename}_schedule3_enabled).state == true && id(${devicename}_raindelay_24h_enabled).state == false && id(${devicename}_raindelay_48h_enabled).state == false)) {
id(${devicename}_script3).execute();
}
# start the sprinkler cycle
- id: ${devicename}_script3
then:
- sprinkler.start_full_cycle: ${devicename}
- lambda: ESP_LOGI("main", "Sprinkler cycle has begun!");
Impossible? Absolutely not Impossible. Esphome is made to run independently and only requires HA if that’s how you set it up to be.
Nope, they arent inside HA. There are ways to use HA to create an irrigation schedule just like there’s an option to create a schedule in Esphome. You should really read the documentation and start learning or else you’ll always be new to this.
Why is there no webserver? You set up a web server so it’s there. Do you just not know how to use it? You should probably consider adding some physical buttons and even an LCD screen and you might want a rotary encoder too.
I would also strongly suggest ditching the 2 controller configuration your doing now and put everything under a single controller.
It’s not illegal to split up watering over 2 days of you have to and just water 1 section today, other section tomorrow and just stagger them like that or however you need to even if its beginning of the week and end of the week, it doesnt matter and actually can help with mowing too. Also, you mentioned zones taking all night to finish… You really dont want to be doing any irritating at night. You want the foliage to have enough time to dry before the sun sets or else you greatly increase the risk for getting nasty fungal infections, especially during warm and humid nights, your just asking for trouble! You always want to try doing early morning watering and if you need to water 2x day then your second should be during late afternoon so that you still have a few hours of sunshine to dry out the foliage before dark.
Another thing to consider is adding a flow meter to the water main that feeds your irrigation. This will help you catch leaks as soon as they happen as well as monitor and/or log your water use for irrigation.
Creating or importing a HA sensor that will check for rain or high probability of rain forecasted and also accumulated rain total over past however many days so that you can dial the water back if for example it rained 3" over the last 4 days and you can take necessary steps with your system to adjust it up or down based on relevant factors.
Thank you for your reply. I am repurposing an old Orbit irrigation system that was damaged during a thunderstorm. I had a Sonoff 4CH Pro installed right beneath it, so I created an extension inside the Orbit unit to drive the original triacs that control the 10 valves I have.
Just a few considerations:
-
I don’t need the webserver, so I didn’t include it.
-
I don’t need any physical buttons, LCD, or encoder — I had them with the Orbit irrigation system, but I much prefer to control everything from my tablet, phone, or PC.
-
I will keep the two main controllers — it’s more logical this way. Every irrigation system, including the Orbit, uses “groups” to manage different schedules.
-
I know I could include the scheduling inside the ESP, but I deliberately chose not to. It’s much easier to create the schedule I need with all the specific conditions I require, such as weather forecasts, humidity, guest presence, and so on.
-
I cannot run the irrigation during the day/early morning for several reasons, including the fact that guests use the lawn until the evening — and I can’t splash them!
-
There isn’t enough time in the early morning to complete the full schedule.
-
The flow meter is already integrated into Home Assistant.
-
It’s impossible to run the two main controllers at the same time with the current arrangement of my system, and I’m not planning to change it. Only Home Assistant is allowed to run them. Remember: no buttons, no encoder, no internal schedules.
-
I read the doc

Yes, I’m aware that ideally the system should be able to run independently in case Home Assistant goes down — but Home Assistant is more critical than the irrigation system, as it handles many other services. So if something happens, I’ll have to restore Home Assistant within a few hours at most, and I’ve made plans to be able to do that. It is just time consuming to realize a system that run by itself if HA doesn’t work.
You don’t? What happens if your hardware running HA fails or maybe the hard drive goes out? How do you plan to access your irrigation system if you needed to?
Which is just an alternative to saying “zones” and refers to the group of heads for each valve. An additional controller wouldn’t be a group because It controls 1 or more groups.
That would be perfectly logical if Esphome didn’t have all those capabilities but, it does.
guests are using the lawn at from 3am - 7am when every other business or sports field runs their irrigation? Are “guests” a group of homeless people sleeping in tents on the lawn?
You have to complete the entire cycle in one day? What happens if it starts pouring rain? You gioing to let it keep running because splitting the irrigation job up is unthinkable?
Just 1 flow meter? That sounds really cute!
I’m not sure why you think you must run both of them simultaneously but, since you won’t ever, not even in a million years or if it could save lives, you’re not gonna change it then… OK…
So no backup or manual shutoff option in case of emergency and your not there or unavailable? Sounds like a good idea!
I never forget anything, especially when I hear good ideas!
UUmm… No, It would take roughly the same amount of time to create automations in Esphome as it would in HA plus, you could still change any configuration options in the automations right from the HA UI and it would be a redundant way to have access to the controller but, things never crash or break so, why bother doing all that work!
You really should use your bitter sarcasm elsewhere
— it doesn’t help to have a proper discussion.
As I wrote, for me it’s more time-consuming to create a fail-safe system inside the ESP. If Home Assistant fails, I have bigger problems than worrying about the irrigation system. Since I would need to restore HA immediately, the irrigation system would be restored at the same time anyway.
I know ESPHome has the ability to handle all these conditions, but I already have them configured from my previous system, so again, it’s easier and faster this way.
3–7 AM is nighttime — that’s when my irrigation system runs.
My guests aren’t homeless — they’re staying at my place for vacation. They often have dinner in the garden or spend the evening/night outside enjoying wine or drinks until late.
And yes, it’s just one flow meter. The system was built decades ago, and it’s not easy or cheap (or even possible) to upgrade everything. I do the best I can with what I have. You shouldn’t judge others without knowing the full context.
So, all in all, it’s a matter of balancing the ideal system, the time required to build it, and the actual likelihood of the worst-case scenario.
You talk about an ideal, fail-proof system. I talk about a good compromise, considering the real situation and my needs.
Thanks for sharing your point of view, by the way.
