Is there a script to identify Sonos master and join a specific device to it?

I’ve got quite a few Sonos devices in my house and I’d like to set it up so that at the touch of a button in each room, it’ll seek out whichever device is the master and join that room’s player to the master (assuming at least one room is already playing).

I know there is an attribute for each player to show which device is the master for the group it’s in. My thought process is that the script could identify playing Sonos devices, then check the attribute for master to trigger the speaker to join that group but I have no idea how to make that happen.

I’ve looked at the Sonos auto-follow automation for Home Assistant but they don’t seem to detect the master, rather they connect to whichever device is assigned as the master.

My main concern in your solution is the trigger of the automation. If the speaker has nothing to play when you tap play on the speaker, it won’t do anything. If you manage to capture your trigger, it’s doable but might result in the speaker to shortly play something before it’s joined.

I decided to have all not playing speakers in the same area join the master of the speaker that started playing. So imagine,

  • I have 4 (individual) speakers in a Room_Area_1,
  • speaker 1 and 2 are in a group, where 2 is the master.
  • I toggle speaker 1, the automation is triggered and searches for non playing speakers in the same area (Room_Area_1) that are not yet in the same group as speaker 1. In this case it will join speaker 3 and 4 to the master of speaker 1 (which is the first speaker listed in attribute ‘group_members’).

What you want is mostly achievable, but you have to take a couple things into account:

  1. what if there is no playing group to join cause there is nothing playing?
    You of course could just have all speakers in the area join yours the speaker you toggled, but you have to work out your scenario and wonder why you would not always to that.
  2. what if the speaker has nothing to play, it won’t do anything so there is no trigger to capture?
  3. what if you use the app to stream something to (in my example) speaker 3?
    how do you decide the other speakers to join your speaker 3 or have speaker 3 join 1 and 2 if they are already playing?
  4. If you play a playlist using airplay (for example), every song results in a short pause → playing state, which will trigger your automation. What do you want to happen in which scenario?
    I bumped into this when I unjoined a specific speaker that was rejoined at the start of each new song. The challenge was that you in the other hand don’t want a delay in joining. If I remember correctly, I played with the from and to state combined with a time duration.

Anyway, it might be more challenging than you think right now. I have spend a lot of time tweaking my situation and I am happy to share some code. But what you want has a lot of challenges in it, because there is happening a lot that “you” are not aware of and bump into once you start “building”.

But, a piece of code you most likely need:

Get all speakers that are in the area of your triggering speaker that are playing

For testing you can fake the trigger in your template editor by using {% set trigger = namespace(entity_id="media_player.<your player>") %}

  area_entities(area_id(trigger.entity_id)) | select('is_device_attr', 'manufacturer', 'Sonos') | 
  select('match', '^media_player.') 
  ) | selectattr("state","eq","playing") | list

You can do a | map(attribute='entity_id') to just see the entity_id’s.
You also might want to reject the triggering speaker (or not)

Group master

The group master is easy to determine by using:

{{ state_attr(trigger.entity_id,"group_members")[0] }}

or use the entity ID instead of the variable 'trigger.entity_id"

{{ state_attr("media_player.<your player>","group_members")[0] }}

If I have more time, I can do more, but I hope this post helps you to get in the right direction.