Entities
Here’s a summary of all the entities required for this 5-zone controller:
- One timer to countdown a zone’s duration.
- One counter to keep track of which zone to process.
- One input_select to control overall operation (on/off/pause).
- One group containing all the zone switches.
- Five input_booleans, one per zone to indicate its enabled/disabled status.
- Five input_datetimes, one per zone to indicate its duration (in hours and minutes).
- Five more input_booleans, one per zone representing each zone switch (controlling a valve in an irrigation system).
Note that the last set of 5 input_booleans should be 5 switches. However, for demonstration purposes, it’s easier to use input_booleans. After you have finished experimenting with this example, you can modify its code to control actual switches as opposed to input_booleans.
Here’s the configuration for all of the entities.
Summary
counter:
zone:
initial: 0
step: 1
input_select:
controller_mode:
name: Zone Controller Mode
options:
- 'off'
- 'on'
- 'pause'
input_boolean:
zone_1:
name: Zone 1
zone_2:
name: Zone 2
zone_3:
name: Zone 3
zone_4:
name: Zone 4
zone_5:
name: Zone 5
switch_zone_1:
name: "Switch Zone 1"
switch_zone_2:
name: "Switch Zone 2"
switch_zone_3:
name: "Switch Zone 3"
switch_zone_4:
name: "Switch Zone 4"
switch_zone_5:
name: "Switch Zone 5"
input_datetime:
zone_1:
name: Zone 1
has_date: false
has_time: true
zone_2:
name: Zone 2
has_date: false
has_time: true
zone_3:
name: Zone 3
has_date: false
has_time: true
zone_4:
name: Zone 4
has_date: false
has_time: true
zone_5:
name: Zone 5
has_date: false
has_time: true
group:
zones:
name: Zones All
entities:
- input_boolean.switch_zone_1
- input_boolean.switch_zone_2
- input_boolean.switch_zone_3
- input_boolean.switch_zone_4
- input_boolean.switch_zone_5
Automation
The single automation contains about 130 lines of YAML. It uses three triggers:
-
State Trigger for the input_select which governs the controller’s operation (on/off/pause).
-
State Trigger for the counter which is used to step through the five zones.
-
Event Trigger for the timer which is used to control a zone’s operation.
The automation’s mode is queued
because it performs actions that will cause it to be triggered (i.e. it calls itself).
Summary
- alias: Zone Controller
id: zone_controller
mode: queued
variables:
zone_max: 5
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: "input_boolean.switch_zone_{{ z_index }}"
z_mode: "input_boolean.zone_{{ z_index }}"
z_duration: "input_datetime.zone_{{ z_index }}"
- choose:
- conditions: "{{ trigger.id == 'controller_mode' }}"
sequence:
- choose:
- conditions: "{{ trigger.to_state.state == 'on' }}"
sequence:
- choose:
- conditions: "{{ z_index == 0 }}"
sequence:
- service: counter.increment
target:
entity_id: counter.zone
- conditions: "{{ z_index <= zone_max and trigger.from_state.state == 'pause' }}"
sequence:
- service: timer.start
target:
entity_id: timer.zone
default:
- service: counter.reset
target:
entity_id: counter.zone
- conditions: "{{ trigger.to_state.state == 'off' }}"
sequence:
- service: homeassistant.turn_off
target:
entity_id: group.zones
- service: timer.cancel
target:
entity_id: timer.zone
- conditions: "{{ 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: "{{ trigger.id == 'zone_index' }}"
sequence:
- choose:
- conditions: "{{ z_index == 0 }}"
sequence:
- service: input_select.select_option
target:
entity_id: input_select.controller_mode
data:
option: 'off'
- conditions: "{{ z_index <= zone_max }}"
sequence:
- choose:
- conditions: "{{ 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:
- "{{ trigger.id == 'zone_timer' }}"
- "{{ z_index != 0 }}"
sequence:
- choose:
- conditions: "{{ trigger.event.event_type in ['timer.started', 'timer.restarted'] }}"
sequence:
- service: input_boolean.turn_on
target:
entity_id: "{{ z_switch }}"
- conditions: "{{ trigger.event.event_type == 'timer.paused' }}"
sequence:
- service: input_boolean.turn_off
target:
entity_id: "{{ z_switch }}"
- conditions: "{{ trigger.event.event_type == 'timer.cancelled' }}"
sequence:
- service: input_boolean.turn_off
target:
entity_id: "{{ z_switch }}"
- service: counter.reset
target:
entity_id: counter.zone
- conditions: "{{ trigger.event.event_type == 'timer.finished' }}"
sequence:
- service: input_boolean.turn_off
target:
entity_id: "{{ z_switch }}"
- service: counter.increment
target:
entity_id: counter.zone
Lovelace UI
I have prepared four Entities Cards in order to display all the zones and control their operation. They are all within a view called Zone Controller (so paste the YAML code under views:
when using Lovelace’s Raw Configuration Editor … or build the cards from scratch).
Summary
- title: Zone Controller
path: zone-controller
badges: []
cards:
- type: entities
entities:
- entity: input_boolean.zone_1
- entity: input_boolean.zone_2
- entity: input_boolean.zone_3
- entity: input_boolean.zone_4
- entity: input_boolean.zone_5
title: Zone Mode
show_header_toggle: false
- type: entities
entities:
- entity: input_datetime.zone_1
- entity: input_datetime.zone_2
- entity: input_datetime.zone_3
- entity: input_datetime.zone_4
- entity: input_datetime.zone_5
title: Zone Duration
- type: entities
entities:
- entity: input_boolean.switch_zone_1
- entity: input_boolean.switch_zone_2
- entity: input_boolean.switch_zone_3
- entity: input_boolean.switch_zone_4
- entity: input_boolean.switch_zone_5
title: Zone Switch
show_header_toggle: false
- type: entities
entities:
- entity: input_select.controller_mode
- entity: counter.zone
- entity: timer.zone
title: Controller
Here’s a screenshot of the UI with the controller in operation. Only zones 1, 2, and 5 are enabled. Each one is set to run for just 1 minute. It has already completed zone 1 and is currently working on zone 2 (you can see Switch Zone 2 is on
and the zone counter indicates 2
). The timer shows there are 35 seconds remaining before zone 2 is turned off and it moves on to activate zone 5.
Operation
In the Zone Modes card, set a few zones to on
. The values you set will survive a restart (i.e. they will not reset to off
).
In the Zone Duration card, set the input_datetimes to whatever values you want. The values you set will survive a restart (i.e. they will not reset to 00:00
).
The Zone Switch card requires no configuration. It’s there just to show you which “Zone Switch” is currently in operation.
In the Controller card, set Zone Controller Mode to on
. It should immediately activate the Zone Switch corresponding to the first enabled Zone. The zone timer will display the remaining time.
While it’s operating, you can set the input_select to pause
and the currently activated zone will be deactivated and the timer paused. Set it back to on
and the zone will be re-activated and the timer will continue from where it left off. If you set it to off
it not only deactivates the current zone but, for good measure, turns off all zones (that’s what the group is used for). If you allow it to complete all enabled zones, it will automatically set the input_select to off
.
If the controller’s mode is off
and you set it to pause
, it automatically sets itself back to off
(because off → pause is a meaningless command).
NOTE
Rather than explain the automation’s operation step by step (a great deal of work), I would prefer to answer specific questions about it.
EDIT
Correction. Replaced non-existent service call “group.turn_off” with “homeassistant.turn_off”.