"I created an automation for Sonos that plays a random music playlist in the morning and at night. It allows you to choose different media players based on the time of day using specific triggers.
The automation also ensures that the current queue restarts and speakers rejoin if the queue was paused or if a speaker becomes ungrouped. It compares the selected players (like [media_player.bedroom, media_player.livingroom]) with all Sonos players (all_sonos_players) to make sure everything is in sync.
To use this automation, you can customize it by listing the specific media players you want to use in the grouped_players,master_player and all_sonos_player (grouped_players+master_player) variable (e.g., [media_player.bedroom, media_player.livingroom]). The automation will then check this list against all_sonos_players to keep everything aligned.
Media Player Sonos Automation
alias: Media Player Sonos-Navidrome
description: ""
trigger:
- platform: time
at: "06:05:00"
enabled: true
id: "1"
- platform: time
at: "22:00:00"
id: "2"
- alias: >-
trigger if any of the sonos media_players are NOT in a unknown state or
playing (ie idle or paused)
platform: template
value_template: |
{{expand(integration_entities('sonos')
| select("match","media_player"))
| list
| count > expand(integration_entities('sonos')
| select("match","media_player"))
| selectattr('state','in',['unavailable','unknown','playing'])
| list
| count}}
for:
hours: 0
minutes: 0
seconds: 15
id: "3"
- platform: homeassistant
event: start
id: "4"
condition: []
action:
- variables:
grouped_players: |
{{ states.media_player
| map(attribute='entity_id')
| select('is_device_attr', 'manufacturer', 'Sonos')
| reject('is_device_attr', 'model', 'Port') | list }}
master_player: |
{{ states.media_player
| map(attribute='entity_id')
| select('is_device_attr', 'manufacturer', 'Sonos')
| select('is_device_attr', 'model', 'Port') | list }}
night_players: |
{{ expand(integration_entities('sonos')
| select("match","media_player"))
| selectattr('entity_id', 'search','bedroom')
| map(attribute='entity_id')
| list}}
allsonosplayers: |
{{ integration_entities("sonos")
| select("match", "media_player")
| list
}}
sonosplaylist: |
{{ ["FV:2/9","FV:2/17","FV:2/18", "FV:2/11"] }}
nightplaylist: |
{{ ["FV:2/14"] }}
- alias: Morning
if:
- condition: trigger
id:
- "1"
then:
- repeat:
sequence:
- alias: Restart
if:
- condition: and
conditions:
- alias: player_count > players_playing
condition: template
value_template: |
{{ allsonosplayers
| count > expand(integration_entities('sonos')
| select("match","media_player"))
| selectattr('entity_id','in', allsonosplayers)
| selectattr('state','eq', 'playing')
| list
| count}}
then:
- alias: group sonos media_players
if:
- condition: template
value_template: |
{{master_player|count > 0}}
then:
- continue_on_error: true
service: media_player.join
target:
entity_id: |
{{master_player[1:]}}
data:
group_members: |
{{master_player[:1]+grouped_players}}
alias: >-
assign newer sonos media_players as master and the
remaining as group_members
else:
- continue_on_error: true
service: media_player.join
target:
entity_id: |
{{allsonosplayers[1:]}}
data:
group_members: |
{{allsonosplayers[:1]}}
alias: >-
join all sonos media_players in a random order as last
resort
- continue_on_error: true
service: media_player.volume_set
metadata: {}
data:
volume_level: 0.33
target:
entity_id: |
{{allsonosplayers}}
- continue_on_error: true
service: media_player.play_media
target:
entity_id: |
{{allsonosplayers[1:]}}
data:
media_content_type: favorite_item_id
media_content_id: |
{{ sonosplaylist | random }}
alias: Play Navidrome playlist
- delay:
hours: 0
minutes: 0
seconds: 5
milliseconds: 0
- delay:
hours: 0
minutes: 0
seconds: 1
milliseconds: 0
while:
- condition: and
conditions:
- alias: "Check total # sono media_players = the # currently playing"
condition: template
value_template: |
{{ allsonosplayers
| count > expand(integration_entities('sonos')
| select("match","media_player"))
| selectattr('entity_id','in', allsonosplayers)
| selectattr('state', 'eq','playing')
| list
| count}}
- condition: time
after: "06:00:00"
before: "21:30:00"
- alias: Night
if:
- condition: trigger
id:
- "2"
then:
- alias: >-
check if night_players has media_players in group_members attribute.
then unjoin. test if the group members == night_players
repeat:
sequence:
- alias: Unjoin
repeat:
sequence:
- continue_on_error: true
service: media_player.unjoin
target:
entity_id: |
{{allsonosplayers}}
data: {}
- delay:
hours: 0
minutes: 0
seconds: 1
milliseconds: 0
until:
- condition: template
value_template: |
{{ expand(integration_entities('sonos')
| select("match","media_player"))
| selectattr('entity_id','in', allsonosplayers)
| map(attribute='attributes')
| map(attribute='group_members')
| first
| list
| count == 1}}
- alias: loop until paused
repeat:
sequence:
- continue_on_error: true
service: media_player.media_pause
metadata: {}
data: {}
target:
entity_id: |
{{allsonosplayers}}
- delay:
hours: 0
minutes: 0
seconds: 1
milliseconds: 0
until:
- condition: template
value_template: |
{{ allsonosplayers
| count == expand(integration_entities('sonos')
| select("match","media_player"))
| selectattr('entity_id','in', allsonosplayers)
| selectattr('state','in', ['paused','idle'])
| list
| count}}
- continue_on_error: true
service: media_player.play_media
target:
entity_id: |
{{night_players}}
data:
media_content_type: favorite_item_id
media_content_id: |
{{ nightplaylist | random }}
alias: Play Navidrome playlist
- continue_on_error: true
service: media_player.volume_set
target:
entity_id: |
{{night_players}}
data:
volume_level: 0.3
alias: Set Volume
- delay:
hours: 0
minutes: 0
seconds: 20
milliseconds: 0
until:
- condition: and
conditions:
- condition: template
value_template: |
{{ expand(integration_entities('sonos')
| select("match","media_player"))
| selectattr('entity_id','in', night_players)
| selectattr('state', 'eq','playing')
| list
| count == night_players
| count}}
- condition: time
after: "21:59:00"
before: "23:59:00"
- continue_on_error: true
service: media_player.shuffle_set
metadata: {}
data:
shuffle: true
target:
entity_id: |
{{night_players}}
- alias: Restart
if:
- condition: trigger
id:
- "3"
- "4"
then:
- repeat:
sequence:
- alias: Rejoin Speakers
if:
- condition: and
conditions:
- alias: >-
Check if sonos has in its group_members the total number
of sonos media_players. if not rejoin missing speakers
condition: template
value_template: |
{{ allsonosplayers
| count > expand(integration_entities('sonos')
| select("match","media_player"))
| selectattr('entity_id','in', allsonosplayers)
| selectattr('state','eq', 'playing')
| map(attribute='attributes')
| map(attribute='group_members')
| first
| list
| count}}
enabled: true
- alias: playing>0
condition: template
value_template: |
{{ expand(integration_entities('sonos')
| select("match","media_player"))
| selectattr('state','eq', 'playing')
| map(attribute='entity_id')
| list
| count > 0}}
enabled: true
then:
- variables:
group_membersandpaused: |
{{expand(integration_entities('sonos')
| select("match","media_player"))
| selectattr('entity_id','in', allsonosplayers)
| selectattr('state', 'eq','playing')
| map(attribute='attributes')
| map(attribute='group_members')
| first
| list + expand(integration_entities('sonos')
| select("match","media_player"))
| selectattr('entity_id','in', allsonosplayers)
| selectattr('state','in', ['paused','idle'])
| map(attribute='attributes')
| map(attribute='group_members')
| list
| first}}
master: |
{{expand(integration_entities('sonos')
| select("match","media_player"))
| selectattr('entity_id','in', allsonosplayers)
| selectattr('state', 'eq','playing')
| map(attribute='attributes')
| map(attribute='group_members')
| first
| list
| first}}
- continue_on_error: true
service: media_player.join
metadata: {}
data:
group_members: |
{{group_membersandpaused[1:]}}
target:
entity_id: |
{{master}}
alias: >-
check if the group_members attribute of the master
media_players contains anything
- delay:
hours: 0
minutes: 0
seconds: 20
milliseconds: 0
- variables:
group_membersandpaused: |
{{expand(integration_entities('sonos')
| select("match","media_player"))
| selectattr('state', 'eq','playing')
| map(attribute='attributes')
| map(attribute='group_members')
| first
| list+expand(integration_entities('sonos')
| select("match","media_player"))
| selectattr('state','in', ['paused','idle'])
| map(attribute='entity_id')
| list}}
master: |
{{expand(integration_entities('sonos')
| select("match","media_player"))
| selectattr('state', 'eq','playing')
| map(attribute='attributes')
| map(attribute='group_members')
| first
| list
| first}}
enabled: false
- alias: Trigger Play
if:
- condition: and
conditions:
- alias: Players grouped
condition: template
value_template: |
{{ allsonosplayers
| count == expand(integration_entities('sonos')
| select("match","media_player"))
| selectattr('state','eq', 'paused')
| selectattr('entity_id','in', allsonosplayers)
| map(attribute='attributes')
| map(attribute='group_members')
| first
| list
| count}}
enabled: true
- alias: Does playlist exist
condition: template
value_template: |
{{expand(integration_entities('sonos')
| select("match","media_player"))
| selectattr('state','eq', 'paused')
| selectattr('entity_id','in', allsonosplayers)
| map(attribute='attributes')
| map(attribute='media_playlist')
| list
| count >= 1}}
enabled: true
then:
- continue_on_error: true
service: media_player.media_play
metadata: {}
data: {}
target:
entity_id: |
{{master_player[1:]}}
- delay:
hours: 0
minutes: 0
seconds: 20
milliseconds: 0
- alias: Restart
if:
- condition: and
conditions:
- alias: "!=unavil or !=playing"
condition: and
conditions:
- alias: unavailable=0
condition: template
value_template: |
{{ expand(integration_entities('sonos')
| select("match","media_player"))
| selectattr('entity_id','in', allsonosplayers)
| selectattr('state','in',['unavailable','unknown'])
| map(attribute='entity_id')
| list
| count == 0}}
enabled: true
- alias: player_count>players_playing
condition: template
value_template: |
{{ allsonosplayers
| count>expand(integration_entities('sonos')
| select("match","media_player"))
| selectattr('entity_id','in', allsonosplayers)
| selectattr('state','eq', 'playing')
| list
| count}}
- alias: players_playing=0
condition: template
value_template: |
{{expand(integration_entities('sonos')
| select("match","media_player"))
| selectattr('entity_id','in', allsonosplayers)
| selectattr('state','eq', 'playing')
| list
| count == 0}}
then:
- alias: Assign newer devices=Master
if:
- alias: Check newer sonos devices to add as master
condition: template
value_template: |
{{master_player|count>0}}
then:
- continue_on_error: true
service: media_player.join
target:
entity_id: |
{{master_player[1:]}}
data:
group_members: |
{{master_player[:1]+grouped_players}}
alias: Join Sonos Speakers
else:
- continue_on_error: true
service: media_player.join
target:
entity_id: |
{{integration_entities("sonos")
| select("match","media_player")
| list
| first}}
data:
group_members: |
{% set sonos= integration_entities("sonos") |
select("match", "media_player") | list%}
{{sonos[1:]}}
alias: Join Sonos Speakers
- continue_on_error: true
service: media_player.play_media
target:
entity_id: |
{{allsonosplayers[1:]}}
data:
media_content_type: favorite_item_id
media_content_id: |
{{ sonosplaylist | random }}
alias: Play Navidrome playlist
- delay:
hours: 0
minutes: 0
seconds: 20
milliseconds: 0
- delay:
hours: 0
minutes: 0
seconds: 1
milliseconds: 0
while:
- condition: and
conditions:
- alias: "Check total # sono speaker=the # playing"
condition: template
value_template: |
{{ allsonosplayers
| count > expand(integration_entities('sonos')
| select("match","media_player"))
| selectattr('entity_id','in', allsonosplayers)
| selectattr('state', 'eq','playing')
| list
| count}}
- condition: time
after: "06:00:00"
before: "21:50:00"
mode: single