Here’s my method of controlling Sonos volumes with HA syncing with the speakers. Coming soon is a method for controlling groups. I have the basic functionality working but have to work out a few bugs. Anyways, here’s some volume controls:
Input Numbers (use 1 per speaker. Note you may wish to play with the max number for comfortable levels)
sonos_guest_room_volume:
name: Guest Room Volume
min: 0
max: 60
step: 1
sonos_living_room_volume:
name: Living Room Volume
min: 0
max: 60
step: 1
sonos_master_bedroom_volume:
name: Master Bedroom Volume
min: 0
max: 60
step: 1
sonos_office_volume:
name: Office Volume
min: 0
max: 60
step: 1
sonos_basement_volume:
name: Basement Volume
min: 0
max: 100
step: 1
Sensors (you’ll need 2 per speaker. One is the volume from Sonos and the other compares if there’s a change between HA and Sonos, for use in the automations):
sonos_guest_room_volume:
value_template: >-
{% set volume = states.media_player.sonos_guest_room.attributes.volume_level %}
{% set new_volume = volume * 100 %}
{{ new_volume}}
sonos_guest_room_volume_changed:
value_template: '{% if (states.input_number.sonos_guest_room_volume.state | int) != (states.sensor.sonos_guest_room_volume.state | int ) %}true{%else%}false{% endif %}'
sonos_living_room_volume:
value_template: >-
{% set volume = states.media_player.sonos_living_room.attributes.volume_level %}
{% set new_volume = volume * 100 %}
{{ new_volume}}
sonos_living_room_volume_changed:
value_template: '{% if (states.input_number.sonos_living_room_volume.state | int) != (states.sensor.sonos_living_room_volume.state | int ) %}true{%else%}false{% endif %}'
sonos_master_bedroom_volume:
value_template: >-
{% set volume = states.media_player.sonos_master_bedroom.attributes.volume_level %}
{% set new_volume = volume * 100 %}
{{ new_volume}}
sonos_master_bedroom_volume_changed:
value_template: '{% if (states.input_number.sonos_master_bedroom_volume.state | int) != (states.sensor.sonos_master_bedroom_volume.state | int ) %}true{%else%}false{% endif %}'
sonos_office_volume:
value_template: >-
{% set volume = states.media_player.sonos_office.attributes.volume_level %}
{% set new_volume = volume * 100 %}
{{ new_volume}}
sonos_office_volume_changed:
value_template: '{% if (states.input_number.sonos_office_volume.state | int) != (states.sensor.sonos_office_volume.state | int ) %}true{%else%}false{% endif %}'
sonos_basement_volume:
value_template: >-
{% set volume = states.media_player.sonos_basement.attributes.volume_level %}
{% set new_volume = volume * 100 %}
{{ new_volume}}
sonos_basement_volume_changed:
value_template: '{% if (states.input_number.sonos_basement_volume.state | int) != (states.sensor.sonos_basement_volume.state | int ) %}true{%else%}false{% endif %}'
Automations (the first is to set the volume from Sonos and the second is to send volume from HA):
- alias: 'Sonos Set Input Number From Sonos Volume'
initial_state: on
trigger:
- platform: state
entity_id: sensor.sonos_living_room_volume_changed
to: 'true'
for:
seconds: 2
- platform: state
entity_id: sensor.sonos_guest_room_volume_changed
to: 'true'
for:
seconds: 2
- platform: state
entity_id: sensor.sonos_master_bedroom_volume_changed
to: 'true'
for:
seconds: 2
- platform: state
entity_id: sensor.sonos_office_volume_changed
to: 'true'
for:
seconds: 2
- platform: state
entity_id: sensor.sonos_basement_volume_changed
to: 'true'
for:
seconds: 2
- platform: homeassistant
event: start
action:
- service: input_number.set_value
data_template:
entity_id: >-
{% set room = trigger.entity_id.split(".")[1] | replace("_changed", "") %}
{% set entity = ["input_number",room]|join(".") %}
{{entity}}
value: >-
{% set room = trigger.entity_id.split(".")[1] | replace("_volume_changed", "") %}
{% if room == "sonos_basement" %}
{{states.sensor.sonos_basement_volume.state }}
{% elif room == "sonos_living_room" %}
{{states.sensor.sonos_living_room_volume.state }}
{% elif room == "sonos_guest_room" %}
{{states.sensor.sonos_guest_room_volume.state }}
{% elif room == "sonos_master_bedroom" %}
{{states.sensor.sonos_master_bedroom_volume.state }}
{% elif room == "sonos_office" %}
{{states.sensor.sonos_office_volume.state }}
{% endif %}
- alias: 'Sonos Set Volume From Input Number'
initial_state: on
trigger:
- platform: state
entity_id: input_number.sonos_basement_volume
- platform: state
entity_id: input_number.sonos_living_room_volume
- platform: state
entity_id: input_number.sonos_master_bedroom_volume
- platform: state
entity_id: input_number.sonos_guest_room_volume
- platform: state
entity_id: input_number.sonos_office_volume
condition:
condition: and
conditions:
- condition: template
value_template: >-
{% set room = trigger.entity_id.split(".")[1] %}
{% set input_num = ["states.input_number",room,"state"]|join(".") %}
{% set sonos_vol = ["states.sensor",room,"state"]|join(".") %}
{% if input_num != sonos_vol %}true
{%else%}false
{% endif %}
action:
- service: media_player.volume_set
data_template:
entity_id: >-
{% set room = trigger.entity_id.split(".")[1]|replace("_volume","")%}
{% set entity = ["media_player",room]|join(".")%}
{{entity}}
volume_level: >-
{% set room = trigger.entity_id.split(".")[1]|replace("_volume","")%}
{% if room == "sonos_basement" %}
{{states.input_number.sonos_basement_volume.state | int / 100 | float}}
{% elif room == "sonos_living_room" %}
{{states.input_number.sonos_living_room_volume.state | int / 100 | float}}
{% elif room == "sonos_guest_room" %}
{{states.input_number.sonos_guest_room_volume.state | int / 100 | float}}
{% elif room == "sonos_master_bedroom" %}
{{states.input_number.sonos_master_bedroom_volume.state | int / 100 | float}}
{% elif room == "sonos_office" %}
{{states.input_number.sonos_office_volume.state | int / 100 | float}}
{% endif %}
Finally, the group for the frontend. Use entity_picture in the customize area at 192x192 pixels with transparent backgrounds. Google has lots, you just may need to resize:
sonos_volumes:
view: no
name: Volumes
entities:
- input_number.sonos_living_room_volume
- input_number.sonos_basement_volume
- input_number.sonos_master_bedroom_volume
- input_number.sonos_office_volume
- input_number.sonos_guest_room_volume
That’s it!