Sprinkler automation with ESPHome, a complete project

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”.

1 Like

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 :slight_smile: 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.

1 Like

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 :slight_smile:

1 Like

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.

1 Like