Group Sonos based on presence (e.g. Motion)

This blueprint automatically groups a Sonos to a main device when presence (e.g. motion) is detected.

blueprint:
  name: Group Sonos on Motion
  description: >
    Group a Sonos device to a main device when presence (e.g. motion) is detected and the main device is playing music.
    Can be extended with custom conditions, for example, only group the Sonos when you're not asleep
  domain: automation
  input:
    presence_entity:
      name: A sensor to detect presence (can be a motion sensor)
      selector:
        entity:
          domain: binary_sensor
    sonos_source:
      name: Sonos source
      description: Sonos entity to group the target Sonos to
      selector:
        entity:
          integration: sonos
    sonos_target:
      name: Sonos target
      description: Sonos target to group to the source Sonos
      selector:
        entity:
          integration: sonos
    no_presence_wait:
      name: Wait time
      description: Time to leave the sonos grouped after last presence is detected.
      default: 120
      selector:
        number:
          min: 0
          max: 3600
          unit_of_measurement: seconds
    custom_conditions:
      name: Custom conditions
      default: []
      description: A list of custom condititions that also have to be met before grouping the sonos

mode: restart
max_exceeded: silent

variables:
  sonos_source: !input sonos_source
  sonos_target: !input sonos_target

trigger:
- platform: state
  entity_id: !input presence_entity
  to: 'on'
- platform: state
  entity_id: !input sonos_source
  to: 'playing'
- platform: homeassistant
  event: start
- platform: event
  event_type: automation_reloaded

condition:
- condition: state
  entity_id: !input presence_entity
  state: 'on'
- condition: state
  entity_id: !input sonos_source
  state: 'playing'
- condition: or
  conditions:
    # Do not trigger the 'action' if our target is already playing some music
    - condition: state
      entity_id: !input sonos_target
      state: 'paused'
    - condition: state
      entity_id: !input sonos_target
      state: 'idle'
    # However, re-trigger the 'action' if we are already grouped to prevent early ungrouping
    - '{{ sonos_target in state_attr(sonos_source, "sonos_group") }}'
- '{{ state_attr(sonos_source, "source")  != "TV" }}'
- condition: and
  conditions: !input custom_conditions

action:
# Only join when we have not already joined, since this would cause a 1 sec silence
- choose:
    - conditions:
      - '{{ sonos_target not in state_attr(sonos_source, "sonos_group") }}'
      sequence:
      - service: sonos.join
        data:
          master: !input sonos_source
          entity_id: !input sonos_target
- wait_for_trigger:
    platform: state
    entity_id: !input presence_entity
    from: "on"
    to: "off"
- delay: !input no_presence_wait
- service: sonos.unjoin
  data:
    entity_id: !input sonos_target

EDIT: Fixed early ungrouping

5 Likes

did you intent to make the custom conditions as required? As is, it’s a requirement to have them

I did not, good find. The default value has been changed to [] which should fix this issue.

1 Like

If I’m reading this right, I need to set the Sonos target and Sonos source as well as motion sensor.

How would it work for this scenario?
Say I want to turn on music in bedroom when I walk into it. Sonos target = bedroom; sensor = bedroom sensor.
If I have music playing in the living room and walk into the bedroom then logic would dictate that I would set my automation source to living room. But say I’m playing music in the office and then walk to the bedroom, this won’t work because source was living room instead of office.

Is there a way to make this with a more generic source?

I guess you would need to create a second automation based on this blueprint where you’d use the office as a source and the bedroom as a target. Note that the blueprint only joins if the source is actually playing music. The reason the blueprint does not support multiple sources is so you have the flexibility to give priority to one of your sources. Let’s assume that you use two sources (office and living room) and one target (bedroom) and both of them are playing different music, how would the blueprint know where to join the bedroom to? By using two automations based on this blueprint, you can easily determine this yourself by passing an additional ‘custom_condition’.

Thanks for this. I’m setting it up now. Like you said, I’ll set-up multiple automations to cover each piece.

I think the next progression is to make like a “follow-you” based on presence. So if you go from living room to bedroom, it starts playing in bedroom (this is what you already have). If you leave bedroom, it stops playing in bedroom (you already have this). But if you stay in bedroom for a while without presence in living room, it stops playing in living room.

Edit: My bigger issue is that apparently my Sonos speakers don’t seem to update their status within Home Assistant most of the time.

this automation is great, but i have one issue i can’t figure out. when the kitchen (source) is already grouped with the living room, and i walk into the bathroom (target), the music in the kitchen stops. But when the living room is grouped with the kitchen, and i walk into the bathroom, everything stays on. any ideas?

This issue does not sound familiar to me. Could you post the relevant automations so I can help you out?

alias: bathroom_music_sync
description: ''
use_blueprint:
  path: MarvinS/group-sonos-based-on-presence-e-g-motion.yaml
  input:
    no_presence_wait: 60
    presence_entity: group.bathroom_motion_sensors
    sonos_source: media_player.kitchen
    sonos_target: media_player.bathroom
    custom_conditions: []

Thanks for the help, that’s what I have

I’ve tried importing this blueprint but get “while scanning for the next token found character ’' that cannot start any token in "<unicode string>", line 49, column 11: to: 'on' ^”.

Any idea what I might be doing wrong?

Sorry that was my mistake, I made an error on my side. Could you try to import it again?

Has anybody had any luck grouping their target speakers with a Playbar playing TV audio as the source?

I’ve setup this blueprint to use Play speaker to Play speaker, but have no luck with TV Playbar to Play speaker. The sensor detects the motion but no action happens.

To make things more confusing, if I click the “Run Actions” button it works perfectly, but motion won’t make this one run.

In case you need my setup, I’ve listed it below.

alias: Group Sonos on Motion
description: ''
use_blueprint:
  path: homeassistant/sonos_followme.yaml
  input:
    presence_entity: binary_sensor.kitchen_motionsensor
    sonos_source: media_player.playbar
    sonos_target: media_player.kitchen_sonos
    custom_conditions: []

Thanks for your help!

That’s odd. Are you playing music, or watching TV? The blueprint does not group the Sonos when the input entity has “TV” as the source.

As for the ‘Run Actions’, it makes sense that this works as it skips the triggers/condition part of the blueprint.

Yes the Playbar is playing audio from the TV.

The aim is to have the kitchen speaker group to the Playbar (TV) and play the tv audio into the kitchen when we’re in there. At the moment the tv volume gets turned up too high so it can be heard in the kitchen.

You mentioned that the blueprint does not group when the tv is the source so I get the feeling this is intended. If I were to remove something like the like below do you think I could achieve the grouping after?

- '{{ state_attr(sonos_source, "source") != "TV" }}'

Thanks Marvin.

Yes this was intended, because I only wanted to use this blueprint to have music follow me around the house. Removing the line you supplied would get you the desired effect. I will make this configurable in a new version of the blueprint.