Then, list all running timers.
- conditions:
- condition: template
value_template: "{{ trigger.sentence == 'list timers' }}"
sequence:
- variables:
timers_set: >-
{{ states.timer | selectattr('entity_id', 'match', 'timer.auto*') | selectattr('state', 'ne', 'idle') | map(attribute='entity_id') | list | count > 0 }}
timer_ids: |-
{%- if timers_set -%}
{{ states.timer | selectattr('entity_id', 'match', 'timer.auto*') | selectattr('state', 'ne', 'idle') | map(attribute='entity_id') | list }}
{%- endif -%}
- if:
- condition: template
value_template: "{{ timers_set }}"
then:
- set_conversation_response: |-
{%- for timer in timer_ids %}
{%- set timer_text = '' -%}
{%- set timer_left = (as_datetime(state_attr(timer, 'finishes_at')) - now()).total_seconds() -%}
{%- set timer_hours = timer_left | timestamp_custom('%H', false) | int -%}
{%- set timer_minutes = timer_left | timestamp_custom('%M', false) | int -%}
{%- set timer_seconds = timer_left | timestamp_custom('%S', false) | int -%}
{%- set timer_text = timer_text ~ ' ' ~ timer_hours ~ ' hour' if timer_hours > 0 else timer_text -%}
{%- set timer_text = timer_text ~ 's' if timer_hours > 1 else timer_text -%}
{%- set timer_text = timer_text ~ ' ' ~ timer_minutes ~ ' minute' if timer_minutes > 0 else timer_text -%}
{%- set timer_text = timer_text ~ 's' if timer_minutes > 1 else timer_text -%}
{%- set timer_text = timer_text ~ ' ' ~ timer_seconds ~ ' second' if timer_seconds > 0 else timer_text -%}
{%- set timer_text = timer_text ~ 's' if timer_seconds > 1 else timer_text %}
{{ states(timer | replace('timer', 'input_text')).split('|')[0] }} timer has{{ timer_text }} left.
{%- endfor -%}
else:
- set_conversation_response: No timers are running
Show all timer commands to persistent notifications.
- conditions:
- condition: template
value_template: "{{ trigger.sentence.startswith('commands for timer') }}"
sequence:
- service: notify.persistent_notification
data:
message: |-
(start|set|reset) {timer_time} minute {timer_name} timer [{location}]
(start|set|reset) {timer_name} timer (to|for) {timer_time} minute[s] [{location}]
(cancel|stop|end) {timer_name} timer
pause {timer_name} timer
restart {timer_name} timer
list timers
commands for timer
- set_conversation_response: Timer commands sent to persistent notifications
On HA restart, loop through the input_text.auto* with saved off timer names and report any timers set to idle that they completed.
- conditions:
- condition: trigger
id:
- ha_restart
sequence:
- variables:
timers: "{{ states.timer | selectattr('entity_id', 'match', 'timer.auto*') | selectattr('state', 'eq', 'idle') | map(attribute='name') | list }}"
- repeat:
for_each: "{{ states.input_text | selectattr('entity_id', 'match', 'input_text.auto*') | rejectattr('state', 'match', 'auto*') | selectattr('name', 'in', timers) | map(attribute='entity_id') | list }}"
sequence:
- variables:
willow: "{{ states(repeat.item).split('|')[1] }}"
- if:
- condition: template
value_template: "{{ willow == '' }}"
then:
- service: rest_command.willow_notify_all
data:
audioUrl: "{{ 'https://wis.jeffcrum.com:19000/api/tts?text=' ~ states(repeat.item).split('|')[0] ~ '+timer+finished' }}"
backlight: true
backlightMax: true
repeat: 1
text: "{{ states(repeat.item).split('|')[0][0] | upper ~ states(repeat.item).split('|')[0][1:] | lower ~ ' timer finished' }}"
volume: 100
else:
- service: rest_command.willow_notify
data:
audioUrl: "{{ 'https://wis.jeffcrum.com:19000/api/tts?text=' ~ states(repeat.item).split('|')[0] ~ '+timer+finished' }}"
hostname: "{{ willow }}"
backlight: true
backlightMax: true
repeat: 1
text: "{{ states(repeat.item).split('|')[0][0] | upper ~ states(repeat.item).split('|')[0][1:] | lower ~ ' timer finished' }}"
volume: 100
- service: timer.start
target:
entity_id: "{{ repeat.item | replace('input_box', 'timer') }}"
data:
duration: "60"
enabled: false
- service: input_text.set_value
target:
entity_id: "{{ repeat.item }}"
data:
value: "{{ repeat.item.split('.')[1] }}"
Then, timer finished
- conditions:
- condition: trigger
id:
- finished
sequence:
- variables:
willow: "{{ states(trigger.event.data.entity_id | replace('timer', 'input_text')).split('|')[1] }}"
- if:
- condition: template
value_template: "{{ willow == '' }}"
then:
- service: rest_command.willow_notify_all
data:
audioUrl: "{{ 'https://wis.jeffcrum.com:19000/api/tts?text=' ~ states(trigger.event.data.entity_id | replace('timer', 'input_text')).split('|')[0] ~ '+timer+finished' }}"
backlight: true
backlightMax: true
repeat: 1
text: "{{ states(trigger.event.data.entity_id | replace('timer', 'input_text'))[0] | upper ~states(trigger.event.data.entity_id | replace('timer', 'input_text'))[1:] | lower ~ ' timer finished' }}"
volume: 100
else:
- service: rest_command.willow_notify
data:
audioUrl: "{{ 'https://wis.jeffcrum.com:19000/api/tts?text=' ~ states(trigger.event.data.entity_id | replace('timer', 'input_text')).split('|')[0] ~ '+timer+finished' }}"
hostname: "{{ willow }}"
backlight: true
backlightMax: true
repeat: 1
text: "{{ states(trigger.event.data.entity_id | replace('timer', 'input_text')).split('|')[0][0] | upper ~states(trigger.event.data.entity_id | replace('timer', 'input_text')).split('|')[0][1:] | lower ~ ' timer finished' }}"
volume: 100
- service: timer.start
target:
entity_id: "{{ trigger.event.data.entity_id }}"
data:
duration: "60"
enabled: false
- service: input_text.set_value
target:
entity_id: "{{ trigger.event.data.entity_id | replace('timer', 'input_text') }}"
data:
value: "{{ trigger.event.data.entity_id.split('.')[1] }}"
And timer cancelled
- conditions:
- condition: trigger
id:
- cancelled
sequence:
- service: input_text.set_value
target:
entity_id: |-
{{ trigger.event.data.entity_id | replace('timer', 'input_text') }}
data:
value: "{{ trigger.event.data.entity_id.split('.')[1] }}"
Finally, single mode. There is some duplicated code above based on needing to do single mode. Conversation response does not get a response when mode: queued
There is no data when response_variable in scripts in mode: queued · Issue #104218 · home-assistant/core (github.com)
mode: single
I think I got everything in here. I’ll update this as I (or you folks) fined issues and get them fixed.
Here is the full code
alias: Auto Timer
description: ""
trigger:
- platform: conversation
command:
- (start|set|reset) {timer_time} minute {timer_name} timer [{location}]
- (start|set|reset) {timer_name} timer (to|for) {timer_time} minute[s] [{location}]
- (cancel|stop|end) {timer_name} timer
- pause {timer_name} timer
- restart {timer_name} timer
- list timers
- commands for timer
id: command
- platform: homeassistant
event: start
id: ha_restart
- platform: event
event_type: timer.cancelled
id: cancelled
- platform: event
event_type: timer.finished
id: finished
condition:
- condition: template
value_template: "{{ trigger.id in ('command', 'ha_restart') or
(trigger.id in ('cancelled', 'finished') and
trigger.event.data.entity_id.startswith('timer.auto')) }}"
action:
- variables:
willows:
- location: office
willow_id: willow-3030f95aa8bc
- location: kitchen
willow_id: willow-3030f95a94b4
- location: mine
willow_id: willow-3030f95ad088
- location: living room
willow_id: willow-3030f95ac698
- location: hers
willow_id: willow-3030f95a9234
- location: garage
willow_id: willow-3030f95a94b8
- choose:
- conditions:
- condition: trigger
id:
- command
sequence:
- variables:
command: "{{ trigger.sentence.split(' ')[0] | lower }}"
- choose:
- conditions:
- condition: template
value_template: "{{ command in ('start', 'set') }}"
sequence:
- variables:
timer_available: |-
{{ states.timer | selectattr('entity_id', 'match', 'timer.auto*') | selectattr('state', 'eq', 'idle') | map(attribute='entity_id') | list | count > 0 }}
timer_used: |-
{{ states.input_text | selectattr('entity_id', 'match', 'input_text.auto*') | selectattr('state', 'eq', trigger.slots.timer_name) | map(attribute='entity_id') | list | count > 0 }}
timer_id: |-
{%- if timer_available -%}
{{ states.timer | selectattr('entity_id', 'match', 'timer.auto*') | selectattr('state', 'eq', 'idle') | map(attribute='entity_id') | list | first }}
{%- endif -%}
willow: |-
{{ willows | selectattr('location', 'eq', trigger.slots.location) | map(attribute='willow_id') | list | first }}
- if:
- condition: template
value_template: "{{ timer_used }}"
then:
- set_conversation_response: |-
{{ trigger.slots.timer_name }} is already in use.
else:
- if:
- condition: template
value_template: "{{ timer_available }}"
then:
- service: timer.start
target:
entity_id: "{{ timer_id }}"
data:
duration: "{{ trigger.slots.timer_time | int(default=0) * 60 }}"
- service: input_text.set_value
target:
entity_id: "{{ timer_id | replace('timer', 'input_text') }}"
data:
value: |-
{{ trigger.slots.timer_name ~ '|' ~ willow if trigger.slots.location else trigger.slots.timer_name ~ '|' }}
- set_conversation_response: |-
{{ trigger.slots.timer_name }} timer started for {{ trigger.slots.timer_time }} minute{{ 's' if trigger.slots.timer_time | int(default=0) > 1 else '' }}
else:
- set_conversation_response: No timers available
- conditions:
- condition: template
value_template: >-
{{ command in ('cancel', 'stop', 'end', 'pause', 'restart', 'reset') }}
sequence:
- variables:
timer_set: |-
{{ states.input_text | selectattr('entity_id', 'match','input_text.auto*') | selectattr('state', 'match',trigger.slots.timer_name ~ '*') | map(attribute='entity_id') | list | count > 0 }}
timer_id: |-
{%- if timer_set -%}
{{ states.input_text | selectattr('entity_id', 'match', 'input_text.auto*') | selectattr('state', 'match', trigger.slots.timer_name ~ '*') | map(attribute='entity_id') | list | first }}
{%- endif -%}
response_command: |-
{%- if command in ('cancel', 'stop', 'end', 'reset') -%}
cancel
{%- elif command == 'pause' -%}
pause
{%- elif command == 'restart' -%}
start
{%- endif -%}
response_word: |-
{%- if command == 'cancel' -%}
cancelled
{%- elif command == 'pause' -%}
paused
{%- elif command == 'restart' -%}
restarted
{%- elif command == 'reset' -%}
reset to {{ trigger.slots.timer_time }} minutes
{%- endif -%}
- if:
- condition: template
value_template: "{{ timer_set }}"
then:
- service: timer.{{ response_command }}
target:
entity_id: "{{ timer_id | replace('input_text', 'timer') }}"
- if:
- condition: template
value_template: "{{ command == 'cancel' }}"
then:
- service: input_text.set_value
target:
entity_id: "{{ timer_id | replace('timer', 'input_text') }}"
data:
value: "{{ timer_id.split('.')[1] }}"
- if:
- condition: template
value_template: "{{ command == 'reset' }}"
then:
- service: timer.start
target:
entity_id: "{{ timer_id | replace('input_text', 'timer') }}"
data:
duration: "{{ trigger.slots.timer_time | int(default=0) * 60 }}"
- set_conversation_response: >-
{{ trigger.slots.timer_name }} timer {{ response_word }}
else:
- set_conversation_response: >-
No timer named {{ trigger.slots.timer_name }} is running
- conditions:
- condition: template
value_template: "{{ trigger.sentence == 'list timers' }}"
sequence:
- variables:
timers_set: >-
{{ states.timer | selectattr('entity_id', 'match', 'timer.auto*') | selectattr('state', 'ne', 'idle') | map(attribute='entity_id') | list | count > 0 }}
timer_ids: |-
{%- if timers_set -%}
{{ states.timer | selectattr('entity_id', 'match', 'timer.auto*') | selectattr('state', 'ne', 'idle') | map(attribute='entity_id') | list }}
{%- endif -%}
- if:
- condition: template
value_template: "{{ timers_set }}"
then:
- set_conversation_response: |-
{%- for timer in timer_ids %}
{%- set timer_text = '' -%}
{%- set timer_left = (as_datetime(state_attr(timer, 'finishes_at')) - now()).total_seconds() -%}
{%- set timer_hours = timer_left | timestamp_custom('%H', false) | int -%}
{%- set timer_minutes = timer_left | timestamp_custom('%M', false) | int -%}
{%- set timer_seconds = timer_left | timestamp_custom('%S', false) | int -%}
{%- set timer_text = timer_text ~ ' ' ~ timer_hours ~ ' hour' if timer_hours > 0 else timer_text -%}
{%- set timer_text = timer_text ~ 's' if timer_hours > 1 else timer_text -%}
{%- set timer_text = timer_text ~ ' ' ~ timer_minutes ~ ' minute' if timer_minutes > 0 else timer_text -%}
{%- set timer_text = timer_text ~ 's' if timer_minutes > 1 else timer_text -%}
{%- set timer_text = timer_text ~ ' ' ~ timer_seconds ~ ' second' if timer_seconds > 0 else timer_text -%}
{%- set timer_text = timer_text ~ 's' if timer_seconds > 1 else timer_text %}
{{ states(timer | replace('timer', 'input_text')).split('|')[0] }} timer has{{ timer_text }} left.
{%- endfor -%}
else:
- set_conversation_response: No timers are running
- conditions:
- condition: template
value_template: "{{ trigger.sentence.startswith('commands for timer') }}"
sequence:
- service: notify.persistent_notification
data:
message: |-
(start|set|reset) {timer_time} minute {timer_name} timer [{location}]
(start|set|reset) {timer_name} timer (to|for) {timer_time} minute[s] [{location}]
(cancel|stop|end) {timer_name} timer
pause {timer_name} timer
restart {timer_name} timer
list timers
commands for timer
- set_conversation_response: Timer commands sent to persistent notifications
- conditions:
- condition: trigger
id:
- ha_restart
sequence:
- variables:
timers: "{{ states.timer | selectattr('entity_id', 'match', 'timer.auto*') | selectattr('state', 'eq', 'idle') | map(attribute='name') | list }}"
- repeat:
for_each: "{{ states.input_text | selectattr('entity_id', 'match', 'input_text.auto*') | rejectattr('state', 'match', 'auto*') | selectattr('name', 'in', timers) | map(attribute='entity_id') | list }}"
sequence:
- variables:
willow: "{{ states(repeat.item).split('|')[1] }}"
- if:
- condition: template
value_template: "{{ willow == '' }}"
then:
- service: rest_command.willow_notify_all
data:
audioUrl: "{{ 'https://wis.jeffcrum.com:19000/api/tts?text=' ~ states(repeat.item).split('|')[0] ~ '+timer+finished' }}"
backlight: true
backlightMax: true
repeat: 1
text: "{{ states(repeat.item).split('|')[0][0] | upper ~ states(repeat.item).split('|')[0][1:] | lower ~ ' timer finished' }}"
volume: 100
else:
- service: rest_command.willow_notify
data:
audioUrl: "{{ 'https://wis.jeffcrum.com:19000/api/tts?text=' ~ states(repeat.item).split('|')[0] ~ '+timer+finished' }}"
hostname: "{{ willow }}"
backlight: true
backlightMax: true
repeat: 1
text: "{{ states(repeat.item).split('|')[0][0] | upper ~ states(repeat.item).split('|')[0][1:] | lower ~ ' timer finished' }}"
volume: 100
- service: timer.start
target:
entity_id: "{{ repeat.item | replace('input_box', 'timer') }}"
data:
duration: "60"
enabled: false
- service: input_text.set_value
target:
entity_id: "{{ repeat.item }}"
data:
value: "{{ repeat.item.split('.')[1] }}"
- conditions:
- condition: trigger
id:
- finished
sequence:
- variables:
willow: "{{ states(trigger.event.data.entity_id | replace('timer', 'input_text')).split('|')[1] }}"
- if:
- condition: template
value_template: "{{ willow == '' }}"
then:
- service: rest_command.willow_notify_all
data:
audioUrl: "{{ 'https://wis.jeffcrum.com:19000/api/tts?text=' ~ states(trigger.event.data.entity_id | replace('timer', 'input_text')).split('|')[0] ~ '+timer+finished' }}"
backlight: true
backlightMax: true
repeat: 1
text: "{{ states(trigger.event.data.entity_id | replace('timer', 'input_text'))[0] | upper ~states(trigger.event.data.entity_id | replace('timer', 'input_text'))[1:] | lower ~ ' timer finished' }}"
volume: 100
else:
- service: rest_command.willow_notify
data:
audioUrl: "{{ 'https://wis.jeffcrum.com:19000/api/tts?text=' ~ states(trigger.event.data.entity_id | replace('timer', 'input_text')).split('|')[0] ~ '+timer+finished' }}"
hostname: "{{ willow }}"
backlight: true
backlightMax: true
repeat: 1
text: "{{ states(trigger.event.data.entity_id | replace('timer', 'input_text')).split('|')[0][0] | upper ~states(trigger.event.data.entity_id | replace('timer', 'input_text')).split('|')[0][1:] | lower ~ ' timer finished' }}"
volume: 100
- service: timer.start
target:
entity_id: "{{ trigger.event.data.entity_id }}"
data:
duration: "60"
enabled: false
- service: input_text.set_value
target:
entity_id: "{{ trigger.event.data.entity_id | replace('timer', 'input_text') }}"
data:
value: "{{ trigger.event.data.entity_id.split('.')[1] }}"
- conditions:
- condition: trigger
id:
- cancelled
sequence:
- service: input_text.set_value
target:
entity_id: |-
{{ trigger.event.data.entity_id | replace('timer', 'input_text') }}
data:
value: "{{ trigger.event.data.entity_id.split('.')[1] }}"
mode: single
Please let me know if you find any issues that we can get fixed or any code that can be optimized.
Of course, I am sure I can fix words in my descriptions as this was built over time and I probably missed something in my changes too.
All criticisms are welcome!