Is it possible to set volume on all google home speakers at same time without calling out each individually in target entities? Anyway to future proof for new speakers?

Hello all,

Could someone give me their thoughts/ possibly show an example of the subject if it is possible. I was building an automation for changing speaker volumes using time/ time of day binary sensors and these questions came up because I felt like I was “cave manning” the setup for this situation.

Below is what I have. I mean, it works. But the subject is the issues I already see with it so I’m not super happy but its where my abilities are at the moment.

I would love to hear/ see others thoughts about how to handle this better. (I have about 10 speakers, all of which are in various speaker groups within the google home ecosystem)—> would putting these into groups within HA do me any good or not really?

To make what I’ve done more understandable. I have another script (tts script) that catches both “current speaker volume” and “tts volume” at run time of that other script. Then to catch the standard set volume if I were to ask for music or something before the tts script was ran, I have the last caveman part where I set the volume on all speakers.

It all just seems less than efficient/ hacky-- maybe my expectations are too high. (I really don’t like the last part)-- Can I include google home groups in the last “entity id” area and it work properly, the next time I play music on a group?

Thank you all again.

alias: Change speaker volumes throughout day
description: ""
trigger:
  - platform: state
    entity_id:
      - binary_sensor.morning
      - binary_sensor.midday
      - binary_sensor.evening
    to: "on"
    id: daily_tts_volume
  - platform: state
    entity_id:
      - binary_sensor.morning
      - binary_sensor.midday
      - binary_sensor.evening
    id: daily_standard_volume
    to: "on"
condition: []
action:
  - choose:
      - conditions:
          - condition: trigger
            id: daily_tts_volume
        sequence:
          - service: input_number.set_value
            data:
              value: 0.6
            target:
              entity_id: input_number.tts_volume
      - conditions:
          - condition: trigger
            id: daily_standard_volume
        sequence:
          - service: input_number.set_value
            data:
              value: 0.6
            target:
              entity_id: input_number.current_speaker_volume
          - service: media_player.volume_set
            data:
              volume_level: 0.6
            target:
              entity_id:
                - media_player.back_porch_speaker
                - media_player.dining_room_wifi
                - media_player.front_porch_speaker
                - media_player.garage_speaker
                - media_player.guest_bathroom_speaker
                - media_player.guest_bedroom_speaker
                - media_player.gym_speaker
                - media_player.living_room_sonos_speaker
                - media_player.master_bathroom_speaker
                - media_player.master_bedroom_sonos_speaker
                - media_player.master_bedroom_speaker
                - media_player.office_wifi
    default: []
mode: single

I have a group of speakers setup in Google app. Then it will show up in HA with a volume control. Then when you get a new speaker add it to the group.

Google’s Groups do not work this way anymore since the sonos lawsuit I do not believe.

As far as I know since the Google / Sonos issue we are unable to set the volume on a Google speaker group.

As for making a HA group, I did this to send TTS and they were obviously not synchronised so I went back to calling TTS across the Google speaker groups and set volumes per entity like your example above. I cant say I ever tried to set volume via a HA group but in theory is would work but without any real benefit over calling them individually.

I personally just created 3 scenes, Daytime, Evening / Night and Important, all 3 scripts set the volumes per entity again like your above example with some set to different levels of volume based on location and or speaker size for example.

I then have an automation that sets them based on time of day and some automations that will capture there state, run the script to change them and revert them back if necessary, like important notices etc.

This is how I do it.

    default:
      - variables:
          speakers: "{{ entity_id }}"
      - repeat:
          count: "{{ speakers | count }}"
          sequence:
            - variables:
                speaker: "{{ speakers[repeat.index - 1] }}"
            - service: script.turn_on
              data:
                variables:
                  volume_level: |-
                    {{( (states(speaker.replace('media_player.','input_number.')
                      ~ '_volume')|default(0.5)|float(0.5)) - (quietfactor|float(0)) ) | float(0.5) }}
                  entity_id: "{{speaker}}"
              target:
                entity_id: script.media_player_volume_set_helper

With a helper:

alias: Media Player Volume Set Helper
sequence:
  - service: media_player.volume_set
    data:
      volume_level: "{{ volume_level|default(\"0.5\", true) | float}}"
      entity_id: "{{entity_id|default(\"no\", true)}}"
mode: parallel
fields:
  volume_level:
    description: volume_level to set
    example: 0.5
  entity_id:
    description: entity_id
    example: media_player.all_speakers
max: 10

Thank you for your reply @rossk

Thank you for responding to this part also. I can tell you know what I’m after because you’ve already been down the same road it sounds like.

So you think if I create a HA group with all of the speakers in it and then run the service for media player volume set, it will change the volume on all? This would be better than me calling out each individual speaker in each target area and would help with bypassing the google/ sonos spat.

Yeah, this is exactly what I’m after. Something like this. So you set yours on a per entity basis also. Hmmm.

Would you possibly share your 3 scripts and an example of how you are using the automation you speak of when you get time.

Your definitely doing what I’m after essentially, I’m just trying to figure out the cleanest way to go about it. My HA instance feels like such a mess sometimes.

Thank you @rossk, @calisro, and @Arh for your responses here. All very helpful

@calisro Thank you so much for this and the help you have given me in past post. I will take a good look at it to ensure I understand it and very possibly use it to make mine better. I’m definitely not at your level of abilities but maybe one day. haha

You can use scenes. For my case, I use just a variable. Not hte best solution. Look at this:

alias: Media Player Volume Set
sequence:
  - variables:
      quiet: >-
        {% if now() >
        now().replace(hour=20).replace(minute=0).replace(second=0).replace(microsecond=0) 
           or now() < now().replace(hour=8).replace(minute=0).replace(second=0).replace(microsecond=0) %}
          true
        {% else %}
          false
        {% endif %}
      quietfactor: "{% if quiet == \"true\" %}0.1{% else%}0{% endif %}"
  - variables:
      speakers: "{{ entity_id }}"
  - repeat:
      count: "{{ speakers | count }}"
      sequence:
        - variables:
            speaker: "{{ speakers[repeat.index - 1] }}"
        - service: script.turn_on
          data:
            variables:
              volume_level: |-
                {{( (states(speaker.replace('media_player.','input_number.')
                  ~ '_volume')|default(0.5)|float(0.5)) - (quietfactor|float(0)) ) | float(0.5) }}
              entity_id: "{{speaker}}"
          target:
            entity_id: script.media_player_volume_set_helper
mode: restart
fields:
  entity_id:
    description: The entity(s) to broadcast to
    example: media_player.back_office_speaker

The quiet factor is just subtracted from the ‘normal’ volume each time i set. I call this script each time I tts broadcast.

So I set the time when I’d like the tts announcement to be ‘softer’. and I subtract 10% from the volume during those times when I broadcast via the script. It works for me. I store all the ‘standard’ volumes per each google home in a input_number so that they always stay at that volume even after my kids adjust theirs when listiening to music. Its all very clumbsy but Google made it this way and its worse since the Sonos suit.

I have HA groups setup as mirrors of my google groups. So when I pass in what I am broadcasting to, it acts on the inidividual devices. You can see the ‘replace’ functions there.

If you get time, would you help me understand how all of your code is working, you are much more advanced than I am with this stuff.

I don’t really follow what all this is doing at all. replace?, default?, float?, quietfactor?

What is this thing doing?

Oh geeze, I have no clue what some of this is doing. Are those templates? Can you explain what is going on there when you have time.

Also “fields:”, “max:”, I’ve never seen that used before.

You’re making me feel like such a failure. lol

  - variables:
      quiet: >-
        {% if now() >
        now().replace(hour=20).replace(minute=0).replace(second=0).replace(microsecond=0) 
           or now() < now().replace(hour=8).replace(minute=0).replace(second=0).replace(microsecond=0) %}
          true
        {% else %}
          false
        {% endif %}
      quietfactor: "{% if quiet == \"true\" %}0.1{% else%}0{% endif %}"

This is the amount by which I will decrease the normal volume by during the time outside of the ‘quiet’ window.

  - variables:
      speakers: "{{ entity_id }}"

This is a variable that holds the entity id(s) passed to teh script.

  - repeat:
      count: "{{ speakers | count }}"

This just means repeat the below action for each entity_id defined in the ‘speakers’ variable.

      sequence:
        - variables:
            speaker: "{{ speakers[repeat.index - 1] }}"

This is just part of the loop. Moving to the next speaker in the passed set.

        - service: script.turn_on
          data:
            variables:
              volume_level: |-
                {{( (states(speaker.replace('media_player.','input_number.')
                  ~ '_volume')|default(0.5)|float(0.5)) - (quietfactor|float(0)) ) | float(0.5) }}
              entity_id: "{{speaker}}"
          target:
            entity_id: script.media_player_volume_set_helper

This called the helper script to adjust the volume for the ONE speaker. I do this in a script just so I can use the ‘turn_on’ service so the calling script does not wait. Helps it do it faster across all my google homes.

This is how you pass variables to a script from a calling script/service. See here:

@calisro Thank you so much for explaining all of this because I know it takes time. I really do appreciate it.

My God though. You must be a programmer for a living. haha

I’m done. I should’ve paid more attention in school in my programming classes. hahaha.

I will take some time over the next little bit to understand all of this and I may come back in the next few days with some followups.

Thank you again for giving me a thorough understanding of my options and another possible approach I can take on this concept.

So you said, you have mirrored your google home groups to home assistant groups. If you send a volume set service call to that HA group, does it work? Or am I completely off base and mixing concepts that don’t go together?

Yes you can call the group directly. I choose not to do that because I needed it to be flexible to set the volumes differently for each speaker in the groups or individually.

Yeah, I was thinking about that also. I’m sure what you’ve shown me will probably be my end approach. My stop gap will probably be what you just said because of the shortcoming that you/ I picked up on immediately.

Rob, thank you again for helping me understand this stuff. The water can get deep fast I’ve learned.

1 Like

If you’re interested, you can reduce this:

  - variables:
      quiet: >-
        {% if now() >
        now().replace(hour=20).replace(minute=0).replace(second=0).replace(microsecond=0) 
           or now() < now().replace(hour=8).replace(minute=0).replace(second=0).replace(microsecond=0) %}
          true
        {% else %}
          false
        {% endif %}
      quietfactor: "{% if quiet == \"true\" %}0.1{% else%}0{% endif %}"

to this:

  - variables:
      quiet: "{{ now() > today_at('20:00') or now() < today_at('08:00') }}"
      quietfactor: "{{ iif(quiet, 0.1, 0) }}"

EDIT

Another way to write this:

{{ now() > today_at('20:00') or now() < today_at('08:00') }}

is this:

{{ not today_at('08:00') < now() < today_at('20:00') }}

but it’s a bit less intuitive (because it refers to the time period that’s not “quiet”).

1 Like

@123 I honestly love when you chime in and shorten these yamls. I learn a lot. Thanks for that!

1 Like

@wtstreetglow
If you want to set it for all of your speakers of a certain integration you could use the following:

{{(expand(integration_entities("sonos"))|selectattr("domain","in","media_player")|map(attribute="entity_id")|list)}}

or when you need the device_ids:

{%set speakers = namespace(device_id=[])%}
{%for e in (expand(integration_entities("sonos"))|selectattr("domain","in","media_player")|map(attribute="entity_id")|list)%}
{%set speakers.device_id=speakers.device_id+[device_id(e)]%}
{%endfor%}
{{speakers.device_id}}

If you’re interested, the first template can be reduced to this:

{{ integration_entities('sonos') | select('match', 'media_player') | list }}

and the second one to this:

{{ integration_entities('sonos') | select('match', 'media_player') 
  | map('device_id') | list }}

@Grumblezz This is great. Thank you for adding this to the conversation. Very valuable. That was one of my issues also. I just was getting the low hanging fruit first and because I’m not super advanced with this stuff.

I can already see an issue in the future of a volume of 0.6 being much louder with sonos that a volume of 0.6 with the google home mini (and I guess, this issue would exist between devices also, not just manufacturer). I was hoping to work towards some type of volume “normalization” somehow at some point. Essentially, I have all of these ideas but not the capabilities to do them yet. haha.

1 Like

Thank you for this @123 I have no doubt I will use some of these ideas in the next little bit. You all are so much more advanced than I am. **sigh

Again, thank you for all of the help you have given me currently and in the past. I am very happy with HA. It makes so many other systems look so bad. But it is also extremely complex.