Google home - set volume up and back again

Sure there is. I use a script for that. I will post it later. Here you go:
scripts.yaml:

announce_downstairs:
  alias: 'Announce downstairs'
  sequence:
    - service: media_player.volume_mute  # The first part gets rid of the default Google Home bloop-bloop sound. First mutes the speaker...
      data:
        entity_id: media_player.googlehome_downstairs
        is_volume_muted: true
    - service: media_player.play_media  # then plays a random 1 second silent track ...
      data:
        entity_id: media_player.googlehome_downstairs
        media_content_type: music
        media_content_id: "{{ states('input_text.base_url') + '/local/audio/1sec.mp3' }}"
    - delay:
        seconds: 1
    - service: media_player.volume_set  # then sets the desired volume ...
      data:
        entity_id: media_player.googlehome_downstairs
        volume_level: >-
          {% if now().hour > 18 or now().hour < 7 %} 0.35
          {% else %} 0.65
          {% endif %}
    - service: media_player.volume_mute  # only then unmutes, so you don't hear the volume changing sounds
      data:
        entity_id: media_player.googlehome_downstairs
        is_volume_muted: false
    - service: media_player.play_media  # then it plays a nice ding-dong sound
      data:
        entity_id: media_player.googlehome_downstairs
        media_content_type: music
        media_content_id: "{{ states('input_text.base_url') + '/local/audio/announcement.mp3' }}"
        # My base_url is contained in an input_text, so that I could put it in secrets.yaml. You can just put the external url to your HA frontend here. NB an internal url won't work in my experience.
    - delay:
        seconds: 2
        # milliseconds: 800
    - service: tts.google_say  # then finally here's your TTS message :-)
      data:
        entity_id: media_player.googlehome_downstairs
        message: "{{my_message}}"

Calling the script from an automation:

    - service: script.announce_downstairs
      data:
        my_message: "Have a great day"
8 Likes

@Emphyrio wow must try today. May I ask you for your nice ding dang? I have only Scarry dong dang kong. Thank you :blush:

I see you have volume-setting capabilities in your script, but I don’t see anything that saves the previous volume setting and restores it after the announcement. Have you figured out a way to acquire the current volume setting before you make changes? Restoring should be pretty simple after that.

3 Likes

I will try to figure that out for you.

Here are the sounds (1 second of silence + announcement sound).

3 Likes

Here’s an adaptation that also restores the volume to its original volume, after the announcement.

announce_downstairs:
  alias: 'Announce downstairs'
  sequence:
    - service: media_player.volume_mute  # The first part gets rid of the default Google Home bloop-bloop sound. First mutes the speaker...
      data:
        entity_id: media_player.googlehome_downstairs
        is_volume_muted: true
    - service: media_player.play_media  # then plays a random 1 second silent track ...
      data:
        entity_id: media_player.googlehome_downstairs
        media_content_type: music
        media_content_id: "{{ states('input_text.base_url') + '/local/audio/1sec.mp3' }}"
    - delay:
        seconds: 1
    - service: input_number.set_value  # store the current volume level (should be after playing 1sec because only then the volume_level attribute is available)
      data:
        entity_id: input_number.current_volume
        value: "{{ state_attr('media_player.googlehome_downstairs','volume_level') }}"
    - service: media_player.volume_set  # then sets the desired volume for the announcement ...
      data:
        entity_id: media_player.googlehome_downstairs
        volume_level: >-
          {% if now().hour > 18 or now().hour < 7 %} 0.35
          {% else %} 0.65
          {% endif %}
    - service: media_player.volume_mute  # only then unmutes, so you don't hear the volume changing sounds
      data:
        entity_id: media_player.googlehome_downstairs
        is_volume_muted: false
    - service: media_player.play_media  # then it plays a nice ding-dong sound
      data:
        entity_id: media_player.googlehome_downstairs
        media_content_type: music
        media_content_id: "{{ states('input_text.base_url') + '/local/audio/announcement.mp3' }}"
        # My base_url is contained in an input_text, so that I could put it in secrets.yaml. You can just put the external url to your HA frontend here. NB an internal url won't work in my experience.
    - delay:
        seconds: 2
        # milliseconds: 800
    - service: tts.google_say  # then finally here's your TTS message :-)
      data:
        entity_id: media_player.googlehome_downstairs
        message: "{{my_message}}"
    - delay:   # Set this delay for the maximum length of your announcement messages
        seconds: 4
    - service: media_player.volume_mute  # Again, muting to prevent volume changing sounds
      data:
        entity_id: media_player.googlehome_downstairs
        is_volume_muted: true
    - service: media_player.volume_set
      data:
        entity_id: media_player.googlehome_downstairs
        volume_level: "{{ states('input_number.current_volume') }}"
    - delay:
        seconds: 1
    - service: media_player.volume_mute
      data:
        entity_id: media_player.googlehome_downstairs
        is_volume_muted: false

This requires an input_number to be defined in configuration.yaml:

input_number:
  current_volume:
    name: 'Current volume'
    min: 0
    max: 1

Although in the latest HA versions you might be able to use an on-the-fly variable, but I haven’t used that before so there’s that.

7 Likes

Thank you very much @Emphyrio

I took @Emphyrio’s example above and parameterized it to make it easier to use generically - i.e. use any media_player entity (or several!), use a specificed volume, etc.

First, a setup script:

# Turns on Google smart speaker(s), bypassing the Google chime by muting
#
# Args:
#   announcement_volume (float): speaker volume_level for announcement (0 <= x <= 1)
#   player_id (entity or list of entities): media_player(s) on which to play announcement
#
# Usage Example:
#     - service: script.google_speaker_announcement_startup
#       data:
#         announcement_volume: "{{ states('input_number.volume_announcement') }}"
#         player_id: media_player.office_display, media_player.family_room_speaker
google_speaker_announcement_startup:
  alias: 'GoogleSpeakerAnnouncementStartup'
  sequence:
    - service: media_player.volume_mute
      data:
        entity_id: "{{ player_id }}"
        is_volume_muted: true
    - delay:
        milliseconds: 200
    - service: media_player.play_media
      data:
        entity_id: "{{ player_id }}"
        media_content_type: music
        media_content_id: "{{ states('input_text.home_assistant_url_internal') + '/local/sounds/silence-1sec.mp3' }}"
    - delay:
        seconds: 1
    - service: media_player.volume_set
      data_template:
        entity_id: "{{ player_id }}"
        volume_level: "{{ announcement_volume }}"
    - delay:
        seconds: 2
    - service: media_player.volume_mute
      data:
        entity_id: "{{ player_id }}"
        is_volume_muted: false
    - service: media_player.play_media
      data:
        entity_id: "{{ player_id }}"
        media_content_type: music
        media_content_id: "{{ states('input_text.home_assistant_url_internal') + '/local/sounds/announcement_chime.mp3' }}"
    - delay:
        seconds: 3

Note that I’ve found this eliminates the Google chime most of the time, but not all of the time. I played with lots of variations of this sequence in terms of order, timing, etc., and haven’t gotten it to be silent 100% of the time. But this one is close…

Then there’s a shutdown script:

# Turns off Google smart speaker(s), restoring volume to default
#
# Args:
#   player_id (entity or list of entities): media_player(s) to shut down
#
# Usage Example:
#     - service: script.google_speaker_announcement_shutdown
#       data:
#         player_id: media_player.office_display, media_player.family_room_speaker
google_speaker_announcement_shutdown:
  alias: 'GoogleSpeakerAnnouncementShutdown'
  sequence:
    - service: media_player.volume_set
      data_template:
        entity_id: "{{ player_id }}"
        volume_level: "{{ states('input_number.volume_smart_speaker_default') }}"
    - delay:
        seconds: 1
    - service: media_player.turn_off
      data:
        entity_id: "{{ player_id }}"

And finally, there’s the announcement itself:

# Plays an TTS announcement on Google smart speaker(s) with specificed volume
#
# Args:
#   announcement_length (int): number of seconds to delay after starting announcement
#                              before assuming it has completed
#   announcement_message (string): message used as input to text-to-speech
#   announcement_volume (float): speaker volume_level for announcement (0 <= x <= 1)
#   player_id (entity or list of entities): media_player(s) on which to play announcement
#
# Usage Example:
#     - service: script.announce
#       data:
#         announcement_length: 10
#         announcement_message: "This is a test.  This is only a test of the Home Asssistant alert system."
#         announcement_volume: "{{ states('input_number.volume_announcement') }}"
#         player_id: media_player.office_display, media_player.family_room_speaker
announcement:
  alias: 'Announcement'
  sequence:
    - service: script.google_speaker_announcement_startup
      data:
          player_id: "{{ player_id }}"
          announcement_volume: "{{ announcement_volume}}"
    - service: tts.cloud_say
      data:
        entity_id: "{{ player_id }}"
        message: "{{ announcement_message  }}"
    - delay:
        seconds: "{{ announcement_length }}"
    - service: script.google_speaker_announcement_shutdown
      data:
          player_id: "{{ player_id }}"

So to use this, you just call the script.announce from an automation or other script, as shown in the example above.

2 Likes

Also, to address @Jiran’s original question (how to restore the volume to its previous level after the announcement), I tried this:

announcement_with_volume_restore:
  alias: 'AnnouncementWithVolumeRestore'
  variables:
    previous_volume: >
      "{% if is_state('media_player.office_display', 'playing') 
          or is_state('media_player.office_display', 'on') 
          or is_state('media_player.office_display', 'paused')
      %} 
        {{ state_attr('media_player.office_display', 'volume_level') | float | round(2) }} 
      {% else %}
        {{ states('input_number.volume_smart_speaker_default') | float | round(2) }}
      {% endif %}"       
  sequence:
    - service: script.google_speaker_announcement_startup
      data:
          player_id: "{{ player_id }}"
          announcement_volume: "{{ announcement_volume}}"
    - service: tts.cloud_say
      data:
        entity_id: "{{ player_id }}"
        message: "{{ announcement_message  }}"
    - delay:
        seconds: 10
    - service: media_player.volume_set
      data_template:
        entity_id: "{{ player_id }}"
        volume_level: "{{ previous_volume }}"  # doesn't seem to be a float, and casting as float makes it 0
    - service: media_player.turn_off
      data:
        entity_id: "{{ player_id }}"

That example has the entity for the previous volume hardcoded to a specific media player since I was experimenting. If the device is off (not playing), the above works by restoring the value of volume_smart_speaker_default to the device after the announcement.

In the case of the device being originally in the playing state, the value of previous_volume is saved and able to be read back with a second TTS call. However, when trying to restore the volume (line with comment above), it complains about it not being a float. If I cast it as a float (add | float), then the volume is restored as a value of zero.

I’ve tried a bunch of stuff to get this part to work, but haven’t been successful. Other ideas welcome!

1 Like

My adapted script works for me to restore the volume. It doesn’t for you?

Apparently I can’t read. :slight_smile:

I read your post above as setting up a static input_number to have as the restored value and missed that you were calling the service to set it within the script. My bad.

That works as long as you don’t have multiple announcements going at the same time… which I’m guessing for most people would be rare.

Any thoughts on how to do it without adding an extra input_number to keep things simpler?

Oh how to decide which one is better? :slight_smile:

Yes, use a variable :upside_down_face:

Hi all!

Fantastic post and love the solution by you, @Emphyrio. I also tried to implement a minimal setup as a script, however, when running it, I do script/automation that calls it does not turn back the volume. Here is what I implemented:

broadcast_msg_single_device:
  alias: 'Broadcast a message on a single device'
  sequence:
    - service: tts.google_say
      data_template:
        entity_id: "{{ device_name }}"
        message: "{{ msg }}"
        language: "{{ lang }}"
    - delay:
        seconds: 2
    - service: input_number.set_value
      data_template:
        entity_id: input_number.current_volume
        value: "{{ state_attr( device_name ,'volume_level') }}"
    - service: media_player.volume_set
      data_template:
        entity_id: "{{ device_name }}"
        volume_level: 0.7
    - service: tts.google_say
      data_template:
        entity_id: "{{ device_name }}"
        message: "{{ msg }}"
        language: "{{ lang }}"
    - delay:
        seconds: 2
    - service: media_player.volume_set
      data_template:
        entity_id: "{{ device_name }}"
        volume_level: "{{ states(input_number.current_volume) }}"
    - service: tts.google_say
      data_template:
        entity_id: "{{ device_name }}"
        message: "{{ msg }}"
        language: "{{ lang }}"

It still plays the second message but not the third anymore. When commenting out the following command, then also the 3rd message is played:

    - service: media_player.volume_set
      data_template:
        entity_id: "{{ device_name }}"
        volume_level: "{{ states(input_number.current_volume) }}"

Would appreciate if you had any idea how to solve this. Probably some beginner’s issue :wink:. Thank you!

My guess would be it has something to do with the delays. After sending the TTS command, it takes some time to process (generate the audio file, send the command to the speaker, download & play the audio file). If you send a new command in the meantime, like setting the volume, it might interfere.

So I would add some bigger delays after your tts.google_say commands.

You should be posting the error you’re getting in the log to help people diagnose your issue. In this case the problem is easy to spot. You’re missing some quotes. Volume level parameter also requires a float value.

volume_level: "{{ states(input_number.current_volume) }}"

Should be.

volume_level: "{{ states('input_number.current_volume')|float }}"

Thanks, @jazzyisj & @Emphyrio. Indeed it was a combination of issues - the quotes were missing, I had to do a cast to float, and a major issue was that the variable was never defined. Making use fo the log certainly helps here … beginner’s fault :grimacing:

Is there a way to define a variable within a script locally so that it only exists there, that there are no conflicts with potentially equally named variables in other scripts, and to make sure that it is always defined for that script independent of any “global” setups? I am not referring to variables that should be passed to that script, but indeed only ones to be used within the script, like the current volume one here.

Is there a way to define a variable within a script locally

First section on this page.

Thanks, Jason. I am still stuggling (as a newbie) with the basics of setting a specific value to a variable. As some code snippets, I would have assumed that it works like the following, but obviously some major flaws in there as it doesn’t even recognize the service:

script:
  variables:
    var_number: 0.5
  sequence:
    - service: variable.set_variable
      data_template:
        variable: "{{ var_number }}"
        value: 0.3

Would anybody be able to point me to the (probably obvious) mistakes here and how to handle such variables? Unfortunately the “Scripts” link doesn’t explain that and also some additional searching hasn’t led to anything. Thanks again!

Looks like you are mixing up automation/script variables and one of the custom variable integrations. Where did you come up with the set_variable service you tried to use? You also didn’t name your script!

You really need to read the link I sent before and this link carefully. If you’re trying to write scripts and don’t understand the basic format you’re going to be in for a very frustrating time!

Once you’ve read those if you still have questions, fire away…

Here’s a quick example to demonstrate how to change a variable value within a script. Put this in your config, reload your scripts, execute this script, then look at your log to see the result.

script:
  test_variable:
    variables:
      var_number: 0.5
    sequence:
      - variables:
          var_number: 0.3
      - service: system_log.write
        data:
          message: "var_number value: {{ var_number }}"