Set a timer using HA Assist

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…

3 Likes

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… :grin:

1 Like

Nice! Will look into that. Im actually working on a timer package to get a simpler but working solution. Nearly done.

2 Likes

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

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 :slight_smile: glad to share my projects.
Regarding your questions:

  1. 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.
  1. 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!
1 Like

Great, thanks so much, I’ll update my config. Have a great weekend!!

1 Like

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?