Can‘t get media_player.clear_playlist to work for Sonos

Hi,

I‘m new to HA and try to do some automations.

Currently I’m trying to find out how I can clear the playlist from a Sonos speaker. After reading a lot Can‘t get media_player.clear_playlist workingof posts I still can‘t understand why the following isn‘t working (the playlist isn‘t cleared):

alias: Neue Automatisierung
description: ""
trigger:
  - platform: state
    entity_id:
      - switch.fenster_bad_offen_vcs
    to: "on"
condition: []
action:
  - service: media_player.clear_playlist
    target:
      entity_id: media_player.esszimmer
    data: {}

Does anyone have an idea, why?

Regards,
Jogi

That call should clear the queue. What do you see happening? Any messages in the log?

Nothing happens and there is no error shown in the log (traces).

Maybe it is a misunderstanding? I expect the following to happen from clearing the queue: The last played media shall be removed. Is that expectation wrong?

Depends on how the media was added. What’s the complete sequence?

Actually I’m running a script that

  1. takes a Sonos snapshot
  2. pauses the current media playing
  3. plays an locally saved announcement-file, then a text-to-speech and then again an announcement-file
  4. restores the Sonos snapshot
  5. clears the playlist.

I need the clearing of the playlist only, if the playlist before taking a snapshot was empty (e.g. the Sonos device has been plugged out before). In that case, the last played announcement-file remains as a title in the sonos app and is played, when the script starts again, so that two announcement-file are played in the beginning. and that is what I want to avoid by clearing the playlist at the end of the script.

My code is as follows:

alias: TTS Engine
variables:
  speaker: media_player.esszimmer
  volume: >-
    {% if (now().hour > 21 and now().hour < 7) %} i0.1 {% else %} 0.1 {% endif
    %}
sequence:
  - service: sonos.snapshot
    data:
      entity_id: "{{ speaker }}"
      with_group: true
  - service: media_player.media_play_pause
    data:
      entity_id: "{{ speaker }}"
  - service: media_player.volume_set
    data:
      entity_id: "{{ speaker }}"
      volume_level: "{{ volume }}"
  - service: media_player.play_media
    data:
      media_content_type: music
      media_content_id: >-
        media-source://media_source/local/234565__foolboymedia__announcement-begin.wav
      entity_id: "{{ speaker }}"
  - delay:
      seconds: 0
  - service: tts.speak
    target:
      entity_id: tts.home_assistant_cloud
    data:
      cache: true
      media_player_entity_id: "{{ speaker }}"
      message: "{{ message }}"
  - delay:
      seconds: "{{ delay }}"
  - service: media_player.play_media
    data:
      media_content_type: music
      media_content_id: >-
        media-source://media_source/local/234566__foolboymedia__announcement-end.wav
      entity_id: "{{ speaker }}"
  - delay:
      seconds: 1
  - service: sonos.restore
    data:
      entity_id: "{{ speaker }}"
      with_group: false
  - service: media_player.clear_playlist
    data:
      entity_id: "{{ speaker }}"
fields: {}

Thanks for the details.

Not all media gets added to the Sonos queue. When the item is a URI and the enqueue parameters is not specified it hits this line of code and just plays the uri without adding it to the queue

What would be interesting is to try to clear the queue from the Sonos App and see if you can a different behavior. That would tell us if it’s an API issue or a missing API call beyond clearing the queue that is needed,

You can try using “play” as the enqueue parameter to play_media, that should cause it to get queued on line 624. I don’t know if tts.speak will allow that parameter to get passed through.

That said, the simpler way to accomplish this is to use the “announce” parameter as described in the docs. This avoids the need to snapshot, restore, etc, and will play the announcement over a currently playing track.

Do you mean setting the value of enqueue to true?

EDIT

Scratch that. It looks like the documentation is out of date because I just noticed that enqueue supports several values, including play (visible in Developer Tools > Services for media_player.play_media).


FWIW, I have observed speakers report paused which turns to idle after executing media_player.clear_playlist. However, on occasion, a speaker that has played a WAV file (typically the one that was the master of a group that played the file) will report paused but fail to change to idle after clearing the playlist. To clear it, typically playing music (Hey Sonos, play jazz) and then stopping it (Hey Sonos, stop playing), the speaker will revert to idle.

I’ll try using enqueue to see if it makes a difference … or switch to using announce (because I currently do the multi-step dance of “snapshot/unjoin from any existing groups/join into a new group/set volume/play/restore”).


EDIT

Tried announce but not sure if it will replace my existing multi-step dance. Using it on three speakers (that are already grouped and playing music) results in the announcement being played independently on all three speakers resulting in a staggered effect (i.e. the three speakers are not in sync).

Yes it is, I have a PR open for that. Provide examples for playing local media by PeteRager · Pull Request #31886 · home-assistant/home-assistant.io · GitHub

That’s interesting. You are sending executing one service call on the speaker that is the group master?

1 Like

When I tried that, the announcement played exclusively on the group master (over the music) and all other group members continued to simply play music (at its original volume). To be clear, I’m identifying the group master as the first media_player listed in the group_members attribute.

To replicate what I currently have, I would need the announcement played on all members of a group (and in sync). In my case, announcements are always sent to groups (representing more than one room and sometimes even more than one floor), almost never to a single speaker.

If I list each individual member of the group in the one service call, the announcement is played on each one but not in sync.


EDIT

FWIW, I didn’t expect it to work (send announcement to group master and it plays on all members) because I assumed it was a limitation of the feature, similar to its reported inability to play to both speakers in a stereo pair. Nevertheless I thought it was worth trying in case my understanding of it was out of date.

Thank you, that is helpful. I’ll add this to the list of items for this integration, at a minimum having these details in the docs would be good.

What it currently does is opens a websocket to the ip address of the speaker and pushes the clip. If it’s a pair it’s the first ip address (e.g. left) This is different than typical operations which tell the speaker to play media and provide it with a URL or music library address to pull the media from. It is possible that additional parameters to the push operation may cause it to play on more than one speaker. Alternatively, we may be able to execute the push in parallel to multiple speakers - which may yield an ok result on a reasonably fast computer - as we just need the time coherence to be <30ms (this is the point at which most listeners start hearing a separate sound)

1 Like

Here’s an update about my attempt to learn more about when/why the “volume_set” timeout occurs.

Speak: Error executing script.
Error for call_service at pos 5:
 Error calling SonosMediaPlayerEntity.set_volume_level on media_player.move:
  HTTPConnectionPool(host='192.168.1.47', port=1400):
   Read timed out. (read timeout=9.5)
  • The error occurs while setting the volume of four members of a group (FWIW, originally I assumed that setting the group master’s volume would automagically set all group members as well but it didn’t so all members are individually listed in media_player.volume_set).

  • The error message identifies the fourth and last member of the group (a Move speaker). The error causes immediate termination and remaining actions aren’t executed.

  • I added continue_on_error to media_player.volume_set. When the error recurred, remaining actions were executed (after an initial delay of approximately 10 seconds representing the volume_set’s timeout). The Move, last in the list, was identified as the cause of the timeout.

  • I rearranged the list members and made the Move third in the list (test to see if it’s merely the last member in the list that’s always identified as the trouble maker).

  • When the error recurred, the error message still identified the Move as the culprit.

  • When using the Sonos app to adjust the Move’s volume (after the error occurs) there’s no noticeable delay. It responds instantly while music is playing and, if volume is adjusted while playback is paused, the new volume level is used immediately when playback is resumed.

See Trace Details

Here’s the service call.

  - service: media_player.volume_set
    target:
      entity_id: '{{ new_group_members }}'
    data:
      volume_level: '{{ volume }}'

Here’s what it looks like in the trace:

Executed: 22 April 2024 at 08:08:36
Result:
params:
  domain: media_player
  service: volume_set
  service_data:
    volume_level: 0.25
    entity_id:
      - media_player.kitchen
      - media_player.family_room
      - media_player.move
      - media_player.living_room
  target:
    entity_id:
      - media_player.kitchen
      - media_player.family_room
      - media_player.move
      - media_player.living_room
running_script: false

Here’s the trace timeline:

I used a WiFi app on my phone to get some sense of signal strength at the Move’s location. It’s -52 dBm which is no worse than the stereo pair in the living room at -54 dBm. In addition, neighboring networks on the same channel are significantly weaker (-80 dBm). FWIW, I tried using the Move’s “support/review” URL, on port 1400, but couldn’t find a signal strength measurement.

As an experiment, I will relocate it elsewhere, to get a stronger signal, to see if it makes any difference. Frankly, I don’t think it will but it’s an easy test to perform.

Good data. If you repeat the volume set command on the move after it fails the first time, does that succeed?

Hypothesis, it’s a battery powered speaker, so it must “go to sleep” to conserve battery power. Since the app reliably works perhaps there is a wake-up command that needs to be sent. If the second volume set command succeeds, that would mean the first one woke it up, and perhaps adding a retry in the integration and shortening the timeout could be a solve. If the second one fails also, that would mean there is some other signal that needs to be sent. (Maybe a WOL)

It sat on its charging base when the errors occurred but I won’t discount the possibility that it might still go into a “deep sleep” mode.

The error occurs when an automation announces “Your tea is ready” which is the first thing played on the Move almost every morning. The error doesn’t always occur but that’s typically when it does. This lends credence to your theory that it’s asleep and seems to be sluggish about acknowledging the volume_set command.

The fly in the ointment is that the volume_set command isn’t the first action in the automation (but it is the first and only one to timeout for the Move). It’s preceded (minimally) by sonos.snapshot, media_player.unjoin, and media_player.join (to form the desired group). Then it sets the volume (service call shown in previous post).

Speculation:

I assume at least one of those three preceding actions will wake up the Move prior to volume_set. Perhaps volume_set is the first and only one of the four actions that behaves differently. In other words, maybe it has different expectations about acknowledgement from the device … and the Move doesn’t always meet this criteria?


EDIT

The Move has been relocated to an area with a measured signal strength of -40 dBm. It may take a few days of testing before any conclusions can be made.

What is the state of the media player entity when the volume set fails. Is it unavailable?

Its history doesn’t show it was unavailable at any time this morning or yesterday.

That’s interesting. If it was in a deep sleep and not responding it should be unavailable. There is an activity monitor that should trigger if no updates are received from the speaker after some amount of time. That needs some investigation to see how it works and if there is sufficient debug logging to see what is happening on the move.

I assume that if it had been unavailable then one of these three service calls, which precede media_player.volume_set, would have complained about it:

  1. sonos.snapshot
  2. media_player.unjoin
  3. media_player.join

I’ve never tried to test those service calls with an unvailable speaker so I can’t say for sure how they would behave (fail with an error or just skip the unvailable speaker).

After 4 mornings of working properly, today on the fifth morning, media_player.volume_set timed out again. Note the 10 second pause between setting the volume and the next action (corresponding to the service call’s 9.5 second timeout).

When it works properly there’s effectively no delay between setting the volume and the next action.

FWIW, the automation flashes some lights then calls a script to announce “Your tea is ready”. So when media_player.volume_set times out, it’s noticeable to everyone because the announcement occurs ~10 seconds after the lights flash.

I measured signal strength near the Move speaker and it’s -39dBm (strong). I think that aspect isn’t the culprit.

Interestingly, no error message was reported in the Log. I could have sworn it had reported one in previous tests with continue_on_error: true. :thinking: I’m now using 2024.4.4 (previously 2024.4.3) but I would be surprised if that’s responsible for the absence of the error message.

On a related note, I noticed the trace file didn’t report that it had to continue because it encountered an error when executing media_player.volume_set. The only clue something is amiss is via the timestamps (just a hair over 9.5 seconds to execute media_player.volume_set). Do you know if it normally does, or doesn’t, report it? I no longer have older trace files to check.

All the functions use the same error handler. This handler does filter out some exceptions and instead logs a debug message. So that appears to be what is happening. I don’t know why it does this or exactly how it works yet.

I to have seen timeout errors getting logged, so it definitely seems strange that you are not seeing them anymore. I’ll run a quick test to see if something broke.

If the error is getting filtered a debug message should get logged.

                    _LOGGER.debug(
                        "Error code %s ignored in call to %s", error_code, function
                    )

To get that we’d need to enable debug logging for the integration.

It’s also possible that there is some kind of timing error, meaning there is always a chance that this sequence will cause a timeout. With 3 successes and 1 fail, it seems like a 25% chance. It may just be a problem with the speaker getting that next command too quickly - as opposed to the theory of it being asleep.

We could try running that sequence more frequently - to see if it reproduces.