Hi guys, I’ve been fidling with this script to use my sonos system as you do. I’ve found a solution for the duration issue. The problem is: the expected format for the duration is HH:MM:SS but this script was sending H:M:S.
The main change is in the duration string formatting (HH:MM:SS):
My script fixes the time format issue but it takes too long to restore the media player. Im seeing loads of entries in the logs like these:
2017-06-03 11:57:40 WARNING (MainThread) [homeassistant.helpers.entity] Update for media_player.bureau is already in progress
It seems to me that media_player.sonos_restore is taking too long, maybe because the home assistant node is in a different network and creaing upnp issues… ill try moving the HASS to the same neetwork.
Just got this working with a combination of the above scripts. For anyone that wants it, this script works perfectly for me, no error logs and it removes the speaker from the group before doing the TTS. Thanks for all the comments and hard work!
sonos_tts:
alias: Sonos Text To Speech
sequence:
- service: media_player.sonos_snapshot
data_template:
entity_id: "{{ 'media_player.' ~ where }}"
with_group: yes
- service: media_player.sonos_unjoin
data_template:
entity_id: "{{ 'media_player.' ~ where }}"
- service: media_player.volume_set
data_template:
entity_id: "{{ 'media_player.' ~ where }}"
volume_level: 0.70
- service: tts.google_say
data_template:
entity_id: "{{ 'media_player.' ~ where }}"
message: "{{ what }}"
# Workout the length of the media
- delay:
seconds: 1
- delay: >-
{% set duration = states.media_player[where].attributes.media_duration %}
{% if duration > 0 %}
{% set duration = duration - 1 %}
{% endif %}
{% set seconds = duration % 60 %}
{% set minutes = (duration / 60)|int % 60 %}
{% set hours = (duration / 3600)|int %}
{{ "%02i:%02i:%02i"|format(hours, minutes, seconds)}}
- service: media_player.sonos_restore
data_template:
entity_id: "{{ 'media_player.' ~ where }}"
with_group: yes
Wow, so complex! Today the whole duration thing can be fixed by using wait_template in a manner similar to this:
script:
tts_wait_test:
sequence:
- service: tts.google_say
data:
entity_id: media_player.your_media_player
message: "Hello World. I am your personal assistant."
- wait_template: >-
{{ is_state('media_player.your_media_player', 'playing') }}
timeout: '00:00:03'
- wait_template: >-
{{ not is_state('media_player.your_media_player', 'playing') }}
timeout: '00:01:00'
- service: tts.google_say
data:
entity_id: media_player.your_media_player
message: "I waited until I finished saying the previous statement, so that I can say this one."
This works great as far as returning to whatever was playing on the Sonos, but it seems to cut short at random points. Say I want it to say “This is a test”. The results could be:
This is a test (4 times in a row with no problems)
This is a te
This is a tes
This is a
This
With the full sentence being peppered in a few times along the way. I can’t see any cause for it.
They’re both. One is connected via ethernet and it is meshing with the others.
It doesn’t appear to a problem with networking though as in the web ui I can see that when I run the sonos_tts_test script the say_sonos script it calls usually gets turned off prematurely.
Here’s the code I am using:
sonos_tts_test:
sequence:
- service: script.turn_on
entity_id: script.say_sonos
data:
variables:
where: 'sonos_office'
what: 'This is a test and it is too short'
say_sonos:
sequence:
- service: media_player.sonos_snapshot
data_template:
entity_id: "{{ 'media_player.' ~ where }}"
with_group: yes
- service: media_player.sonos_unjoin
data_template:
entity_id: "{{ 'media_player.' ~ where }}"
- service: media_player.volume_set
data_template:
entity_id: "{{ 'media_player.' ~ where }}"
volume_level: 0.4
- service: tts.google_say
data_template:
entity_id: "{{ 'media_player.' ~ where }}"
message: "{{ what }}"
- wait_template: >-
{{ is_state('media_player.' ~ where , 'playing') }}
timeout: '00:00:03'
- wait_template: >-
{{ not is_state('media_player.' ~ where , 'playing') }}
timeout: '00:01:00'
- service: media_player.sonos_restore
data_template:
entity_id: "{{ 'media_player.' ~ where }}"
with_group: yes
Try changing the timeout on the 1st wait template to 30 seconds. I think what might be happening is by the time the songs starts playing the 3 seconds has passed and it’s timed out.
The first wait is to wait for sonos to start to play; the second to wait for songs to stop playing…
Good idea. 30 seconds would be FAR too long but I will experiment with increasing the delay. I might set up another sensor monitoring the state so I can see how quickly that updates.
The way I would be using this is to interrupt music (or even TV the Sonos Playbar) to give a notification. i.e. The garage door is open or the like.
Hi, I’m having trouble getting the script to work correctly, I have used code above:
when I try it I get the following error:
This is the error:
2017-07-17 20:48:56 ERROR (MainThread) [homeassistant.core] Invalid service data for media_player.sonos_snapshot: Entity ID media_player. is an invalid entity id for dictionary value @ data[‘entity_id’]. Got ‘media_player.’
As far as I can tell, none of the variables are being passed to the script - Entity ID media_player. when it should be Entity ID media_player.sonos_office I think?
And apologies in advance, I’m very new to this so may be missing something very obvious, really appreciate your help.
I just tried copy/pasted the last example from @mihalski but my sonos is not restoring it’s state. I tried playing a song then manually activate the script to say something, it says the text but then it never returns to the music.
However i see this in the log, don’t know it it’s related :
2017-07-17 14:01:01 WARNING (MainThread) [homeassistant.helpers.entity] Update for media_player.portable is already in progress
So i got it to work albeit the problems that @mihalski explained with the premature stop but another issue is that if i am playing a song and i am in the middle of the song then the doorbell rings and then the music goes back it starts from beginning which is not useful at all, was the idea of restore to go back and play exactly where it was left ?
I guess the problem is that i was using a Music Service (i think in this specific case i used SoundCloud or MixCloud) which i believe the snapshot/restore does not work with correctly. @maddox mentioned something about this in an old issue. The problem lies in the lower layer the SoCo library used for Sonos.
@donnib I’ve had the same problem with pandora for a while now. Each time pandora is interrupted, when it resumes, it starts a new track. If I play local media the stop/resume functionality works as expected.
Wait until the player starts; as the next wait waits for it to not play.
So once you ask it to speak; we wait until it starts to speak (3 second timeout); and then wait for it to stop speaking (with a 1 minute timeout).
My thought above was that the 3 seconds was not long enough. I am running with 15 seconds now and have yet had any stutters or other issues - it works as well as it did with the old duration computation (which also had a challenge in that the mp3 duration was returned by the media player itself so you had to wait until the sonos was playing the tts message before you knew how long to wait…)