Sonos Group Status

Hi, I was thinking of a feature request to add an attribute to Sonos media players that display the status of the speaker as grouped or ungrouped. I would like to build a Whole-Home Audio switch for my Sonos speakers but I don’t think there’s currently a way of getting it’s current status. Thanks

Okay.

1 Like

Awesome. Thanks

Am I overlooking something here but all this does is set is_coordinator: true on a speaker that’s grouped OR not grouped…?

If I group Speaker B to the master Speaker A, A will show is_coordinator: true and B will show is_coordinator: false

If I don’t group them, A will show is_coordinator: true and B will show is_coordinator: true

How is this at all useful for determining speaker status?

I agree, it’s not incredibly useful. I did add a template sensor that compares the song title and if the same as the coordinator to consider it in a group. It’s a hack but it does work.

So what are you actually looking for?

I can’t speak for @timdonovanuk but I’d personally think having attributes for which speakers are grouped together.

Either in the master speaker have an array with the slaves

or the slave speakers have an attribute identifying which speaker is it’s master.

I am looking at this now. I am planning to add a coordinator attribute if the speaker is a slave, a coordinates attribute if the speaker is a master or no attribute if the speaker plays on its own.

Would that work?

I will then probably remove is_coordinator because it can be inferred from the above and, as you said, it is not that useful anyway.

@amelchio Yes, I think that would work. Would make this a lot easier to do. Thanks

I made a proposal: https://github.com/home-assistant/home-assistant/pull/13553

It would be great if you are able to test it as a custom_component so we can make sure that these attributes are more useful.

@amelchio Testing it now as a custom component. So it looks like:

  1. master speaker returns “coordinates” and the entity_id’s of the slaves
  2. slave speakers return attribute “coordinator” and the entity_id of the master
  3. speakers not group return no attribute

I’ll rework my automations to get the controls with this setup. But so far looks good

@amelchio So the one feedback I have is this makes it more difficult to figure out which sonos media_players aren’t in a group and are not the master when scanning all media_players in a loop since the following returns all media_players that don’t have an attribute called “coordinates”. Is it possible to add an attribute for sonos speakers that aren’t in a group something like “independant”?

  sonos_not_group_slaves:
    friendly_name: Not Group Slaves
    value_template: >-
      {% for player in states.media_player if not player.attributes.coordinator -%}
        {{player.entity_id}}
      {%- endfor %}

The following will list players that are independent but I guess your issue is that it also lists non-Sonos media players?

{% for player in states.media_player if not player.attributes.coordinator and not player.attributes.coordinates -%}
    {{player.entity_id}}
{%- endfor %}

Yes exactly. For grouping players, we need to unjoin players that are no longer in the group so there needs to be a way to determine which those are without sending every non sonos media_players.

I thought it would be excessive with three separate attributes so now I tried something slightly different. The PR now adds a sonos_group attribute to all Sonos players. This lists the entire group that the player is a part of, with the coordinator/master player listed first.

This should allow you to:

  1. identify Sonos players (the sonos_group attribute exists)
  2. identify independent players (sonos_group | length == 1)
  3. identify grouped players (sonos_group | length > 1)
  4. identify group masters (sonos_group[0] == entity_id)
  5. identify group slaves (sonos_group[0] != entity_id)

Let me know what you think :slight_smile:

@amelchio This works much better! I’ll test it out more this weekend and see if anything breaks but so far so good

@Jer78 did you complete testing? It would be great if you could comment in the PR. Cheers!

@amelchio
I’m just having one issue I can’t get passed but my lack of jinja skills is the problem. I keep getting errors because there’s a space in the sonos_group attribute. Here’s what I have…

I tried this and it returns “unknown”

  sonos_group_slaves:
    friendly_name: Group Slaves
    entity_id: sensor.sonos_group_master
    value_template: >-
      {%- for player in states.media_player if player.state == 'playing' and player.attributes.sonos_group %}
      {%- if player.attributes.sonos_group[0] == player.entity_id %}
        {% set n = player.attributes.sonos_group|length %}
        {% set slaves = "" %}
        {%- for player in player.attributes.sonos_group %}
          {% set slave = player.attributes.sonos_group[n] %}
          {% set slaves = [slaves,slave]|join(",") %}
        {% endfor -%}
        {{slaves|replace("media_player", "input_boolean")}}
      {% endif -%}
      {%- endfor %}

This was my original but it returns the right players but one of them has a “/n” line break that I need to get rid of.

  sonos_group_slaves:
    friendly_name: Group Slaves
    entity_id: sensor.sonos_group_master
     value_template: >-
       {%- for player in states.media_player if player.state == 'playing' and player.attributes.sonos_group %}
       {%- if player.attributes.sonos_group[0] == player.entity_id %}
         {%- set master = [player.entity_id,","]|join("") -%}
         {%- set slaves = player.attributes.sonos_group|replace(master, "") -%}
         {{slaves|replace("media_player", "input_boolean")|replace("[", "")|replace("]", "")|replace("'", "")}}
       {% endif -%}
       {%- endfor %}

Any ideas?

@Jer78

I am not quite sure what you are trying to do. Does this help?

       {%- for player in states.media_player if player.state == 'playing' and player.attributes.sonos_group %}
       {%- if player.attributes.sonos_group[0] == player.entity_id %}
         {%- set slaves = player.attributes.sonos_group[1:] %}
         {{ slaves|join(",")|replace("media_player", "input_boolean") }}
       {%- endif %}
       {%- endfor %}
1 Like

@amelchio Perfect. This works. Thanks for your help. I think the PR is ready to go.