Media_player.alexa and volume control

After converting all my alexa-ttl scripts and automations over to notify.alexa_media (without issue, thank you), I wish to continue this transition by setting some volume levels on the echo-speak. Is there a new format/syntax for setting volume now?

Never mind. I think I found a workaround for my scripting/automations. Using two services separated by a two second pause seems to reliably work if you don’t mind the beep at the beginning. The cludge-code sample looks like this:

dash_button_test:
  alias: Dash Button Test
  sequence:
  - service: media_player.volume_set
    data:
      entity_id: media_player.406_living_room_echo_dot
      volume_level: '0.8'
  - delay: '00:00:02'
  - service: notify.alexa_media
    data:
      target:
        - media_player.406_living_room_echo_dot
      message: Hey Dude, how is your programming going?
      data:
        type: tts
5 Likes

Thanks alos using volume_set in my play_radio script.
I have ported this script over from my old automation system and have the folllowing now:

alias: Alexa Play Radio
sequence:
  - service: media_player.play_media
    data:
      entity_id: '{{ alexa_device }}'
      media_content_id: '{{ alexa_station }}'
      media_content_type: TUNEIN
  - delay:
      hours: 0
      minutes: 0
      seconds: 2
      milliseconds: 0
  - service: media_player.volume_set
    data_template:
      entity_id: '{{ alexa_device }}'
      volume_level: '{{ alexa_volume }}'
  - delay:
      hours: 0
      minutes: 0
      seconds: 2
      milliseconds: 0
  - service: media_player.volume_set
    data_template:
      entity_id: '{{ alexa_device }}'
      volume_level: '{{ alexa_volume }}'
  - delay:
      hours: 0
      minutes: 0
      seconds: 2
      milliseconds: 0
  - service: media_player.volume_set
    data_template:
      entity_id: '{{ alexa_device }}'
      volume_level: '{{ alexa_volume }}'
  - condition: template
    value_template: '{{ alexa_show_startpage == 1 }}'
  - delay:
      hours: 0
      minutes: 0
      seconds: 4
      milliseconds: 0
  - service: media_player.play_media
    target:
      entity_id: '{{ alexa_device }}'
    data:
      media_content_type: custom
      media_content_id: zeige start bildschirm
mode: parallel
max: 20

The multiple call to volume set is because i had the issue on my old system that the new volume can just be set when alexas was playing → thus setting it multiple times solved the issue on my old system.

Now i have the following error in my logs often:

2022-04-01 11:52:37 WARNING (MainThread) [alexapy.helpers] alexaapi.set_volume((<alexapy.alexaapi.AlexaAPI object at 0xffff78056ee0>, 0.32), {}): An error occured accessing AlexaAPI: An exception of type AlexapyTooManyRequestsError occurred. Arguments:
('Too Many Requests',)

So my question is:
Is your approach (set voume, wait 2 secs & do alexa mediaplayer action) reliable and also working?

thank you

Thanks for this sample code, i spring boarded off your code here and added a follow up to return the echo to a reasonable volume after the announcement and also reduced some unnecessary dead time in-between the first volume change the and announcement.

alias: Close the doors
sequence:
  - service: media_player.volume_set
    data:
      entity_id: media_player.echo_studio
      volume_level: '1'
  - delay: '00:00:01'
  - service: notify.alexa_media
    data:
      target:
        - media_player.echo_studio
      message: Close the fooking door
      data:
        type: tts
  - delay: '00:00:01'
  - service: media_player.volume_set
    data:
      entity_id: media_player.echo_studio
      volume_level: '0.5'
mode: single

2 Likes

I did another work on the previous examples. I store the initial volume level and restore it after the announcement. I created an input_number helper to do so (hint: The variables feature of a script may be more straight forward).

I made some surprising observations. The delay sets the length of time until the next adjustment of the volume is done. The spoken language is independent from this.

Hence, the length of the delay has to match the length of the spoken text. To get a little pause and not have to match the millisecond, I append a short pause to the text by the break tag of SSML. Just play a little with those values to get a nice blending of spoken words and the playing music.

Another observation is, to call the announcement first and then to push up the volume. Doing it the other way results in an ugly climax of the music just before the announcement.

alias: Close the door
sequence:
  - service: input_number.set_value
    data:
      value: "{{ state_attr('media_player.beta', 'volume_level') | default(0.5, true) | float }}"
    target:
      entity_id: input_number.previous_volume_of_beta
  - service: notify.alexa_media
    data:
      target: media_player.beta
      message: >-
        <break time="500ms"/> It's cold outside. Please shut the door! <break
        time="1500ms"/>
      data:
        type: announce
  - service: media_player.volume_set
    data:
      volume_level: 0.8
    target:
      entity_id: media_player.beta
  - delay:
      hours: 0
      minutes: 0
      seconds: 6
  - service: media_player.volume_set
    data:
      volume_level: "{{ states('input_number.previous_volume_of_beta') | float }}"
    target:
      entity_id: media_player.beta
mode: single
icon: mdi:door-open

Perfect! Elmar. Thank you very much!
But in my case it gave error and did not go back to the previous volume.
So I used it like this, and it’s working perfectly!

alias: Alexa diz Ola Paty
sequence:
  - service: notify.alexa_media_echo_show_capo
    data:
      target: media_player.echo_show_capo
      message: >-
        <break time="500ms"/> Olá, estranha! Que bom que você apareceu por aqui!
        Seja bem vinda! Estou ligando a TV pra vocĂŞ! Se quiser pode me chamar
        dizendo, "Alexa!", ligue o ar condicionado, ou, desligue a TV! A
        temperatura agora está
        {{states("sensor.openweathermap_temperature")|round(0)}} graus! A
        PrevisĂŁo para amanhĂŁ Ă© de {{states("sensor.weather_conditions_pt")}},
        com temperatura mĂ­nima de 
        {{(state_attr('weather.openweathermap','forecast')[1].templow)|round(0)
        }}, e máxima de
        {{(state_attr('weather.openweathermap','forecast')[1].temperature)|round(0)
        }} graus. Fique Ă  vontade e sinta-se em casa! <break time="1500ms"/>
      data:
        type: announce
  - service: media_player.volume_set
    data:
      volume_level: 0.8
    target:
      entity_id: media_player.echo_show_capo
  - delay:
      hours: 0
      minutes: 0
      seconds: 34
      milliseconds: 0
  - service: media_player.volume_set
    data:
      volume_level: 0.4
    target:
      entity_id: media_player.echo_show_capo
mode: single
icon: mdi:cast-audio

1 Like

@vacari:

Yes the timing matters a lot and even may depend upon the device. I am still working upon an improved version. There are significant differences in the timing between announce and tts. tts in fact needs two delays. Even for tts I start the speaking before controlling the volume flow contrary to the above scripts.

Sorry guys for not adding an update after my first post above.
Here are my current scripts:

Play radio:

alias: Alexa Play Radio
sequence:
  - service: media_player.volume_set
    data_template:
      entity_id: "{{ alexa_device }}"
      volume_level: "{{ alexa_volume }}"
  - delay:
      hours: 0
      minutes: 0
      seconds: 2
      milliseconds: 0
  - service: media_player.play_media
    data:
      entity_id: "{{ alexa_device }}"
      media_content_id: "{{ alexa_station }}"
      media_content_type: TUNEIN
  - condition: template
    value_template: "{{ alexa_show_startpage == 1 }}"
  - delay:
      hours: 0
      minutes: 0
      seconds: 10
      milliseconds: 0
  - service: media_player.play_media
    target:
      entity_id: "{{ alexa_device }}"
    data:
      media_content_type: custom
      media_content_id: zeige start bildschirm
mode: parallel
max: 20

To call it:


                  - service: script.turn_on
                    target:
                      entity_id: script.alexa_play_radio
                    data:
                      variables:
                        alexa_device: media_player.badezimmer
                        alexa_volume: 0.23
                        alexa_station: Life Radio Oberösterreich
                        alexa_show_startpage: 1

Announcment single:

alias: Alexa AnkĂĽndigung Einzeln
sequence:
  - variables:
      old_volume: "{{ state_attr(alexa_device , 'volume_level')|float(0) }}"
  - service: media_player.volume_set
    data_template:
      entity_id: "{{ alexa_device }}"
      volume_level: "{{ alexa_volume_speak }}"
  - delay:
      hours: 0
      minutes: 0
      seconds: 1
      milliseconds: 0
  - service: "{{ alexa_service }}"
    data:
      message: "{{ alexa_message }}"
      data:
        type: announce
        method: all
  - delay:
      hours: 0
      minutes: 0
      seconds: 10
      milliseconds: 0
  - service: media_player.volume_set
    data_template:
      entity_id: "{{ alexa_device }}"
      volume_level: "{{ old_volume }}"
mode: parallel
max: 20

to call it:

  - service: script.alexa_announce
    data_template:
      alexa_device: media_player.badezimmer
      alexa_service: notify.alexa_media_badezimmer
      alexa_volume_speak: 0.8
      alexa_message: Achtung, Achtung! Wasser wird heiĂź in 5 4 3 2 1 0...

Have fun

1 Like

So far my final service. It works for the types tts and announce. It has been tested with Echo 4th generation and Echo Dot 3rd generation.

alias: Alexa say
description: Say something with an Alexa device (tts or announce)
variables:
  # length of a pause before speaking, to adjust the volume without noise
  pause: "{{ 1.7 if type == 'tts' else 0.0 | float }}"
  # the gong replaces the pause in case of `announce`
  gong: "{{ 1,7 if type == 'announce' else 0.0 | float }}"
  # store the original volume to reset it later
  # set a default because of the empty value, when no music is playing
  reset: "{{ state_attr(target, 'volume_level') | default(0.5, true) | float }}"
fields:
  message:
    description: the message (SSML)
    example: <amazon:effect name="whispered">Please close the door.</amazon:effect>
    required: true
  type:
    description: tts or announce
    example: tts
    required: true
  target:
    description: the target devise as a string
    example: media_player.beta
    required: true
  volume:
    description: the volume of the speach
    example: 0.7
    required: true
  duration:
    description: the length of the speach in seconds
    example: 3.3
    required: true
sequence:
  # start up the speaking before controlling the volume, to avoid a moment of yelling music
  - service: notify.alexa_media
    data:
      target: "{{ target }}"
      # but delay the words until the volume is adjusted in case of `tts`
      # in case of `announce` the pause is zero as the gong did this job
      message: >-
        <break time='{{ pause + 0.2 | float }}s'/> {{ message }} <break
        time='1s'/>
      data:
        type: "{{ type }}"
  # a pause in case of `tts`
  # zero in case off `announce`, we want a loud gong
  - delay:
      hours: 0
      minutes: 0
      seconds: "{{ pause | float }}"
      milliseconds: 0
  # tune up
  - service: media_player.volume_set
    data:
      volume_level: "{{ volume }}"
    target:
      entity_id: "{{ target }}"
  # tuned for the length of the spoken text
  # plus the length of gong if any
  - delay:
      hours: 0
      minutes: 0
      seconds: "{{ gong + duration | float }}"
      milliseconds: 0
  # reset the old volume
  - service: media_player.volume_set
    data:
      volume_level: "{{ reset | float }}"
    target:
      entity_id: "{{ target }}"
  # wait until Alexa adjusted to the old volume before doing the next one in the queue
  - repeat:
      while:
        - condition: template
          value_template: >-
            {{ (reset | float) != (state_attr(target, 'volume_level') | float)  }}
      sequence:
        - delay:
            hours: 0
            minutes: 0
            seconds: 1.5
            milliseconds: 0
    # TODO: prevent an endless loop
mode: queued
max: 5
icon: mdi:bullhorn

Use announce:

type: announce
message: >-
  <p>It's <emphasis level="strong">cold</emphasis> outside.</p>
  <p><amazon:effect name="whispered">Please close the door!</amazon:effect></p>
target: media_player.beta
volume: 0.8
duration: 4.7

Use tts:

type: tts
message: >-
  <p>It's <emphasis level="strong">cold</emphasis> outside.</p>
  <p><amazon:effect name="whispered">Please close the door!</amazon:effect></p>
target: media_player.beta
volume: 0.8
duration: 4.7
1 Like

Limitations

My above script is in queue mode. Running it in parallel mode with parallel calls would end up in a mess. The increased volume of the first run would be taken as the original volume of the parallel run.

The queue if fine for one device, but I also can’t speak to multiple devices at the same time, because the queue is on the level of the script. I use it to remind to close an open door. It would make sense to talk into both rooms at the same time. Ideally the queue should work on per target level. Any idea how to improve this?