Sonos announcement issue: not playing on all group members & restore not restoring prior groups (if any)

Good morning, all.

Trying to make my doorbell TTS notification function better here. I was doing just a HA group which had all Sonos playing the announcement but totally out of sync. I read some posts here and conjured up a new concoction.

The Sonos app shows the new group being made, audio adjustments being made (added these to try to confirm my deafness wasn’t missing other speakers playing audio; they weren’t playing anything though), and the restore occurs. The restore doesn’t return any prior groups to each other, though. So if I was rocking out to Guns-n-Roses in the kitchen and dining room before, the group does not exist after the TTS announcement automation ends, nor does the prior audio playlist continue.

I’m at a loss as to why the entire group does not play the TTS announcement -and- why the restore isn’t restoring everything to the prior state (old groups, play where it left off, etc).

- id: da21735e-351c-11ee-be56-0242ac120002
  alias: Sonos Doorbell Announcement
  trigger:
  - platform: state
    entity_id: binary_sensor.doorbell_button_pressed
    to: 'on'
  action:
  - service: sonos.snapshot
    data:
      entity_id:
        - media_player.family_room
        - media_player.tv_room
        - media_player.kitchen
        - media_player.dining_room
        - media_player.move_2
        - media_player.sonos_roam
  - delay: '00:00:01'  # Ensures face recognition has time to process
  - service: media_player.join
    data:
      group_members:
        - media_player.tv_room
        - media_player.family_room
        - media_player.dining_room
        - media_player.move_2
        - media_player.sonos_roam
    target:
      entity_id: media_player.kitchen
  - delay: '00:00:01'  # Brief delay to ensure the group is formed
  - service: media_player.volume_set
    data:
      entity_id: media_player.kitchen
      volume_level: 0.20  # Kitchen speaker volume
  - service: media_player.volume_set
    data:
      entity_id: media_player.family_room
      volume_level: 0.30  # Family room speaker volume
  - service: media_player.volume_set
    data:
      entity_id: media_player.tv_room
      volume_level: 0.20  # TV room speaker volume
  - service: media_player.volume_set
    data:
      entity_id: media_player.dining_room
      volume_level: 0.40  # Dining room speaker volume
  - service: media_player.volume_set
    data:
      entity_id: media_player.move_2
      volume_level: 0.30  # Move 2 speaker volume
  - service: media_player.volume_set
    data:
      entity_id: media_player.sonos_roam
      volume_level: 0.40  # Sonos Roam speaker volume
  - delay: '00:00:01'  # Brief delay to ensure volume set
  - choose:
      - conditions:
          - condition: template
            value_template: >  # Check for face recognition matches
              {{ state_attr('sensor.double_take_doorbell', 'matches') | length > 0 }}
        sequence:
          - service: tts.cloud_say
            data_template:
              entity_id: media_player.kitchen  # The main speaker to start the group
              message: >
                {% set matches = state_attr('sensor.double_take_doorbell', 'matches') %}
                {% set faces = matches | map(attribute='name') | list %}
                {% set corrected_faces = faces | map('trim') | list %}
                {% if 'viviana' in corrected_faces %}
                  {% set corrected_faces = corrected_faces | map('capitalize') | list %}
                  {% set corrected_faces = corrected_faces | map('replace', 'viviana', 'Viv-ee-ah-nah') | list %}
                {% endif %}
                {% if corrected_faces | length == 1 %}
                  {{ corrected_faces[0] }} is at the front door.
                {% else %}
                  {{ corrected_faces | join(', ') }} are at the front door.
                {% endif %}
    default:
      - service: tts.cloud_say
        data:
          entity_id: media_player.kitchen
          message: Someone is at the front door.
  - wait_template: "{{ not is_state('media_player.family_room', 'playing') }}"
    timeout: '00:00:06'  # Timeout to avoid indefinite waiting
    continue_on_timeout: true
  - service: sonos.restore
    data:
      entity_id:
        - media_player.family_room
        - media_player.tv_room
        - media_player.kitchen
        - media_player.dining_room
        - media_player.move_2
        - media_player.sonos_roam
  mode: single

Any advice to resolve my two issues? Thank you!

I installed GitHub - nimroddolev/chime_tts: A custom Home Assistant integration to play combined audio files before and/or after text-to-speech (TTS) messages by @Nimrod_Dolev which I found here. Chime TTS - Play audio before/after TTS audio lag free

I converted my script to use it. All Sonos speakers are playing the announcement concurrently and the group returns to playing.

I’m only failing to configure the new integration’s ability to play TTS over the audio stream I think. Or, maybe that doesn’t work as I’m thinking it would vs. the couple of seconds muted time on either side of the TTS output.

- id: da21735e-351c-11ee-be56-0242ac120002
  alias: Sonos Doorbell Announcement
  trigger:
    - platform: state
      entity_id: binary_sensor.doorbell_button_pressed
      to: 'on'
  action:
  - service: sonos.snapshot
    data: 
      with_group: true
      entity_id:
        - media_player.family_room
        - media_player.tv_room
        - media_player.kitchen
        - media_player.dining_room
        - media_player.move_2
        - media_player.sonos_roam
  - delay: '00:00:02'  # Ensures face recognition has time to process
  - service: media_player.join
    data:
      group_members:
        - media_player.tv_room
        - media_player.family_room
        - media_player.dining_room
        - media_player.move_2
        - media_player.sonos_roam
    target:
      entity_id: media_player.kitchen
  - delay: '00:00:01'  # Brief delay to ensure the group is formed
  - choose:
      - conditions:
          - condition: template
            value_template: >  # Check for face recognition matches
              {{ state_attr('sensor.double_take_doorbell', 'matches') | length > 0 }}
        sequence:
          - service: chime_tts.say
            data_template:
              entity_id: media_player.kitchen  # The main speaker to start the group
              message: >
                {% set matches = state_attr('sensor.double_take_doorbell', 'matches') %}
                {% set faces = matches | map(attribute='name') | list %}
                {% set corrected_faces = faces | map('trim') | list %}
                {% if 'viviana' in corrected_faces %}
                  {% set corrected_faces = corrected_faces | map('capitalize') | list %}
                  {% set corrected_faces = corrected_faces | map('replace', 'viviana', 'Viv-ee-ah-nah') | list %}
                {% endif %}
                {% if corrected_faces | length == 1 %}
                  {{ corrected_faces[0] }} is at the front door.
                {% else %}
                  {{ corrected_faces | join(', ') }} are at the front door.
                {% endif %}
              tts_service: tts.cloud_say  # Use Nabu Casa TTS service
    default:
      - service: chime_tts.say
        data:
          entity_id: media_player.kitchen
          message: Someone is at the front door.
          tts_service: tts.cloud_say
  - wait_template: "{{ not is_state('media_player.kitchen', 'playing') }}"
    timeout: '00:00:06'  # Timeout to avoid indefinite waiting
    continue_on_timeout: true
  - service: sonos.restore
    data: 
      with_group: true
      entity_id:
        - media_player.family_room
        - media_player.tv_room
        - media_player.kitchen
        - media_player.dining_room
        - media_player.move_2
        - media_player.sonos_roam
  mode: single

Well, aside a few seconds extra delay (not added in by my delays) to get the TTS announcement and then to resume the audio, the only issue I have is that sonos.restore function starts with the next song in the queue and not where we stopped.

- id: da21735e-351c-11ee-be56-0242ac120002
  alias: Sonos Doorbell Announcement
  trigger:
    - platform: state
      entity_id: binary_sensor.doorbell_button_pressed
      to: 'on'
  action:
  - delay: '00:00:01'
  - service: sonos.snapshot
    data: 
      with_group: true
      entity_id: all
#        - media_player.family_room
#        - media_player.tv_room
#        - media_player.kitchen
#        - media_player.dining_room
#        - media_player.move_2
#        - media_player.sonos_roam
  - delay: '00:00:01'  # Ensures face recognition has time to process
#  - service: media_player.join
#    data:
#      group_members:
#        - media_player.tv_room
#        - media_player.family_room
#        - media_player.dining_room
#        - media_player.move_2
#        - media_player.sonos_roam
#    target:
#      entity_id: media_player.kitchen
#  - delay: '00:00:01'  # Brief delay to ensure the group is formed
  - choose:
      - conditions:
          - condition: template
            value_template: >  # Check for face recognition matches
              {{ state_attr('sensor.double_take_doorbell', 'matches') | length > 0 }}
        sequence:
          - service: chime_tts.say
            data_template:
              entity_id: 
                - media_player.kitchen
                - media_player.dining_room
                - media_player.tv_room
#                - media_player.family_room
#                - media_player.sonos_roam
#                - media_player.move_2
              message: >
                {% set matches = state_attr('sensor.double_take_doorbell', 'matches') %}
                {% set faces = matches | map(attribute='name') | list %}
                {% set corrected_faces = faces | map('trim') | list %}
                {% if 'viviana' in corrected_faces %}
                  {% set corrected_faces = corrected_faces | map('capitalize') | list %}
                  {% set corrected_faces = corrected_faces | map('replace', 'viviana', 'Viv-ee-ah-nah') | list %}
                {% endif %}
                {% if corrected_faces | length == 1 %}
                  {{ corrected_faces[0] }} is at the front door.
                {% else %}
                  {{ corrected_faces | join(', ') }} are at the front door.
                {% endif %}
              tts_service: tts.cloud_say  # Use Nabu Casa TTS service
              join_players: true
              unjoin_players: true
#              announce: true
    default:
      - service: chime_tts.say
        data:
          entity_id: group.sonos_speakers
            - media_player.kitchen
            - media_player.dining_room
            - media_player.tv_room
#            - media_player.family_room
#            - media_player.sonos_roam
#            - media_player.move_2
          message: Someone is at the front door.
          tts_service: tts.cloud_say
          join_players: true
          unjoin_players: true
#          announce: true
  - wait_template: "{{ not is_state('media_player.kitchen', 'playing') }}"
    timeout: '00:00:03'  # Timeout to avoid indefinite waiting
    continue_on_timeout: true
#  - delay: '00:00:02'  # Brief delay to prevent timeout from Sonos API
  - service: sonos.restore
    data: 
      with_group: true
      entity_id: all
#        - media_player.family_room
#        - media_player.tv_room
#        - media_player.kitchen
#        - media_player.dining_room
#        - media_player.move_2
#        - media_player.sonos_roam
  mode: single

Have you tried removing the snapshot/restore service calls and uncommenting announce: true ?

Wouldn’t removing Sonos parameters cause groups to be lost after the announcement? Or does your join/unjoin not affect the actual groups somehow?

Chime TTS offer the same join/unjoin services as the standard Home Assistant media_player entity. I don’t own any Sonos speakers, but I know from Chime TTS users who do, that the join/unjoin is problematic and they recommended not to use it.

Have you tried removing the snapshot/restore service calls and uncommenting announce: true ?

Did you try?

So, I did six tests:

Removing the sonos.snapshot and sonos.restore; adding announce; and keeping join/unjoin with no music playing on devices results in an announcement.

With the Sonos speakers that grouped playing music at TTS event, the ones that receive the TTS input do not rejoin the group after playing music.

Removing join/unjoin with announce = true results in everything staying grouped in Sonos app and music playing. But, the speakers are not in sync with the TTS.

Removing join/unjoin/announce results in the TTS being synced across devices, the Sonos group remains intact after TTS, but the Sonos queue and music is cleared.

Removing join/unjoin with fade_audio = true results in the TTS being synced across devices, the Sonos group remains intact after TTS, but the Sonos queue and music is cleared.

Removing join/unjoin with announce = true results && setting 0ms for the integration’s fade transition in everything staying grouped in Sonos app and music playing. And, the speakers ARE in sync with the TTS.

Sweet.

EDIT Apologies, I meant to reply to derekcentrico.

I’m intrigued by the ability to have the announcement played in sync because my understanding is the announce option is incapable of doing this on unjoined speakers.

In your tests, you say you removed “join/unjoin” but does that mean you did not use an explicit media_player.join service call and used the integration’s own ability to do it?

Or are you saying you used no form of joining whatsoever and played the announcement, in sync, on multiple unjoined speakers?


I wasn’t able to find a “fade transition” option in the integration’s documentation. Are you referring to delay or something else?

image

Apologies, I replied to Nimrod_Dolev but meant to reply to you.

Man, I was torn about pasting my changes per each test and flooding the place with useless text. Should’ve done it to help you visualize.

I removed the join/unjoin and used the announce variable. Whether it works as designed or is an anomaly I don’t know. However, 2 ARCs, 1 One SL, 1 Move2, 1 Roam, and 1 Era 100 are all playing the announcement at the same time -and- I am not losing playing music and not losing Sonos app groups.

The only caveat is that I’m a bit deaf in my left ear (thanks to a lovely IED explosion). But, my right ear is good and the echo I heard across speakers is not occurring at the moment.

Here’s my current code (cleaned up and less Sonos devices being used but still working as described):

- id: da21735e-351c-11ee-be56-0242ac120002
  alias: Sonos Doorbell Announcement
  trigger:
    - platform: state
      entity_id: binary_sensor.doorbell_button_pressed
      to: 'on'
  action:
  - delay: '00:00:03'  # compreface can be sluggish right now for some reason
  - choose:
      - conditions:
          - condition: template
            value_template: >  # Check for face recognition matches
              {{ state_attr('sensor.double_take_doorbell', 'matches') | length > 0 }}
        sequence:
          - service: chime_tts.say
            data_template:
              entity_id: 
                - media_player.kitchen
                - media_player.dining_room
                - media_player.tv_room
#                - media_player.family_room
                - media_player.sonos_roam
                - media_player.move_2
              message: >
                {% set matches = state_attr('sensor.double_take_doorbell', 'matches') %}
                {% set faces = matches | map(attribute='name') | list %}
                {% set corrected_faces = faces | map('trim') | list %}
                {% if 'viviana' in corrected_faces %}
                  {% set corrected_faces = corrected_faces | map('capitalize') | list %}
                  {% set corrected_faces = corrected_faces | map('replace', 'viviana', 'Viv-ee-ah-nah') | list %}
                {% endif %}
                {% if corrected_faces | length == 1 %}
                  {{ corrected_faces[0] }} is at the front door.
                {% else %}
                  {{ corrected_faces | join(', ') }} are at the front door.
                {% endif %}
              tts_service: tts.cloud_say  # Use Nabu Casa TTS service
              announce: true
    default:
      - service: chime_tts.say
        data:
          entity_id: 
            - media_player.kitchen
            - media_player.dining_room
            - media_player.tv_room
#            - media_player.family_room
            - media_player.sonos_roam
            - media_player.move_2
          message: Someone is at the front door.
          tts_service: tts.cloud_say
          announce: true
  - wait_template: "{{ not is_state('media_player.kitchen', 'playing') }}"
    timeout: '00:00:04'  # Timeout to avoid indefinite waiting
    continue_on_timeout: true
  mode: single

You haven’t configured chime_tts.say to use join_players: true so the list of speakers are not joined yet they play the announcement in sync. You have inspired me to test it on my system.

Exactly. Eliminating that allows Sonos groups to survive if not using the sonos.snapshot and restore function.

Let me know how it goes for you. Seems to still be functional after a HA Green reboot.

Don’t want to mark it as solved in case you have a different experience or see something more logical when toying.

I carried out a simple test and received unexpected results.

I used media_player.play_media directly, like this:

service: media_player.play_media
data:
  media_content_type: music
  media_content_id: http://io/TTS/tts_2.wav
  announce: true
target:
  entity_id:
    - media_player.bedroom
    - media_player.move
    - media_player.living_room

Test Results

  • The WAV file played in sync but only on two of the three speakers. The third was silent.

  • I tried it again and the file played, in sync, on only two of the three speakers but not the same two as in the first trial.

  • A third trial produced the same results as the second one.

  • I added a fourth speaker and the results were the same as in the second trial (only two out four played the file).

  • I added a fifth speaker and, once again, only two speakers played the file in sync and all others were silent. For this trial, the two that played were different from previous trials.

  • I joined all five speakers first then played the file (to all five). Only two speakers played the file and it was not in sync. For this trial, the two that played were the same as in the fifth trial.


Based on these results, I can’t use the service call’s announce feature to reliably play on more than two speakers. Why it behaves this way is unclear to me because the speakers work properly when used to play any file without announce (i.e. using Home Assistant or the Sonos app).

FWIW, I have been using a script of my own invention to play announcements. It creates a snapshot, pauses the desired speakers (if playing), unjoins them from any existing group(s), joins them into a new group, sets their volume, plays an optional preamble (i.e. prerecorded sound effect), plays the supplied file, then restores the snapshot. The script has been used at least once a day for over two years with reliable performance.

I experimented with announce when it was first introduced and it played out of sync but, I now realize, I had always tested it with joined speakers. Anyways, my latest test results, with unjoined speakers, aren’t ideal (at least not for me). Perhaps the next step is to test Nimrod_Dolev’s Chime integration with my speakers.

Interesting. I tried similarly at first, albeit with a sonos group created via groups.yaml. This was all out of sync and messed up everything.

I wonder if playing TTS vs. the recorded file would be any different for you. Probably not.

I’ve been having the same issues, but I want to throw this out there cause I didn’t see it mentioned. I know the announce feature is only supported by S2/Gen 2 Sonos HW. You may need to upgrade to resolve some of the out-of-sync issues with announce. I however am still running into issues as I have created a group for all my speakers and get the announcement played via media_player.play_media but the music if playing does not return after the announcement.