Script to resume Google Cast devices after they have been interrupted by any action

You can test it by checking the attributes of the media player in developer tools > states.

If you then use the service media_player.play_media in developer tools > services with the media_content_id and the media_content_type from the previous step, and that works, the script should work as well.

I guess that could be the case when a speaker group is playing, and a TTS (or other action) is only sent to one of the group members.

I can fix that, I need to check for the member states as well then, but that is an easy fix.

Update

Version 1.7.4/1.7.5 - 23 March 2022

:star2: Improvements

  • (1.7.5) Replaces fixed delays with wait templates so there is no unneeded delay in resuming (for example when only a short TTS is sent)

:bug: Bug fixes

  • Added a check if all members of a speaker group are idle or off before resuming the stream to avoid resuming to early (in case a group was playing, but the action causing the interruption was only sent to one of the members) (possible fix for the issue of @bomba23 )
  • (1.7.5) Fixed retrieving volume for players which were in state off

Thank you very much for you work, I just discovered and implemented your script and it works like a charm!

What I would like to know is how people fix the issue with delayed and cut off TTS messages in groups?!

I have 8 nest mini speakers in one group and when playing TTS messages some always start a bit later and therefore skip the first 1-2 seconds or so. I tried different things like setting the volume for all devices and adding stuff like “@ @ @” before my messages but this is either annoying or doesnt work every time…

You could send the TTS to the individual devices instead of the group, but then they won’t be synced.

Update

Version 1.7.6 - 24 March 2022

:bug: Bug fixes

  • Fix for wait template to determine if resume can be started (it was starting too soon)

Just wanted to let you know I really like your integration. I was thinking how I could solve the problem of the interruption and found your script. Thanks for your work!

Thanks for the coffee!

1 Like

Hi good work, however I have some issue with the script.


I saw an error on this line, can it be the reason?

- alias: Perform service calls defined in action
    repeat:
      count: '{{ service_calls | count }}'
      sequence:
      - service: '{{ service_calls[repeat.index -1].service }}'
        target: '{{ service_calls[repeat.index -1].get(''target'', {}) }}'
        data: '{{ service_calls[repeat.index -1].get(''data'', {}) }}'

data: '{{ service_calls[repeat.index -1].get(''data'', {}) }}' complaining with the: Incorrect type. Expecting “object”

And just to be sure, if I run internet radio like that (enabling it via routines) will your script work?

sequence:
  - service: tts.google_say
    data:
      entity_id: media_player.living_room_speaker
      language: en
      message: Chill House incoming
  - delay:
      hours: 0
      minutes: 0
      seconds: 3
      milliseconds: 0
  - service: media_player.play_media
    data:
      media_content_id: https://radiorecord.hostingradio.ru/chillhouse96.aacp
      media_content_type: audio
    target:
      device_id: df205a766947919fb814c96d6a7f4097
  - delay:
      hours: 0
      minutes: 0
      seconds: 3
      milliseconds: 0
  - service: media_player.media_play
    data: {}
    target:
      device_id: df205a766947919fb814c96d6a7f4097
mode: single
alias: Record Chill House

UPD: played a bit with the variables. Looks like if I leave the variable empty e.g. players_screen: it breaks.

btw, i am not sure why, but my nest mini takes some time to buffer the radio stream, however the script above speeds it up drastically. So whenever I try to use your calls service it is a long wait before it resumes, with playing my script inside your script makes it way better (or you could potentially add media_play part inside your script.

Could you send a trace of the Resume script (by uploading it to a site like codepile.net). I can use that to determine where the error is caused.

My script uses the same service call as your script, so there should be no delay caused by the script. Did you use the last version, because the versions before could indeed have a short delay.

Here you go.

As I mentioned this happens when I do this

variables:
    players_screen:
    speaker_groups:
    primary_spotcast: pavel
    default_volume_level: 0.25

in the script, which maybe is completely wrong (out of touch with yaml), but I assumed it will see it as empty and will simply continue. After removing these empty variables it works.

About the delay. I am not sure why it happens, but for some reason radio streams are buffering ~20 seconds taking into account I have gigabit internet. I read that some people had this issue on some other radio stations as well and they recommended to use this workaround by adding media_play command explaining it as there is some magic delay between google nest executing cast command and actually playing the sound, thus by forcing it manually fixes the problem. Strange tho. Can you try my script and see if you get a delay or is it instant?

- service: media_player.play_media
    data:
      media_content_id: https://radiorecord.hostingradio.ru/chillhouse96.aacp
      media_content_type: audio
    target:
      device_id: DEVICE_ID

In my case the delay is 30s

After removing these empty variables it works.

I can’t reproduce this, I can see in the trace where it goes wrong, but with players_screen: null and fixed_picture: null that template renders without issues for me. However I did add additional checks for a value in those variables now, so please give 1.7.6.1 a try (will update topic start after confirmation if this helps)

Regarding the service call, the script uses media_player.play_media. The main difference is that I use the entity_id and not the device_id.

This would have been the service call for resuming in your case, could you check if that works without delay?

service: media_player.play_media
target:
  entity_id: media_player.living_room_speaker
data:
  media_content_id: https://radiorecord.hostingradio.ru/chillhouse96.aacp
  media_content_type: no type
  extra:
    metadata:
      metadataType: 3
      title: no title
      artist: no artist

I’ve tested this myself in developer tools > services with an entity_id of my own, and it works without delay.

Could you send a trace of script.google_home_resume_perform_resume as well, so I can check if something is going wrong there?

so please give 1.7.6.1

Can you point me where exactly is the updated script? I didn’t find it in the github (checked PRs, branches, forks, commits :slight_smile: )

I have tried your service call in a vacuum without any resume scripts and it doesn’t change anything. I still get ~20 sec delay before music starts playing. It is something with the HA itself and how it handles music streams.

I then tried to launch the script you sent, launch TTS with the resume script and I got the same result. It took about 20 seconds to launch the music back. It is not a big deal, i can always incorporate the workaround in the music launch script, but it is strange tho.

here is the perform_resume stacktrace:

Still delay cca 30s, but it is not about your script.

This automation helps me:

alias: A call to media_player.media_play
description: ''
trigger:
  - platform: state
    entity_id: media_player.YOURSPEAKER
    to: idle
condition: []
action:
  - delay:
      seconds: 1
  - service: media_player.media_play
    data: {}
    target:
      entity_id: media_player.YOURSPEAKER
mode: single

Hi @kasiopec

For me 1.6.7.1 shows here.
This part has changed (around line 515):

    - variables:
        player_data_enriched: >
          {%- set ns = namespace(info=[]) %}
          {%- for entity in player_data %}
            {%- set members = speaker_groups[entity.entity_id]
                              if speaker_groups is defined
                                and iif(speaker_groups)
                                and entity.entity_id in speaker_group_list
                              else []
            %}
            {%- set screen = players_screen is defined
                              and iif(players_screen)
                              and entity.entity_id in players_screen
            %}
            {%- set type = iif(members,'group',iif(screen,'screen','no screen')) %}
            {%- set additional =  dict(members = members, type = type) %}
            {%- if entity.app_name == 'Spotify' %}
              {%- set list_check = [ entity.entity_id ] + members %}
              {%- set names_check = expand(list_check) | map(attribute='name') | list %}
              {%- set spotcast = spotify_data
                                  | selectattr('source', 'in', names_check)
                                  | map(attribute='entity_id')
                                  | join
                                  | replace('media_player.spotify_', '')
              %}
              {% set spotcast = iif(spotcast, spotcast, primary_spotcast) %}
              {% set spotcast = iif(spotcast == primary_spotcast, 'primary_account', spotcast) %}
              {%- set add_spotcast =  dict(spotcast = spotcast) %}
              {%- set additional = dict(additional, **add_spotcast) %}
            {%- elif entity.state == 'playing'
                      and fixed_picture is defined
                      and iif(fixed_picture)
                      and entity.media_artist in fixed_picture.keys() | list
            %}
              {%- set add_picture = dict(fixed_picture = fixed_picture[entity.media_artist]) %}
              {%- set additional = dict(additional, **add_picture) %}
            {%- elif entity.state == 'off' %}
              {%- set volume = state_attr(entity.entity_id, 'volume_level') %}
              {%- set volume = volume if volume | is_number else default_volume_level %}
              {%- set add_volume = dict(volume_level = volume) %}
              {%- set additional = dict(additional, **add_volume) %}
            {%- endif %}
            {%- set ns.info = ns.info + [ dict(entity, **additional) ] %}
          {%- endfor %}
          {{ ns.info }}

Also interesting for @Manazer maybe:

I’m not sure what is causing this delay then, for me it starts within a second using the service call I posted above from developer tools > services. But I can add a short delay and the media_player.media_play service call.

I’ve done that in 1.7.6.2 now

This has changed (around line 900)

                - alias: "Stream?"
                  conditions: "{{ stream }}"
                  sequence:
                    - variables:
                        picture_url: "{{ player.fixed_picture if player.fixed_picture is defined else player.entity_picture }}"
                        metadata:
                          metadataType: 3
                          title: "{{ player.media_title }}"
                          artist: "{{ player.media_artist }}"
                        picture:
                          images:
                            - url: "{{ picture_url }}"
                    - alias: "Resume stream"
                      service: media_player.play_media
                      target:
                        entity_id: "{{ player.entity_id }}"
                      data:
                        media_content_id: "{{ player.media_content_id }}"
                        media_content_type: "{{ player.media_content_type }}"
                        extra:
                          metadata: >
                            {{ medadata if picture_url == 'no pic' else dict(metadata, **picture) }}
                    - delay: 2
                    - alias: "Player still idle?"
                      choose:
                        - conditions: "{{ is_state(player.entity_id, 'idle') }}"
                          sequence:
                            - alias: "Play"
                              service: media_player.media_play
                              target:
                                entity_id: "{{ player.entity_id }}"

Disabled my automation (delayed call to media_player.media_play), tried resume on 1.7.6.2, this error appears:

Logger: homeassistant.core
Source: components/cast/media_player.py:658
First occurred: 4:27:10 PM (1 occurrences)
Last logged: 4:27:10 PM

Error executing service: <ServiceCall media_player.play_media (c:450f2dc30e4abde9f61072971d28e73b): entity_id=['media_player.google_home'], extra=, media_type=audio/mp4, media_id=https://stream......../.......mp3>
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/core.py", line 1654, in catch_exceptions
    await coro_or_task
  File "/usr/src/homeassistant/homeassistant/core.py", line 1673, in _execute_service
    await cast(Callable[[ServiceCall], Awaitable[None]], handler.job.target)(
  File "/usr/src/homeassistant/homeassistant/helpers/entity_component.py", line 204, in handle_service
    await self.hass.helpers.service.entity_service_call(
  File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 671, in entity_service_call
    future.result()  # pop exception if have
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 949, in async_request_call
    await coro
  File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 708, in _handle_entity_call
    await result
  File "/usr/src/homeassistant/homeassistant/components/cast/media_player.py", line 658, in async_play_media
    await self.hass.async_add_executor_job(
  File "/usr/local/lib/python3.9/concurrent/futures/thread.py", line 58, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/usr/local/lib/python3.9/site-packages/pychromecast/quick_play.py", line 77, in quick_play
    controller.quick_play(**data)
  File "/usr/local/lib/python3.9/site-packages/pychromecast/controllers/media.py", line 665, in quick_play
    self.play_media(media_id, media_type, **kwargs)
  File "/usr/local/lib/python3.9/site-packages/pychromecast/controllers/media.py", line 566, in play_media
    raise PyChromecastError()
pychromecast.error.PyChromecastError

Hmm, there seems to be something wrong with a service call for media_player.play_media but I did not make any change to that service call. I only added media_player.media_play.

Are you sure this is caused by the script? Can you use media_player.play_media from developer tools > service with similar arguments without errors?

@TheFes
Ok, 7.6.1 changes are working. Now the script is executing even if I have empty variables. I guess this one is fixed.

However 7.6.2 did nothing. Again, it is not your script problem, but HA acting strange. Like if you say it is instant on your side then it is definitely some HA problem or chromecast. Maybe because I run it as a docker container etc.

Btw, are you using nest mini? Maybe it is nest problem.

7.6.2 should do the same as your script does, so first send the url to stream, and then send a media play command.
It could be that the media player doesn’t show as idle, could you send another trace maybe?