Grouping Sonos Speakers

Hey there, complete noob here. I have been trying this in my developer hassio image and have not had any success. I used that hassio image and placed everything with the config file ( removed the call outs to automation, scripts, groups…etc.). I have debugged it to this error:

"16:47:43 WARNING (Recorder) [homeassistant.components.recorder] Ended unfinished session (id=4 from 2018-08-17 16:45:21.686237)
2018-08-17 16:47:44 WARNING (MainThread) [homeassistant.components.http] You have been advised to set http.api_password.
2018-08-17 16:48:05 WARNING (MainThread) [homeassistant.setup] Setup of config is taking over 10 seconds.
2018-08-17 16:48:21 WARNING (MainThread) [homeassistant.components.input_select] Invalid option: (possible options: Bathroom, Brandon Bedrooom)
2018-08-17 16:48:21 ERROR (MainThread) [homeassistant.core] Invalid service data for input_boolean.turn_on: Entity ID is an invalid entity id for dictionary value @ data[‘entity_id’]. Got ‘’
2018-08-17 16:48:21 ERROR (MainThread) [homeassistant.core] Invalid service data for input_boolean.turn_off: Entity ID is an invalid entity id for dictionary value @ data[‘entity_id’]. Got ‘’
"

Sorry for how ugly this is going to look, but here is the config file:

# Attempt to Change Sonos

input_boolean:
sonos_bathrooom_slave:
name: Bathroom
sonos_brandon_bedroom_slave:
name: Brandon Bedroom

input_select:
master_sonos:
name: Master Sonos Player
icon: mdi:itunes
options:
- Bathroom
- Brandon Bedrooom
#Senor
sensor:

  • platform: yr

  • platform: template
    sensors:
    sonos_join_speakers:
    entity_id:
    - input_boolean.sonos_bathroom_slave
    - input_boolean.sonos_brandon_bedroom_slave
    value_template: >-
    {% set master = states.sensor.sonos_group_master.state %}
    {% for player in states.media_player -%}
    {%- set domain, device = player.entity_id.split(’.’) -%}
    {%- set new_domain = “input_boolean” -%}
    {%- set new_device = [device, “slave”]|join("") -%}
    {%- set switch = [new_domain,new_device] | join(".") -%}
    {%- if is_state(switch, ‘on’) and player.entity_id != master -%}
    {{player.entity_id}},
    {%- endif -%}
    {%- endfor %}
    sonos_unjoin_speakers:
    entity_id:
    - input_boolean.sonos_brandon_bedroom_slave
    - input_boolean.sonos_bathroom_slave
    value_template: >-
    {% set master = states.sensor.sonos_group_master.state %}
    {% for player in states.media_player -%}
    {%- set domain, device = player.entity_id.split(’.’) -%}
    {%- set new_domain = “input_boolean” -%}
    {%- set new_device = [device, “slave”]|join("
    ") -%}
    {%- set switch = [new_domain,new_device] | join(".") -%}
    {%- if is_state(switch, ‘off’) and player.entity_id != master -%}
    {{player.entity_id}},
    {%- endif -%}
    {%- endfor %}
    sonos_not_group_slaves:
    friendly_name: Not Group Slaves
    value_template: >-
    {% for player in states.media_player if player.attributes.is_coordinator -%}
    {%- if loop.last -%}{{player.entity_id}}–
    {%- else -%}{{player.entity_id}};
    {%- endif -%}
    {%- endfor %}
    sonos_group_slaves:
    friendly_name: Group Slaves
    value_template: >-
    {% for player in states.media_player if player.state == ‘playing’ and not player.attributes.is_coordinator -%}
    {%- if loop.last -%}{{player.entity_id}}–
    {%- else -%}{{player.entity_id}};
    {%- endif -%}
    {%- endfor %}

    sonos_group_song:
    friendly_name: Group Song
    value_template: >-
    {% for player in states.media_player if player.state == ‘playing’ and not player.attributes.is_coordinator %}
    {{player.attributes.media_title}}
    {% endfor %}
    sonos_group_master:
    entity_id:
    - sensor.sonos_group_song
    value_template: >-
    {% set group_song = states.sensor.sonos_group_song.state %}
    {% for player in states.media_player if player.state == ‘playing’ and player.attributes.is_coordinator and player.attributes.media_title in group_song %}
    {{player.entity_id}}
    {% endfor %}
    #Automation
    automation:

  • alias: ‘Set Sonos States’
    initial_state: on
    trigger:

    • platform: state
      entity_id: sensor.sonos_group_slaves
    • platform: state
      entity_id: sensor.sonos_not_group_slaves
    • platform: state
      entity_id: sensor.sonos_group_master
    • platform: homeassistant
      event: start
      action:
    • service: input_select.select_option
      data_template:
      entity_id: input_select.master_sonos
      option: >-
      {% set master = states.sensor.sonos_group_master.state %}
      {% if master == “media_player.sonos_bathroom_room”%}Bathroom
      {% elif master == “media_player.sonos_brandon_bedrooom_room”%}Brandon Bedroom
      {% endif %}
    • service: input_boolean.turn_on
      data_template:
      entity_id: ‘{%- set slaves = states.sensor.sonos_group_slaves.state -%}{{slaves|replace("–", “_slave”)|replace(";", "_slave, ")|replace(“media_player”, “input_boolean”)}}’
    • service: input_boolean.turn_off
      data_template:
      entity_id: ‘{%- set slaves = states.sensor.sonos_not_group_slaves.state -%}{{slaves|replace("–", “_slave”)|replace(";", "_slave, ")|replace(“media_player”, “input_boolean”)}}’
      #Script
      script:
      sonos_group_speakers:
      sequence:
    • service: media_player.sonos_join
      data_template:
      master: >-
      {% if is_state(“input_select.master_sonos”, “Bathroom”) %}media_player.sonos_bathroom
      {% elif is_state(“input_select.master_sonos”, “Brandon Bedroom”) %}media_player.sonos_brandon_bedroom
      {% endif %}
      entity_id: ‘{%- set slaves = states.sensor.sonos_join_speakers.state -%}{{slaves[:-1]}}’
    • service: media_player.sonos_unjoin
      data_template:
      entity_id: ‘{%- set slaves = states.sensor.sonos_unjoin_speakers.state -%}{{slaves[:-1]}}’
      #Script
      group:
      sonos_grouping_options:
      view: no
      name: Group Sonos Players
      control: hidden
      entities:
    • input_select.master_sonos
    • input_boolean.sonos_bathroom_slave
    • input_boolean.sonos_brandon_bedroom_slave
    • script.sonos_group_speakers

I have verified the names of the sonos devices through the entity registry.
media_player.brandon_bedroom:
media_player.bathroom:

Thank you all in advance for the help!

(Sorry for the formatting, i’m searching now to see if I can fix that)

Hi there, complete noob here.
I’m starting the automations in my house. I have a Sonos system, which consists 1xBeam
1xSub
2xOne
but they are all grouped to surround sound and the two sonos one are set to the back speaker right and left. With the oficial application sometimes I take 1xsonos one and take it to another division of the house and then just add it back to the group as back speaker right or left.
With this setting can I do the same through the home assistant or just play simultaneously on all?

Sorry for my english,
Thanks um advance,

Best Regards,

I’m really not sure what happens when speakers are grouped together within the Sonos app as a stereo setup. Does the Sonos component show all the speakers separately as media_players?

They show up as one. So a 5.1(playbase,sub,2 ones) show up as living room or whatever. A second 5.1 (playbar,sub,2 ones) show up as a single entity say basement. even if you have 2 ones in a stereo pair they show up as a single entity…which is perfect in my mind…

Im still waiting for a clean way to do the groupings, hopefully soon. I seen an article not to long ago they opened up the api some more or something, i need to check it out.

Thanks, i will try my luck, and see what i can do. I will be checking for updates. Thanks again

I am having a hard time trying to set this up, not sure if anyone would have any ideas.

I am getting the following error:
ERROR (MainThread) [homeassistant.core] Invalid service data for media_player.sonos_unjoin: Entity ID is an invalid entity id for dictionary value @ data[‘entity_id’]. Got ‘’

I am using the newer code posted above, the only difference is that my speakers are named “sonoslivingroom” instead of “living_room” and I’ve made the changes throughout.

Also in the script section, I’ve retyped the single quotes as sometimes these don’t come across well when you do a cut and paste.

Thanks

@berniebl
Can you post exactly what you are using so I can troubleshoot what’s wrong?

Thanks Jeremy,

I am sure that it may be something really stupid that I missed, but I looked at this close so much that it all seems normal to me now. Here is what I have:

In Input_Boolean.yaml

  living_room:
    name: Living Room
  office:
    name: Office
  kitchen:
    name: Kitchen

In Input_Select.yaml

  master_sonos:
    name: Master Sonos Player
    icon: mdi:itunes
    options:
      - Living Room
      - Office
      - Kitchen

In Sensors.yaml

  - platform: template
    sensors:
      sonos_join_speakers:
        entity_id:
          - media_player.sonoslivingroom
          - media_player.sonoskitchen
          - media_player.sonosoffice
        value_template: >-
         {% set master = states.sensor.sonos_group_master.state %}
         {% for player in states.media_player -%}
           {%- set domain, device = player.entity_id.split('.') -%}
           {%- set new_domain = "input_boolean" -%}
           {%- set switch = [new_domain,device] | join(".") -%}
           {%- if is_state(switch, 'on') and player.entity_id != master -%}
             {{player.entity_id}},
           {%- endif -%}
         {%- endfor %}
      sonos_unjoin_speakers:
        entity_id:
          - media_player.sonoslivingroom
          - media_player.sonoskitchen
          - media_player.sonosoffice
        value_template: >-
         {% set master = states.sensor.sonos_group_master.state %}
         {% for player in states.media_player -%}
           {%- set domain, device = player.entity_id.split('.') -%}
           {%- set new_domain = "input_boolean" -%}
           {%- set switch = [new_domain,device] | join(".") -%}
           {%- if is_state(switch, 'off') and player.entity_id != master -%}
             {{player.entity_id}},
           {%- endif -%}
         {%- endfor %}

      sonos_group_master:
        entity_id:
          - media_player.sonoslivingroom
          - media_player.sonoskitchen
          - media_player.sonosoffice
        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 %}
              {{player.entity_id}}
            {% endif %}
          {% endfor -%}
      sonos_not_group_slaves:
        friendly_name: Not Group Slaves
        entity_id: sensor.sonos_group_slaves
        value_template: >-
          {% for player in states.media_player if player.attributes.sonos_group %}
          {% set n = player.attributes.sonos_group %}
            {%- if n|length == 1 -%}
              {{player.entity_id}},
            {%- endif -%}
          {%- endfor %}

      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 slaves = player.attributes.sonos_group[1:] %}
            {{ slaves|join(",")|replace("media_player", "input_boolean") }}
          {%- endif %}
          {%- endfor %}

In Automation.yaml

  - alias: 'Set Sonos States'
    initial_state: on
    trigger:
      - platform: state
        entity_id: sensor.sonos_group_slaves
      - platform: state
        entity_id: sensor.sonos_not_group_slaves
      - platform: state
        entity_id: sensor.sonos_group_master
      - platform: homeassistant
        event: start
    condition:
      condition: and
      conditions:
        - condition: template
          value_template: '{% if states.sensor.sonos_group_slaves.state != "" and states.sensor.sonos_group_master.state != "" %}true{%endif%}'
    action:
      - service: input_select.select_option
        data_template:
          entity_id: input_select.master_sonos
          option: >-
            {% set master = states.sensor.sonos_group_master.state %}
            {% if "media_player.sonoslivingroom" in master %}Living Room
            {% elif "media_player.sonoskitchen" in master%}Kitchen
            {% elif "media_player.sonosoffice" in master%}Office
            {% endif %}
      - service: input_boolean.turn_on
        data_template:
          entity_id: '{{states.sensor.sonos_group_slaves.state}}'
      - condition: template
        value_template: '{% if not is_state("sensor.sonos_not_group_slaves", "")%}true{%endif%}'
      - service: input_boolean.turn_off
        data_template:
          entity_id: '{%- set slaves = states.sensor.sonos_not_group_slaves.state -%}{{slaves[:-1]|replace("media_player","input_boolean")}}'

In Scripts.yaml

  sonos_group_speakers:
    sequence:
      - service: media_player.sonos_join
        data_template:
          master: >-
            {% if is_state("input_select.master_sonos", "Living Room") %}media_player.sonoslivingroom
            {% elif is_state("input_select.master_sonos", "Office") %}media_player.sonosoffice
            {% elif is_state("input_select.master_sonos", "Kitchen") %}media_player.sonoskitchen
            {% endif %}
          entity_id: '{%- set slaves = states.sensor.sonos_join_speakers.state -%}{{slaves[:-1]}}'
      - service: media_player.sonos_unjoin
        data_template:
          entity_id: '{%- set slaves = states.sensor.sonos_unjoin_speakers.state -%}{{slaves[:-1]}}'  

in Groups.yaml

sonos_grouping_options:
  view: no
  name: Group Sonos Players
  control: hidden
  entities:
    - input_select.master_sonos
    - input_boolean.kitchen
    - input_boolean.living_room
    - input_boolean.office
    - script.sonos_group_speakers

Before I attempt this, is this still working with current version? Any updates I should be aware of?

Thank you!

Not sure if you got this working (please let me know if you did), but from my noob experience, the dictionary value error is the result of formatting errors. You either have inconsistent spacing or you have something with a value where it should actually be blank.

I have a sonos in my kitchen this is powered via a switch (unfortunately – can’t easily change either).
I would like to join to other Sonos when playing.
Do you know how to query to find master? I believe your automation above assumes/joins living_room. But what if living_room is not controller?

Thanks in advance for any advice.

~Bryan

Getting the following error when I execute the script:

Error executing service <ServiceCall script.sonos_group_speakers (c:643dc753a0374e61b6894cfe3a9c05c1)>
Traceback (most recent call last):
File “/usr/local/lib/python3.6/site-packages/homeassistant/core.py”, line 1130, in _safe_execute
await self._execute_service(handler, service_call)
File “/usr/local/lib/python3.6/site-packages/homeassistant/core.py”, line 1143, in _execute_service
await handler.func(service_call)
File “/usr/local/lib/python3.6/site-packages/homeassistant/components/script.py”, line 123, in service_handler
context=service.context)
File “/usr/local/lib/python3.6/site-packages/homeassistant/components/script.py”, line 181, in async_turn_on
kwargs.get(ATTR_VARIABLES), context)
File “/usr/local/lib/python3.6/site-packages/homeassistant/helpers/script.py”, line 130, in async_run
await self._handle_action(action, variables, context)
File “/usr/local/lib/python3.6/site-packages/homeassistant/helpers/script.py”, line 172, in _handle_action
action, variables, context)
File “/usr/local/lib/python3.6/site-packages/homeassistant/helpers/script.py”, line 261, in _async_call_service
context=context
File “/usr/local/lib/python3.6/site-packages/homeassistant/helpers/service.py”, line 81, in async_call_from_config
domain, service_name, service_data, blocking=blocking, context=context)
File “/usr/local/lib/python3.6/site-packages/homeassistant/core.py”, line 1101, in async_call
processed_data = handler.schema(service_data)
File “/usr/local/lib/python3.6/site-packages/voluptuous/schema_builder.py”, line 267, in call
return self._compiled([], data)
File “/usr/local/lib/python3.6/site-packages/voluptuous/schema_builder.py”, line 589, in validate_dict
return base_validate(path, iteritems(data), out)
File “/usr/local/lib/python3.6/site-packages/voluptuous/schema_builder.py”, line 427, in validate_mapping
raise er.MultipleInvalid(errors)
voluptuous.error.MultipleInvalid: Entity ID is an invalid entity id for dictionary value @ data[‘entity_id’]

My script code is:

sonos_group_speakers:
    sequence:
      - service: media_player.sonos_join
        data_template:
          master: >-
            {% if is_state("input_select.master_sonos", "Playbar") %}media_player.sonos_playbar
            {% elif is_state("input_select.master_sonos", "Man Cave") %}media_player.sonos_man_cave
            {% elif is_state("input_select.master_sonos", "Parlour") %}media_player.sonos_parlour
            {% elif is_state("input_select.master_sonos", "Lovenest") %}media_player.sonos_lovenest
            {% elif is_state("input_select.master_sonos", "Breakfast Nook") %}media_player.sonos_breakfast_nook
            {% elif is_state("input_select.master_sonos", "Cabana") %}media_player.sonos_cabana
            {% elif is_state("input_select.master_sonos", "Roamer") %}media_player.sonos_roamer
            {% endif %}
          entity_id: '{%- set slaves = states.sensor.sonos_join_speakers.state -%}{{slaves[:-1]}}'
      - service: media_player.sonos_unjoin
        data_template:
          entity_id: '{%- set slaves = states.sensor.sonos_unjoin_speakers.state -%}{{slaves[:-1]}}'

@ berniebl, I seem to be having the same issue. Were you able to figure out what was wrong? Like you, I really want to get this working but this thread seems to have dried up.

No, never got it resolved, I did review my code several times and could not find anything out of the ordinary. I will be setting up another instance of HA during the holiday season, I may give this one more shot. Keep us posted if you find a fix

Sorry to hear that. Would be great if the OP or someone else could help us both out :-). I really, REALLY want this working. Such a cool feature that is much needed for my setup.

With different types of setups and configurations, I don’t hold the OP or developer responsible to make sure that everything works for everyone. I am just happy that talented folks can share their hard work and talent to the community and help some of us that are a little more programmatically challenged. If they can spot a quick mistake to assist, I am grateful, but sicne this is working for the majority of folks, I tent to think that it’s either a mistake on my side or my setup is just a little different than others.

1 Like

I completely agree. I don’t hold anyone responsible or have any expectations. That being said, I would love to get this working lol.

Currently, when I execute, the “master player” ungroups in the Sonos app, but nothing else seems to group together. I’ve checked and double checked my code against what has been posted and can’t seem to locate any differences.

I do have my scrips in a scripts.yaml file, so it seems to require slightly different indentations from what has been posted in the config.yaml or I get config errors.

I’m happy to detail all my code, but hate to continue cluttering up this thread if it is dead.

Hey everyone, I’m really sorry I’ve been MIA lately. I started a new job recently and its been consuming a lot of my time.

Here’s an update on this project. Everything still works for me, but I do agree, due to the complexity of setting this up it’s really not ideal.

However, there is some good news! :slight_smile:

If you are using lovelace, you’ll probably be interested in Karl’s @kalkih Mini Media Player. He recently added Sonos grouping support and it’s MUCH easier to setup vs. my poor hacking attempt above, not to mention offers a lot more in customization over the current built in media player component.

And if you’re not on lovelace, this just might be a reason to look into it now. I would love to help everyone get this working but I also don’t want to give false hopes since my free time lately has been next to nothing. :frowning:

But if anyone wants to get my solution working, I may have a little bit of time this weekend, so shoot my a PM and I will try to help the best I can!! Thanks everyone!

3 Likes

Thanks, @Jer78, after sonos supports group/ungroup services, with some guide from Phil’s blog, I have also create a different version using sonos group/ungroup services and eaiser to maintain. Happy to share it in Music Follow Me - Sonos Speakers Group/Ungroup Automation