So right now with the Sonos component, you can join and unjoin speakers with a service but the problem is, you can’t tell which speakers are currently in a group. There’s only an attribute called is_cooridinator. It will be true if it’s in a group and the master or if it’s not in a group and playing on its own. So the only real way to figure out a group is to first search for players that is_coordinator is false, then get the song name, finally find the one that’s true playing the same song. It’s a real roundabout way of doing this but currently the only way given the current state of this component. Hopefully one day it’s not needed but for now…it’s nice to control groups from HA. As for a master volume, maybe once you know which players are in the group send a volume control +/- to all the speakers. But as for reading the current state of mixed volumes might be difficult.
Is this because of the naming of the input_boolean’s?
@Coolie1101
Yes, but you could name the input_booleans the same and not have to add _slave to the end. I just already had some names that.
Also You may want to wait before adding this as there is some changes coming to the Sonos component soon. Probably in the next release that will impact this project. It is a little simpler after the update.
Okay.
I’m having a little trouble understanding the following statement.
Isn’t the names pulled from the players when added to HA?
I’m having difficulty having the volume sliders showing… just about everything else shows up though.
@Coolie1101 Yes, the media_players are pulled from HA, but the way it’s set up is the sensors look for media_players with the same name as the input_booleans. You can change the name to whatever you’d like but you’d need to modify the sensor so it matches them too.
In other words, if your Sonos player is called media_player.living_room, this template will look for an input_boolean.living_room_slave.
Got it, thanks.
Very cool! Nice work. Any chance you mind sharing how you got the sonos images for icons?
any idea what im missing here? my media_players are named like media_player.basement.
I am getting some errors like it is not getting the entity id for some reason. Ive been starring at this trying to find where it is messing up and cant narrow it down. I believe it is in the sensor. Since your were named a little differnet im wondering if i missed a change somewhere. I have a lot of other things tied to those entity names and it would be too much to change like you have. If you have a minute to take a look it would be appreciated.
Sensor:
- platform: template
sensors:
sonos_join_speakers:
entity_id:
- input_boolean.living_room_slave
- input_boolean.bedroom_slave
- input_boolean.basement_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.living_room_slave
- input_boolean.bedroom_slave
- input_boolean.basement_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 %}
script:
sonos_group_speakers:
sequence:
- service: media_player.sonos_join
data_template:
master: >-
{% if is_state("input_select.master_sonos", "Living Room") %}media_player.living_room
{% elif is_state("input_select.master_sonos", "Basement") %}media_player.basement
{% elif is_state("input_select.master_sonos", "Bedroom") %}media_player.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]}}'
automations:
- 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.living_room"%}Living Room
{% elif master == "media_player.bedroom"%}Bedroom
{% elif master == "media_player.basement"%}Basement
{% 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")}}'
input_select:
master_sonos:
name: Master Sonos Player
icon: mdi:itunes
options:
- Living Room
- Basement
- Bedroom
@darbos at first glance I can’t see anything wrong. What errors are you getting? It would be helpful to see those. Also, do you plan on updating right away to 0.67 when it comes? Because there are changes coming to the Sonos component with the grouping and you’ll have to change this if you plan on updating.
lol sorry about that. I meant to include them, too much pasting in forgot
Thats good to know I appreciate it. It really depends on what is released with the new updates if I go to them. If it something useful for me then I usally do them, or Ill take a snapshot in vmware, upgrade and see how it goes then if i need to I can revert. I am on 65.6 right now, I tried 66.0 but I just had that small bug with my ecobee, I believe they fixed it in 66.1 but I havent upgraded. Now knowing that sonos will be upated in 67 Ill just hold off and upgrade to upgrade until then. Still great work here!
I do have some family and friends coming in town this weekend and was trying to show off
If you see something pop out Id appreciate it, otherwise I can hang tight I dont want to waste your time.
IndexError: list index out of range
2018-04-11 19:10:56 WARNING (MainThread) [homeassistant.components.input_select] Invalid option: (possible options: Select Master, Living Room, Basement, Bedroom)
2018-04-11 19:10:56 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 ''
@Darbos Ok, yeah that error came up for me too. Here’s what I suggest, if you’re interested for something this weekend. Create a custom component using the latest sonos.py
Put this in .homeassistant/custom_components/media_player/ directory. If you don’t have it, create it. This way you can stay at 65.6 but use the latest Sonos.
Then here’s my latest yaml using this update. It’s a bit simplier.
Template Sensors:
sonos_join_speakers:
entity_id:
- media_player.living_room
- media_player.bedroom
- media_player.basement
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.living_room
- media_player.bedroom
- media_player.basement
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.living_room
- media_player.bedroom
- media_player.basement
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 %}
Use these Input Booleans instead:
living_room:
name: Living Room
basement:
name: Basement
bedroom:
name: Bedroom
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
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.living_room" in master %}Living Room
{% elif "media_player.bedroom" in master%}Bedroom
{% elif "media_player.basement" in master%}Basement
{% 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")}}'
Input Select:
master_sonos:
name: Master Sonos Player
icon: mdi:itunes
options:
- Living Room
- Basement
- Bedroom
Script:
sonos_group_speakers:
sequence:
- service: media_player.sonos_join
data_template:
master: >-
{% if is_state("input_select.master_sonos", "Living Room") %}media_player.living_room
{% elif is_state("input_select.master_sonos", "Basement") %}media_player.basement
{% elif is_state("input_select.master_sonos", "Bedroom") %}media_player.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]}}'
@Darbos and here’s the images I use for Sonos speakers. Put them in your www directory and reference them to your input_booleans in the customize section like this:
input_boolean.living_room:
entity_picture: /local/sonos_playbar.png
man your awesome. took the time to write it with my players and all, thank you very much!
Its working now I really appreciate it! I see now in the attributes it shows you sonos_group now. that is great!
Hey I was looking through the 67.0 notes and the sonos component page but dont see a mention of any changes to the grouping abilities? Did it not make it into 67? Thanks
@Darbos I looked for it too, doesn’t look like it made it into 0.67. Not sure why (I’m not the dev) but for now, you can keep running the custom component.
I appreciate it, was just curious.
@Jer78 I have been looking at this solution for some time, and now it seems that grouping capabilities made it into the 0.69 update https://github.com/home-assistant/home-assistant/pull/13553
Is there a chance that you are going to revise your scripts to incorporate this grouping scheme into this nice solution? I would be first in line to do some trying and testing