On top of not being originally designed for voice use, timers need a lot of rework in my opinion.
You have to work around a lot of limitations (not being able to increase past original duration, a remaining
attribute that’s not really “remaining” unless the state of the timer changes…). You end up having to calculate everything by hand…
unfortunately the timers aren’t working for me. it says “Unexpected error during intent recognition” when i say “set a timer for 1 minute”
Which ones did you try to setup?
Did you check HA’s logs right after asking? It should give a more precise idea of what’s going wrong.
You can also test the matching manually in Developer Tools > Assist, you write the sentence as you think it should match, and it will tell you if it finds a matching intent (indicating if your sentence’s format is wrong or your intent is not properly configured).
PS: Many of these number-dependent intents should become a lot easier to handle as soon as HA updates to the new parser version, that fixes the broken number words recognition.
Update: Intents cleaned up with 2024.2 now supporting numbers without nasty workarounds. You can find the full list here.
Let’s do some math…
Nice! Will look into that. Im actually working on a timer package to get a simpler but working solution. Nearly done.
Hello everyone,
I updated my repo with a ready-to-deploy timers package.
You will only need two files:
- package/assist_timers.yaml
- custom_sentences//assist_timers.yaml
Be sure to update the package file variables first.
Only Dutch and English for the timer functionality… Sorry…
This is great, thanks. I haven’t looked at the yaml in depth, but I wonder how much work it would be to add phrasing like what I use with Alexa (most succinct wording I could find)
“Alexa, 5 minute stove timer”
“Alexa, 10 minute water timer”
Excludes unnecessary “set a” and “for” and “please”
I havent added the ability to name timers (yet).
This adds a whole bunch of code. Maybe Ill do it later.
You could modify the sentences to your liking and make certain parts optional by placing them in […] brackets.
This is working pretty good. You need to create the timer ahead of time.
I need to work out dropping the word “Seconds” from the response if no second exist… :
alias: responce_timer_test
description: ""
trigger:
- platform: conversation
command:
- >-
(Set|start|begin) a timer for {minutes} minutes (and) {seconds}
(seconds)
- (Set|start|begin) a timer for {minutes} minutes
id: Start Timer
- platform: conversation
command: (cancel|stop) the timer
id: Cancel Timer
condition: []
action:
- choose:
- conditions:
- condition: trigger
id:
- Start Timer
sequence:
- service: timer.start
target:
entity_id: timer.test_timer
data:
duration: 00:0{{ trigger.slots.minutes }}:00{{ trigger.slots.seconds }}
enabled: true
- set_conversation_response: >-
I have set a timer for {{ trigger.slots.minutes }} minutes and {{
trigger.slots.seconds }} seconds
enabled: true
- conditions:
- condition: trigger
id:
- Cancel Timer
sequence:
- service: timer.cancel
data: {}
target:
entity_id: timer.test_timer
mode: single
I have the file package/assist_timers.yaml and custom_sentences/en/assist_timers.yaml but I am getting an error of “Unexpected error during intent recognition". Here is the log after I tried to run it. Any ideas?
Logger: homeassistant.components.assist_pipeline.pipeline
Source: components/assist_pipeline/pipeline.py:988
Integration: Assist pipeline (documentation, issues)
First occurred: 11:16:00 AM (1 occurrences)
Last logged: 11:16:00 AM
Unexpected error during intent recognition
Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/components/assist_pipeline/pipeline.py", line 988, in recognize_intent
conversation_result = await conversation.async_converse(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/src/homeassistant/homeassistant/components/conversation/__init__.py", line 543, in async_converse
result = await agent.async_process(
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/src/homeassistant/homeassistant/components/conversation/default_agent.py", line 221, in async_process
result = await self.async_recognize(user_input)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/src/homeassistant/homeassistant/components/conversation/default_agent.py", line 205, in async_recognize
result = await self.hass.async_add_executor_job(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/concurrent/futures/thread.py", line 58, in run
result = self.fn(*self.args, **self.kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/src/homeassistant/homeassistant/components/conversation/default_agent.py", line 383, in _recognize
for result in recognize_all(
File "/usr/local/lib/python3.12/site-packages/hassil/recognize.py", line 507, in recognize_all
for maybe_match_context in maybe_match_contexts:
File "/usr/local/lib/python3.12/site-packages/hassil/recognize.py", line 1082, in match_expression
group_contexts = [
^
File "/usr/local/lib/python3.12/site-packages/hassil/recognize.py", line 1074, in match_expression
yield from match_expression(settings, context, item)
File "/usr/local/lib/python3.12/site-packages/hassil/recognize.py", line 1082, in match_expression
group_contexts = [
^
File "/usr/local/lib/python3.12/site-packages/hassil/recognize.py", line 1363, in match_expression
raise MissingRuleError(f"Missing expansion rule <{rule_ref.rule_name}>")
hassil.recognize.MissingRuleError: Missing expansion rule <would>
It’s a shame the local calendar is so slow to update or you could do this quite simply with calendar events.
I created that a while back but since the calendars doesn’t update fast enough then it was not very useful
So I removed the [would] words from the custom_sentences file and now I am getting this error.
Logger: homeassistant.components.assist_pipeline.pipeline
Source: components/assist_pipeline/pipeline.py:988
Integration: Assist pipeline (documentation, issues)
First occurred: 11:29:23 AM (1 occurrences)
Last logged: 11:29:23 AM
Unexpected error during intent recognition
Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/components/assist_pipeline/pipeline.py", line 988, in recognize_intent
conversation_result = await conversation.async_converse(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/src/homeassistant/homeassistant/components/conversation/__init__.py", line 543, in async_converse
result = await agent.async_process(
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/src/homeassistant/homeassistant/components/conversation/default_agent.py", line 296, in async_process
intent_response = await intent.async_handle(
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/src/homeassistant/homeassistant/helpers/intent.py", line 87, in async_handle
raise UnknownIntent(f"Unknown intent {intent_type}")
homeassistant.helpers.intent.UnknownIntent: Unknown intent TimerStart
OK I feel dumb now. I fixed the issue. I had packages: !include_dir_named packages but my folder was named package without the s. All is working now. Thanks
Ah yes, I see WOULD is not a word in the english assist language compared to the dutch variant which is. Ill remove it, thanks for pointing that out.
Glad it works now!
Thanks for this - however its not working as expected for me. Have had to amend a few things to get the intent recognised by assist, and so far only got 1 timer working.
- config/custom_sentences/en/assist_timers.yaml - line 1 specifies “nl” in the “en” file
- In custom_sentences I had to remove <[would]> completely
- add 2 new sentences:
- sentences:
- "set [a] {minutes} minute[s] timer"
slots:
hours: 0
minutes: 0
seconds: 0
- sentences:
- "set [a] {seconds} second[s] timer"
slots:
hours: 0
minutes: 0
seconds: 0
- had to create a new automation for announcing the end of the timer
- change seconde[s] to second[s] in sentences
I grabbed the latest file from github, but not sure how this would’ve worked for others?
I’ve updated it enough to work for my use cases (minutes and seconds) but here is my amended assist_timers.yaml english file in case it’s useful to you / anyone else.
language: "en"
intents:
TimerStop:
data:
- sentences:
- "(stop|cancel|turn off) [the] {entity_id} timer[s]"
- sentences:
- "(stop|cancel|turn off) [the] timer[s]"
slots:
entity_id: "null"
TimerPause:
data:
- sentences:
- "(pause|interrupt) [the] {entity_id} timer[s]"
slots:
timer_action: "pause"
- sentences:
- "(pause|interrupt) [the] timer[s]"
slots:
entity_id: "null"
timer_action: "pause"
- sentences:
- "(pause|interrupt) all timer[s]"
slots:
entity_id: "all"
timer_action: "pause"
- sentences:
- "(resume|continue) [the] {entity_id} timer[s]"
slots:
timer_action: "resume"
- sentences:
- "(resume|continue) [the] timer[s]"
slots:
entity_id: "null"
timer_action: "resume"
- sentences:
- "(resume|continue) all timer[s]"
slots:
entity_id: "all"
timer_action: "resume"
TimerDuration:
data:
- sentences:
- "how [much] long[er] on [the] {entity_id} timer"
- "how much time is left on [the] {entity_id} timer"
- "how long until [the] {entity_id} timer (is finished|finishes)"
- sentences:
- "how [much] long[er] on [the] timer[s]"
- "how much time is left on [the] {entity_id} timer[s]"
- "how long until [the] timer[s] (is finished|finishes)"
slots:
entity_id: "null"
TimerStart:
data:
#Alle tijden
- sentences:
- "set [a] timer (for|with) {hours} hour[s] [and] {minutes} minute[s] [and] {seconds} second[s]"
#Alleen uur
- sentences:
- "set [a] timer (for|with) {hours} hour[s]"
slots:
hours: 0
minutes: 0
seconds: 0
#Alleen minuut
- sentences:
- "set [a] timer (for|with) {minutes} minute[s]"
slots:
hours: 0
minutes: 0
seconds: 0
#Alleen seconde
- sentences:
- "set [a] {seconds} second[s] timer"
slots:
hours: 0
minutes: 0
seconds: 0
#Geen uur, wel minuten en seconden
- sentences:
- "set [a] timer (for|with) {minutes} minute[s] [and] {seconds} second[s]"
slots:
hours: 0
minutes: 0
seconds: 0
#Geen seconden, wel uren en minuten
- sentences:
- "set [a] timer (for|with) {hours} hour[s] [and] {minutes} minute[s]"
slots:
hours: 0
minutes: 0
seconds: 0
- sentences:
- "set [a] {minutes} minute[s] timer"
slots:
hours: 0
minutes: 0
seconds: 0
lists:
entity_id:
values:
- in: "(first|one|1)"
out: "timer.assist_timer1"
- in: "(second|two|2)"
out: "timer.assist_timer2"
- in: "(third|three|3)"
out: "timer.assist_timer3"
- in: "(all|every)"
out: "all"
seconds:
range:
from: 0
to: 120
minutes:
range:
from: 0
to: 120
hours:
range:
from: 0
to: 24
responses:
intents:
TimerStop:
default: >
{%- set timer_amount = states.timer
| selectattr('state','eq','active')
| selectattr('entity_id','match','timer.assist_timer*')
| map(attribute='entity_id')
| list
| length -%}
{% if timer_amount == 0 and
(as_timestamp(now()) - as_timestamp(states.timer.assist_timer1.last_changed) > 3 and states('timer.assist_timer1') == 'idle') and
(as_timestamp(now()) - as_timestamp(states.timer.assist_timer2.last_changed) > 3 and states('timer.assist_timer2') == 'idle') and
(as_timestamp(now()) - as_timestamp(states.timer.assist_timer3.last_changed) > 3 and states('timer.assist_timer3') == 'idle') %}
There are no timers active.
{% elif (slots_entity_id == 'timer.assist_timer1' and states('timer.assist_timer1') == 'idle') or
(slots_entity_id == 'timer.assist_timer2' and states('timer.assist_timer2') == 'idle') or
(slots_entity_id == 'timer.assist_timer3' and states('timer.assist_timer3') == 'idle') %}
This timer is not active.
{% elif timer_amount > 1 and slots_entity_id == 'null' %}
There are multiple timers active.
{{ (["Please specify which timer you mean.", "Please specify which timer.", "Specify which timer you mean.", ""] | random) }}
{% elif slots_entity_id == 'all' %}
{{ (["Understood. ", "Okay. ", "Of course. ", ""] | random) }}All timers stopped.
{% else %}
{{ (["Understood. ", "Okay. ", "Of course. ", ""] | random) }}Timer stopped.
{% endif %}
TimerPause:
default: >
{%- if slots.timer_action is set or slots.timer_action != "" -%}
{%- set timer_action = slots.timer_action -%}
{%- else -%}
{%- set timer_action = "resume" -%}
{%- endif -%}
{%- set timer_amount = states.timer
| selectattr('state','eq','active')
| selectattr('entity_id','match','timer.assist_timer*')
| map(attribute='entity_id')
| list
| length -%}
{% if timer_amount == 0 %}
There are no timers active.
{% elif timer_amount > 1 and slots.entity_id == 'null' %}
There are multiple timers active.
{{ (["Please specify which timer you mean.", "Please specify which timer.", "Specify which timer you mean.", ""] | random) }}
{% elif slots.entity_id == 'all' %}
{{ (["Understood. ", "Okay. ", "Of course. ", ""] | random) }}.
All timers {% if timer_action == "pause" %}paused{% else %}resumed{% endif %}.
{% elif (as_timestamp(now()) - as_timestamp(states.timer.assist_timer1.last_changed) < 3 and states('timer.assist_timer1') == 'idle') or
(as_timestamp(now()) - as_timestamp(states.timer.assist_timer2.last_changed) < 3 and states('timer.assist_timer2') == 'idle') or
(as_timestamp(now()) - as_timestamp(states.timer.assist_timer3.last_changed) < 3 and states('timer.assist_timer3') == 'idle') %}
Timer {% if timer_action == "pause" %}paused{% else %}resumed{% endif %}.
{% elif (timer_amount == 1 and slots.entity_id == 'null') or
(slots.entity_id == 'timer.assist_timer1' and states('timer.assist_timer1') != 'idle') or
(slots.entity_id == 'timer.assist_timer2' and states('timer.assist_timer2') != 'idle') or
(slots.entity_id == 'timer.assist_timer3' and states('timer.assist_timer3') != 'idle') %}
{{ (["Understood. ", "Okay. ", "Of course. ", ""] | random) }}Timer {% if timer_action == "pause" %}paused{% else %}resumed{% endif %}.
{% else %}
This timer is not active.
{% endif %}
TimerDuration:
default: >
{%- set timer_amount = states.timer
| selectattr('state','eq','active')
| selectattr('entity_id','match','timer.assist_timer*')
| map(attribute='entity_id')
| list
| length -%}
{% if timer_amount == 0 %}
There are no timers active.
{% else %}
{%- if slots.entity_id != 'all' and slots.entity_id != 'null' %}
{%- set active_timers = states.timer
| selectattr('state','eq','active')
| selectattr('entity_id','match',slots.entity_id)
| list -%}
{%- else%}
{%- set active_timers = states.timer
| selectattr('state','eq','active')
| selectattr('entity_id','match','timer.assist_timer*')
| list -%}
{%- endif %}
{% if active_timers|length == 0 %}
{%- if slots.entity_id != 'all' and slots.entity_id != 'null' %}This timer is not active.
{%- else %}There are no timers active. {%- endif %}{%
elif active_timers|length > 1 %}There are {{active_timers|length }} timers active. {%
endif %}{%
for timer in active_timers %}{%
set timer_id = timer.entity_id %}{%
set timer_finishes_at = state_attr(timer_id, 'finishes_at') %}{%
set time_remaining = as_datetime(timer_finishes_at) - now() %}{%
set hours_remaining = time_remaining.total_seconds() // 3600 %}{%
set minutes_remaining = (time_remaining.total_seconds() % 3600) // 60 %}{%
set seconds_remaining = time_remaining.total_seconds() % 60 %}{%
if timer.state == "active" or timer.state == "paused" %}{%
if slots.entity_id != timer_id
%}{{ state_attr(timer_id, 'friendly_name')[9:] }} {%
if timer.state == "paused" %} is paused and {% endif %}has {%
else %}There are {% endif %}{%
if hours_remaining > 0 %}{{ hours_remaining | round }} hours {% endif %}{%
if minutes_remaining == 1 %}1 minute {% endif %}{%
if minutes_remaining > 1 %}{{ minutes_remaining | round }} minutes {% endif %}{%
if seconds_remaining == 1 and hours_remaining == 0%}1 seconde {% endif %}{%
if seconds_remaining > 1 and hours_remaining == 0 %}{{ seconds_remaining | round }} seconds {% endif %}remaining. {%
endif %}{%
endfor %}
{% endif %}
TimerStart:
default: >
{{ (["Understood. ", "Okay. ", "Of course. ", ""] | random) + (["I will start a timer for ", "Timer started with ", "Starting timer with ", "Timer active for "] | random)}}{% if (slots.hours | int(default=0)) == 1 %}1 hour{% elif (slots.hours | int(default=0)) > 1 %}{{ (slots.hours | int)}} hours{% endif %}{% if (slots.hours | int(default=0)) > 0 and ((slots.minutes | int(default=0)) > 0 or (slots.seconds | int(default=0)) > 0) %} and {% endif %}{% if (slots.minutes | int(default=0)) == 1 %}1 minute{% elif (slots.minutes | int(default=0)) > 1 %}{{ (slots.minutes | int)}} minutes{% endif %}{% if (slots.minutes | int(default=0)) > 0 and (slots.seconds | int(default=0)) > 0 %} and {% endif %}{% if (slots.seconds | int(default=0)) == 1 %}1 second{% elif (slots.seconds | int(default=0)) > 1 %}{{ (slots.seconds | int)}} secondes{% endif %}.
Hi OliP, thanks for point that out. You are right, I made a mistake in the language and some 's were still there. I updated the file on my github and added those sentences you suggested to seconds, minutes and hours.
I did try it afterwards and it seemed to work fine on my end now. Did you update the package file containing the automations too?
Hi Don, really great to see this, thanks for making it! Just a few questions though, so I can get working exactly as I want.
- If I want to use tts.speak with Piper as the entity, how do I modify the code in the modify variables section?
- I’m struggling to get the timer media to play (I do get the tts message though, so the timer is working). I’ve added my own media file, which I renamed to timer.mp3 (just like in your variables section), but I’m a little unsure about the media file path. My file is under 'www > assist-sounds> timer.mp3. What should I put as the path next to timer_media_location?
Thanks again, great addition to Assist!!
Hi Carl,
No problem glad to share my projects.
Regarding your questions:
- I’ve updated the timer package to have the option to choose piper.
It now has another variable. You should use the following:
timer_tts: true #Set this to true if you want the timer to be a tts message. Default is true.
timer_tts_service: "tts.speak" #Which TTS service to use? Default is "tts.speak".
timer_tts_target: "tts.piper" #Which TTS target to use, e.g. piper or ha cloud? Default is "tts.home_assistant_cloud".
timer_tts_message: "A set timer has finished." #You can also assign a sensor or input_text entity_id to have a dynamic tts message.
- Like the example shows, you should use “/media/local/FILENAME.mp3”. This uses files that are located in your /media folder (one up from config, not inside the config folder). It is capital sensitive!
Great, thanks so much, I’ll update my config. Have a great weekend!!
Hi again Don,
So I’ve played a bit more with the timers now, and now they aren’t working at all. I get the confirmation that the timer has started, but then I don’t get anything when the timer has finished. I get the following in the logs
Logger: homeassistant.components.automation.assist_timerreached
Source: helpers/script.py:1933
integration: Automation (documentation, issues)
First occurred: 14:29:50 (6 occurrences)
Last logged: 15:48:55
Assist - TimerReached: Media file or TTS: default: Error executing script. Invalid data for call_service at pos 2: required key not provided @ data['media_player_entity_id']
Assist - TimerReached: Error executing script. Invalid data for choose at pos 4: required key not provided @ data['media_player_entity_id']
Logger: homeassistant.components.automation.assist_timerreached
Source: components/automation/__init__.py:747
integration: Automation (documentation, issues)
First occurred: 14:29:50 (3 occurrences)
Last logged: 15:48:55
Error while executing automation automation.assist_timerreached: required key not provided @ data['media_player_entity_id']
Here’s my package file, where I’ve just changed the media player and volume.
## Assist Package - Timers
## Routine before going to sleep
## https://github.com/don86nl/ha_intents
### TO DO: OPTIE NAAM BIJ SENTENCES
homeassistant:
customize:
script.assist_timerstart:
settings: &settings
########################################################
### SET THE VARIABLES HERE TO CUSTOMIZE YOUR ROUTINE ###
########################################################
timer_target: "media_player.kitchen_display" #Which device or room should play the timer? #NOTE: If you choose a room, ALL media_players in that room will be played.
timer_target_default: "media_player.kitchen_display" #Which media_player entity should be used if timer_target is none? (Used when dynamic targets are null.)
#You can also assign a sensor.entity_id or input_text to have a dynamic room or media_player assigned.
#This can be usefull if, for example, you have a sensor monitoring where Assist is activated, to use it in that specific room or device.
# Timer settings
timer_tts: true #Set this to true if you want the timer to be a tts message. Default is true.
timer_tts_service: "tts.speak" #Which TTS service to use? Default is "tts.cloud_say".
timer_tts_message: "A set timer has finished." #You can also assign a sensor or input_text entity_id to have a dynamic tts message.
#If timer_tts is set to false, the media_location will automatically be used to play the target media file.
timer_media_location: "/media/local/timer.mp3"
# Timer volume
timer_volume: 0.5 #What volume level do you want the timer to play at? Device volume level will be restored after the timer has finished.
########################################################
script:
assist_timerstart:
alias: "Assist - TimerStart"
description: "Script for starting a timer using HA Assist."
icon: mdi:assistant
mode: single
variables:
settings: *settings
sequence:
- alias: "Set variables"
variables:
timer_location: >-
{%- if settings.get('timer_target')[:13] == "media_player." %}
{{ area_name(settings.get('timer_target')) | lower }}
{% elif (settings.get('timer_target')[:7] == "sensor." or settings.get('timer_target')[:11] == "input_text.") and states(settings.get('timer_target'))[:13] == "media_player." %}
{{- states(settings.get('timer_target')) }}
{%- elif settings.get('timer_target')[:13] != "media_player." and settings.get('timer_target')[:7] != "sensor." and settings.get('timer_target')[:11] != "input_text." %}
{{- settings.get('timer_target') }}
{%- elif (settings.get('timer_target')[:7] == "sensor." or settings.get('timer_target')[:11] == "input_text.") and (states(settings.get('timer_target')) != "") and (states(settings.get('timer_target'))[:13] == "media_player.") %}
{{ area_name(settings.get('timer_target_default')) }}
{%- elif (settings.get('timer_target')[:7] == "sensor." or settings.get('timer_target')[:11] == "input_text.") %}
{% if states(settings.get('timer_target')) != "" and states(settings.get('timer_target')) != "not_home" and states(settings.get('timer_target')) != 0 %}
{{ states(settings.get('timer_target')) }}
{% else %}
{{- area_name(settings.get('timer_target_default')) | lower }}
{%- endif %}
{%- else %}
{{- area_name(settings.get('timer_target')) | lower }}
{%- endif %}
- alias: "Set timer location"
service: input_text.set_value
target:
entity_id: >-
{% if states('timer.assist_timer1') != 'active' and states('timer.assist_timer1') != 'paused' %}
input_text.assist_timer1_location
{% elif states('timer.assist_timer2') != 'active' and states('timer.assist_timer2') != 'paused' %}
input_text.assist_timer2_location
{% else %}
input_text.assist_timer3_location
{% endif%}
data:
value: "{{ timer_location }}"
- alias: "Start timer"
service: timer.start
data_template:
duration: "{{ duration }}"
target:
entity_id: >-
{% if states('timer.assist_timer1') != 'active' and states('timer.assist_timer1') != 'paused' %} timer.assist_timer1
{% elif states('timer.assist_timer2') != 'active' and states('timer.assist_timer2') != 'paused' %} timer.assist_timer2
{% else %} timer.assist_timer3{% endif%}
assist_timerstop:
alias: "Assist - TimerStop"
description: "Script for stopping a timer using HA Assist."
icon: mdi:assistant
mode: single
variables:
entity_id: >-
{% if entity_id is set or entity_id != "" %}
{{ entity_id }}
{% else %}
null
{% endif %}
sequence:
- alias: Set variables
variables:
entity_id: >-
{% if entity_id is set or entity_id != "" %} {{ entity_id }} {% else %}
null {% endif %}
- choose:
- conditions:
- condition: template
value_template: "{{ entity_id[:18] == 'timer.assist_timer' }}"
alias: Single Timer
sequence:
- alias: "Single timer: Idle or active"
choose:
- conditions:
- condition: template
value_template: "{{ states(entity_id) == 'idle' }}"
alias: Timer not active
sequence:
- stop: Timer is not active
default:
- service: timer.cancel
target:
entity_id: "{{ entity_id }}"
alias: Cancel single timer
- service: input_text.set_value
data:
value: "0"
target:
entity_id: |-
{{ states.timer
| selectattr('state','eq','active')
| selectattr('entity_id','match','timer.assist_timer*')
| map(attribute='entity_id')
| join('_location, ') | replace('timer.', 'input_text.') }}
alias: Reset timer location value
- stop: Timer cancelled
- conditions:
- condition: template
value_template: "{{ entity_id == 'null' }}"
alias: No specific Timer
- alias: Timer(s) are active
condition: template
value_template: |-
{{ states.timer
| rejectattr('state','eq','idle')
| selectattr('entity_id','match','timer.assist_timer*')
| map(attribute='entity_id')
| list
| length > 0 }}
sequence:
- alias: "No specific timer: # active?"
choose:
- conditions:
- condition: template
value_template: "{{ entity_id == 'null' }}"
alias: No specific timer asked
- alias: Multiple timers active
condition: template
value_template: |-
{{ states.timer
| rejectattr('state','eq','idle')
| selectattr('entity_id','match','timer.assist_timer*')
| map(attribute='entity_id')
| list
| length > 1 }}
sequence:
- stop: Multiple timers active, none specified
default:
- service: timer.cancel
target:
entity_id: |-
{{ states.timer
| rejectattr('state','eq','idle')
| selectattr('entity_id','match','timer.assist_timer*')
| map(attribute='entity_id')
| join(', ') }}
alias: Cancel single timer
- service: input_text.set_value
metadata: {}
data:
value: "0"
target:
entity_id: |-
{{ states.timer
| rejectattr('state','eq','idle')
| selectattr('entity_id','match','timer.assist_timer*')
| map(attribute='entity_id')
| join('_location, ') | replace('timer.', 'input_text.') }}
alias: Reset timer location value
- stop: Timer cancelled
alias: No specific timer
- conditions:
- alias: All timers
condition: template
value_template: "{{ entity_id == 'all' }}"
sequence:
- alias: Timers active?
choose:
- conditions:
- condition: template
value_template: |-
{{ states.timer
| rejectattr('state','eq','idle')
| selectattr('entity_id','match','timer.assist_timer*')
| map(attribute='entity_id')
| list
| length == 0 }}
alias: No timers active
sequence:
- stop: No timers active
alias: No timers active
default:
- service: timer.cancel
target:
entity_id: |-
{{ states.timer
| rejectattr('state','eq','idle')
| selectattr('entity_id','match','timer.assist_timer*')
| map(attribute='entity_id')
| join(', ') }}
alias: Cancel all timers
- stop: Cancel all timers
alias: All timers
assist_timerpause:
alias: "Assist - TimerPause"
description: "Script for pausing a timer using HA Assist."
icon: mdi:assistant
mode: single
variables:
entity_id: >-
{% if entity_id is set or entity_id != "" %} {{ entity_id }} {% else %} null
{% endif %}
timer_action: >-
{% if timer_action is set or timer_action != "" %} {{ timer_action }} {%
else %} resume {% endif %}
sequence:
- choose:
- conditions:
- condition: template
value_template: "{{ entity_id[:18] == 'timer.assist_timer' }}"
alias: Single Timer
sequence:
- alias: "Single timer: Idle or active"
choose:
- conditions:
- condition: template
value_template: "{{ states(entity_id) == 'idle' }}"
alias: Timer not active
sequence:
- stop: Timer is not active
default:
- alias: Pause or resume
choose:
- conditions:
- condition: template
value_template: "{{ timer_action == 'pause' }}"
alias: Action = pause
sequence:
- service: timer.pause
target:
entity_id: "{{ entity_id }}"
alias: Pause timer
- stop: Pause timer
alias: Pause
default:
- service: timer.start
target:
entity_id: "{{ entity_id }}"
alias: Resume timer
- stop: Resume timer
- conditions:
- condition: template
value_template: "{{ entity_id == 'null' }}"
alias: No specific Timer
- alias: Timer(s) are active
condition: template
value_template: |-
{{ states.timer
| rejectattr('state','eq','idle')
| selectattr('entity_id','match','timer.assist_timer*')
| map(attribute='entity_id')
| list
| length > 0 }}
sequence:
- alias: "No specific timer: # active?"
choose:
- conditions:
- condition: template
value_template: "{{ entity_id == 'null' }}"
alias: No specific timer asked
- alias: Multiple timers active
condition: template
value_template: |-
{{ states.timer
| rejectattr('state','eq','idle')
| selectattr('entity_id','match','timer.assist_timer*')
| map(attribute='entity_id')
| list
| length > 1 }}
sequence:
- stop: Multiple timers active, none specified
default:
- alias: Pause or resume
choose:
- conditions:
- condition: template
value_template: "{{ timer_action == 'pause' }}"
alias: Action = pause
sequence:
- service: timer.pause
target:
entity_id: |-
{{ states.timer
| rejectattr('state','eq','idle')
| selectattr('entity_id','match','timer.assist_timer*')
| map(attribute='entity_id')
| join(', ') }}
alias: Pause timer
- stop: Pause timer
alias: Pause
default:
- service: timer.start
target:
entity_id: |-
{{ states.timer
| rejectattr('state','eq','idle')
| selectattr('entity_id','match','timer.assist_timer*')
| map(attribute='entity_id')
| join(', ') }}
alias: Resume timer
- stop: Resume timer
alias: No specific timer
- conditions:
- alias: All timers
condition: template
value_template: "{{ entity_id == 'all' }}"
sequence:
- alias: Timers active?
choose:
- conditions:
- condition: template
value_template: |-
{{ states.timer
| rejectattr('state','eq','idle')
| selectattr('entity_id','match','timer.assist_timer*')
| map(attribute='entity_id')
| list
| length == 0 }}
alias: No timers active
sequence:
- stop: No timers active
alias: No timers active
default:
- alias: Pause or resume
choose:
- conditions:
- condition: template
value_template: "{{ timer_action == 'pause' }}"
alias: Action = pause
sequence:
- service: timer.pause
target:
entity_id: |-
{{ states.timer
| rejectattr('state','eq','idle')
| selectattr('entity_id','match','timer.assist_timer*')
| map(attribute='entity_id')
| join(', ') }}
alias: Pause timer
- stop: Pause timer
alias: Pause
default:
- service: timer.start
target:
entity_id: |-
{{ states.timer
| rejectattr('state','eq','idle')
| selectattr('entity_id','match','timer.assist_timer*')
| map(attribute='entity_id')
| join(', ') }}
alias: Resume timer
- stop: Resume timer
alias: All timers
automation:
- alias: Assist - TimerReached
id: assist_timerreached
description: Assist automation when set timer time is reached.
trigger:
- alias: "Any timer reached"
id: "timer_finished"
platform: event
event_type: timer.finished
condition:
- condition: template
value_template: "{{ trigger.event.data.entity_id[:18] == 'timer.assist_timer' }}"
alias: Finished timer is an assist timer
variables:
settings: *settings
action:
- alias: "Get generic variables from script"
variables:
timer_tts: "{{ settings.get('timer_tts') }}"
timer_tts_service: "{{ settings.get('timer_tts_service') }}"
timer_tts_message: "{{ settings.get('timer_tts_message') }}"
timer_media_location: "{{ settings.get('timer_media_location') }}"
timer_volume: "{{ settings.get('timer_volume') }}"
timer_target: >-
{%- if settings.get('timer_target')[:13] == "media_player." %}
{{- settings.get('timer_target') }}
{%- elif (settings.get('timer_target')[:7] == "sensor." or settings.get('timer_target')[:11] == "input_text.") and (states(settings.get('timer_target'))[:13] == "media_player.") %}
{{- states(settings.get('timer_target')) }}
{%- elif (settings.get('timer_target')[:7] == "sensor." or settings.get('timer_target')[:11] == "input_text.") and (states(settings.get('timer_target')) == "") %}
{{- settings.get('timer_target_default') }}
{%- else %}
{%- set media_player_list = states.media_player | map(attribute='entity_id') | list %}
{%- if "sensor." in settings.get('timer_target') or "input_text." in target_area %}
{%- set target_area = states(settings.get('timer_target')) %}
{%- else %}
{%- set target_area = settings.get('timer_target') %}
{%- endif %}
{%- for entity_id in media_player_list %}
{%- if area_name(entity_id) | lower == target_area | lower %}
{{ entity_id }}
{%- endif %}
{%- endfor %}
{%- endif %}
- alias: "Store current device volume"
variables:
device_volume: "{{ state_attr(timer_target, 'volume_level') }}"
- alias: "Set volume for timer"
service: media_player.volume_set
data:
volume_level: "{{ timer_volume }}"
target:
entity_id: "{{ timer_target }}"
- alias: Media file or TTS
choose:
- conditions:
- alias: Timer is a media file
condition: template
value_template: "{{ timer_tts == false }}"
sequence:
- alias: Play media
service: media_player.play_media
target:
entity_id: "{{ timer_target }}"
data:
media_content_id: "{{ timer_media_location }}"
announce: true
media_content_type: music
enabled: true
alias: Media file
default:
- delay:
seconds: 1
- service: "{{ timer_tts_service }}"
data:
cache: true
entity_id: "{{ timer_target }}"
message: >-
{% if timer_tts_message[:7] == "sensor." or timer_tts_message[:11] == "input_text." %}
{{ states(timer_tts_message) }}
{% else %}
{{ timer_tts_message }}
{% endif %}
alias: TTS
- alias: "Restore device previous volume"
service: media_player.volume_set
data:
volume_level: "{{ device_volume }}"
target:
entity_id: "{{ timer_target }}"
mode: single
- alias: Assist - TimerFinished
id: assist_timerfinished
description: Assist automation when set timer time is finished.
trigger:
- platform: state
entity_id:
- timer.assist_timer1
- timer.assist_timer2
- timer.assist_timer3
to: "idle"
alias: Assist timer finished or cancelled
condition:
- condition: template
value_template: "{{ trigger.from_state != trigger.to_state }}"
alias: "Timer was active or paused"
action:
- delay:
seconds: 3
alias: "Delay for Timer Reached automation"
- alias: "Reset timer location"
service: input_text.set_value
target:
entity_id: "{{ 'input_text.' + trigger.entity_id[6:] + '_location' }}"
data:
value: ""
mode: parallel
timer:
assist_timer1:
name: "Assist - Timer 1"
icon: mdi:assistant
restore: true
assist_timer2:
name: "Assist - Timer 2"
icon: mdi:assistant
restore: true
assist_timer3:
name: "Assist - Timer 3"
icon: mdi:assistant
restore: true
input_text:
assist_timer1_location:
name: "Assist - Timer 1 Location"
icon: mdi:assistant
max: 255
assist_timer2_location:
name: "Assist - Timer 2 Location"
icon: mdi:assistant
max: 255
assist_timer3_location:
name: "Assist - Timer 3 Location"
icon: mdi:assistant
max: 255
intent_script:
TimerStart:
async_action: false
action:
- service: script.assist_TimerStart
data:
duration: "{{hours | int(default=0)}}:{{ minutes | int(default=0) }}:{{ seconds | int(default=0) }}"
TimerStop:
async_action: true
action:
- service: script.assist_TimerStop
data:
entity_id: "{{ entity_id }}"
TimerPause:
async_action: true
action:
- service: script.assist_TimerPause
data:
entity_id: "{{ entity_id }}"
timer_action: "{{ timer_action }}"
TimerDuration:
async_action: true
action:
- stop: ""
I’m also still not getting my media file to play…
Any idea what could be wrong?