Sprinkler automation - Multiple switches, multiple times per day, on for x minutes, only one on at a time

Hey all…

I have 3 switches that I want on multiple times per day for x minutes, but the trick is that they cannot run at the same time.

For example:

Switch 1 - On from 6 AM - 6:30 AM
Switch 2 - On from 6:30 AM - 7 AM
Switch 3 - On from 7AM - 7:30 AM
Switch 1 - On from 12 PM - 12:30PM

I have this working now, but each switch/time combo is a separate automation and not the simplest to maintain. Any thoughts how I can pull this off in one automation?

Thanks!

I created a demo of a 5-zone controller for another user in the following post. It’s all done with a single automation. It’s easily reduced to 3 zones for your needs.

  • Set each one of the three zones to 30 minutes.
  • Create an automation with a Time Trigger set to 06:00, 12:00, etc that sets input_select.controller_mode to on.

When your automation triggers at 06:00 and enables the controller, it will turn on the first zone for 30 minutes, then turn it off and proceed to turn on the second zone for 30 minutes, etc. When all zones are done, it sets input_select.controller_mode to off.

The entire process is repeated at 12:00 and whatever other times you specify in the Time Trigger. Obviously the trigger times should be spaced at least 90 minutes apart (3 zones x 30 minutes/zone = 90 minutes).

Other features include the ability to manually pause the controller and to optionally disable a zone (which will make the controller skip that zone).

For demonstration purposes, it controls input_booleans. For real-world use, you simply need to replace the input_booleans with switches (that control your sprinkler valves). Let me know if you need help adapting it to your environment.

1 Like

Wow, this is awesome! This should do the trick I think. Ill play with it soon and let you know if there’s something I get stuck on.

Thanks so much!

If you cut it down to three zones be sure to change the value of zone_max from 5 to 3.

  variables:
    zone_max: 5

If you want to future-proof it (i.e. avoid having to change the value whenever you add a zone or two) you can replace it with a template that calculates the total quantity of entities within group.zones. Now you only have to add the new zone to the group without needing to update the automation.

  variables:
    zone_max: "{{ expand('group.zones') | count }}"
1 Like

A single automation can do this like

On 1
Delay xx
Off1
On2
Delay xx
Off2
On3……etc

Yeah, I suppose so, but was looking for something a bit more generic and parameterized so to say. Thanks.

I tried creating the automation and am getting “Message malformed: expected dictionary” upon saving. I copy/pasted it directly from the code in the thread above. Any ideas?

Edit:

Nevermind, I see the issue. The very first character in the yaml is a - that shouldnt be there.

It’s there because the assumption is that the user will copy-paste the entire example into automations.yaml. If you are copying it into the Automation Editor then, yes, you must remove it. After you click the Save button, the Automation Editor will store it in automations.yaml … and add a hyphen to it.

1 Like

Ah ok, didnt realize that.

Ok, so I got your example from the other thread working. I then went to modify it to toggle my actual sprinklers and its not working. It wont flip them on, etc. The three sprinklers I have are switch.sprinkler1 through 3.

Here is the automation code:

alias: Zone Controller
trigger:
  - id: controller_mode
    platform: state
    entity_id: input_select.controller_mode
  - id: zone_index
    platform: state
    entity_id: counter.zone
  - id: zone_timer
    platform: event
    event_type: timer.started,timer.finished,timer.paused,timer.restarted,timer.cancelled
    event_data:
      entity_id: timer.zone
action:
  - variables:
      z_index: '{{ states(''counter.zone'') | int }}'
      z_switch: switch.sprinkler{{ z_index }}
      z_mode: input_boolean.zone_{{ z_index }}
      z_duration: input_datetime.zone_{{ z_index }}
  - choose:
      - conditions:
          - condition: template
            value_template: '{{ trigger.id == ''controller_mode'' }}'
        sequence:
          - choose:
              - conditions:
                  - condition: template
                    value_template: '{{ trigger.to_state.state == ''on'' }}'
                sequence:
                  - choose:
                      - conditions:
                          - condition: template
                            value_template: '{{ z_index == 0 }}'
                        sequence:
                          - service: counter.increment
                            target:
                              entity_id: counter.zone
                      - conditions:
                          - condition: template
                            value_template: >-
                              {{ z_index <= zone_max and
                              trigger.from_state.state == 'pause' }}
                        sequence:
                          - service: timer.start
                            target:
                              entity_id: timer.zone
                            data:
                              duration: '0'
                    default:
                      - service: counter.reset
                        target:
                          entity_id: counter.zone
              - conditions:
                  - condition: template
                    value_template: '{{ trigger.to_state.state == ''off'' }}'
                sequence:
                  - service: group.turn_off
                    target:
                      entity_id: group.zones
                  - service: timer.cancel
                    target:
                      entity_id: timer.zone
              - conditions:
                  - condition: template
                    value_template: >-
                      {{ trigger.to_state.state == 'pause' and
                      trigger.from_state.state != 'off' }}
                sequence:
                  - service: timer.pause
                    target:
                      entity_id: timer.zone
            default:
              - service: input_select.select_option
                target:
                  entity_id: input_select.controller_mode
                data:
                  option: 'off'
      - conditions:
          - condition: template
            value_template: '{{ trigger.id == ''zone_index'' }}'
        sequence:
          - choose:
              - conditions:
                  - condition: template
                    value_template: '{{ z_index == 0 }}'
                sequence:
                  - service: input_select.select_option
                    target:
                      entity_id: input_select.controller_mode
                    data:
                      option: 'off'
              - conditions:
                  - condition: template
                    value_template: '{{ z_index <= zone_max }}'
                sequence:
                  - choose:
                      - conditions:
                          - condition: template
                            value_template: '{{ is_state(z_mode, ''on'') }}'
                        sequence:
                          - service: timer.start
                            target:
                              entity_id: timer.zone
                            data:
                              duration: '{{ state_attr(z_duration, ''timestamp'') }}'
                    default:
                      - service: counter.increment
                        target:
                          entity_id: counter.zone
            default:
              - service: counter.reset
                target:
                  entity_id: counter.zone
      - conditions:
          - condition: template
            value_template: '{{ trigger.id == ''zone_timer'' }}'
          - condition: template
            value_template: '{{ z_index != 0 }}'
        sequence:
          - choose:
              - conditions:
                  - condition: template
                    value_template: >-
                      {{ trigger.event.event_type in ['timer.started',
                      'timer.restarted'] }}
                sequence:
                  - service: switch.turn_on
                    target:
                      entity_id: '{{ z_switch }}'
              - conditions:
                  - condition: template
                    value_template: '{{ trigger.event.event_type == ''timer.paused'' }}'
                sequence:
                  - service: switch.turn_off
                    target:
                      entity_id: '{{ z_switch }}'
              - conditions:
                  - condition: template
                    value_template: '{{ trigger.event.event_type == ''timer.cancelled'' }}'
                sequence:
                  - service: switch.turn_off
                    target:
                      entity_id: '{{ z_switch }}'
                  - service: counter.reset
                    target:
                      entity_id: counter.zone
              - conditions:
                  - condition: template
                    value_template: '{{ trigger.event.event_type == ''timer.finished'' }}'
                sequence:
                  - service: switch.turn_off
                    target:
                      entity_id: '{{ z_switch }}'
                  - service: counter.increment
                    target:
                      entity_id: counter.zone
mode: queued
variables:
  zone_max: 3
max: 10

Basically I update the z_switch variable up top accordingly and then updated the 4 service calls that turn on/off the switch. Also here is my groups config:

zones:
  name: Zones All
  entities:
    - switch.sprinkler1
    - switch.sprinkler2
    - switch.sprinkler3

Any ideas?

I was able to replicate the failure you experienced. It’s this line in your version of the automation:

    event_type: timer.started,timer.finished,timer.paused,timer.restarted,timer.cancelled

I used that version of event_type and the Event Trigger failed to detect the timer’s events (which is crucial for controlling the operation of the switches).

A bit of background:

This is how you can define a list in YAML:

- timer.started
- timer.finished
- timer.paused
- timer.restarted
- timer.cancelled

Here’s the same list in JSON:

[ "timer.started", "timer.finished", "timer.paused", "timer.restarted", "timer.cancelled" ]

You’ll notice that the JSON equivalent is not this:

timer.started, timer.finished, timer.paused, timer.restarted, timer.cancelled

However, the Automation Editor converted the YAML version into that format, rendering Event Trigger useless for detecting a timer’s individual events. Why the Automation Editor does that is a separate discussion; the key point is that it shouldn’t do that for an Event Trigger.

Replace this:

    event_type: timer.started,timer.finished,timer.paused,timer.restarted,timer.cancelled

with this:

    event_type: [ "timer.started", "timer.finished", "timer.paused", "timer.restarted", "timer.cancelled" ]

That allows the Event Trigger to work properly and, I believe, the Automation Editor will leave it unchanged. If it still changes it then you will have to do what’s described below.


< soapbox >
This is one of several reasons I stopped using the Automation Editor a long time ago. It’s fine for composing simple automations but it has enough quirks, notably how it formats YAML according to an inflexible set of rules, that make it less than productive for complex automations. There’s an easy way to separate the automations you compose with a text editor from those composed with the Automation Editor and that’s what I have done. It prevents the Automation Editor from touching anything I create with a text editor (VS Code).
</ soapbox >


1 Like

Awesome, that fixed it. Thanks for the detailed explanation.

One other thing I noticed is that if I set the mode to Off, it doesnt actually turn off my switches nor does it cancel the timer or reset the zone to 0. Any ideas there? If its a total pain to fix, dont worry about it. I can work around that.

Thanks again!

That’s a legitimate bug. When I posted the original automation, I made a quick last-minute change from the version I was actually testing. I threw something in without much thought and, naturally, it proved to be wrong. :man_facepalming:

Change this line (a service call that doesn’t exist):

                  - service: group.turn_off

to this:

                  - service: homeassistant.turn_off

You’ll find that line here, where the controller mode gets set to off and is supposed to turn off all the switches and cancel the timer:

              - conditions:
                  - condition: template
                    value_template: '{{ trigger.to_state.state == ''off'' }}'
                sequence:
                  - service: group.turn_off   <-------- WRONG
                    target:
                      entity_id: group.zones
                  - service: timer.cancel
                    target:
                      entity_id: timer.zone

I’ll correct the automation in the other post.

1 Like

That did the trick. Thanks for all the help, this is exactly what I needed!