SONOS TTS Script

Dear all,

If you can also help me with this related issue:

https://github.com/home-assistant/home-assistant/issues/6424

Thank you a lot in advance :slight_smile:

I just had a quick look at your config and wondering if you’re asking for all 3 sensors to trigger before the automation runs. Have you tried with just one entity_id to see if that works?

I’m getting:
voluptuous.error.MultipleInvalid: offset "0:0:0" should be format 'HH:MM' or 'HH:MM:SS'
when the dynamic delay is calculated.
Any idea?

It’s getting 0:0:0 for the duration instead something like 00:00:35. It would be helpful to see your configuration to see why it’s getting nothing for the duration.

here you go. Please let me know if you need more.

configuration:

homeassistant:
  name: Home
  latitude: !secret home_latitude
  longitude: !secret home_longitude
  elevation: 21
  unit_system: metric
  time_zone: Europe/Brussels
  customize: !include customize.yaml

tts:
  - platform: google
    cache: true
    time_memory: 300
    language: 'nl'

scriot:

sonos_tts:
  alias: Sonos Text To Speech
  sequence:
- service: media_player.sonos_snapshot
  data_template:
    entity_id: "{{ 'media_player.' ~ where }}"
- service: tts.google_say
  data_template:
    entity_id: "{{ 'media_player.' ~ where }}"
    message: "{{ what }}"
- 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 %}
    "{{ [hours, minutes, seconds]|join(':') }}"
- service: media_player.sonos_restore
  data_template:
    entity_id: "{{ 'media_player.' ~ where }}"

automation:

 alias: 'Testing TTS to Sonos'
  trigger:
    - platform: state
      entity_id: input_boolean.test
      from: "off"
      to: "on"
  action:
    - service: script.turn_on
      entity_id: script.sonos_tts
      data:
        variables:
          where: 'playbar'
          what: 'Hallo!'
    - service: input_boolean.turn_off
      entity_id: input_boolean.test
1 Like

Would also need to see the script.sonos_tts

added to previous post.
Formatting in the file is correct, doesn’t come out right in the post.

Try this: the spacing was a bit off, but that could be copying and pasting. Also script was misspelled but that might be a typo. The main problem I saw was a . missing in the line {% set duration = states.media_player.[where].attributes.media_duration %}. I think that was your main problem it wasn’t getting the duration.

script:

  sonos_tts:
    alias: Sonos Text To Speech
    sequence:
    - service: media_player.sonos_snapshot
      data_template:
      entity_id: "{{ 'media_player.' ~ where }}"
    - service: tts.google_say
      data_template:
      entity_id: "{{ 'media_player.' ~ where }}"
      message: "{{ what }}"
   - 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 %}
       "{{ [hours, minutes, seconds]|join(':') }}"
  - service: media_player.sonos_restore
    data_template:
    entity_id: "{{ 'media_player.' ~ where }}"
2 Likes

adding the “.” causes an error in my configuration.
I don’t think that’s it. In all above scripts the “.” is also missing.
Maybe the
unit_system: metric
is causing it?

I have the same problem. It’s really quite strange. With this line, it does not work:

{% set duration = states.media_player.[where].attributes.media_duration %}

When I run a config check, it gives the error:

ERROR (MainThread) [homeassistant.bootstrap] Invalid config for [script]: [delay] is an invalid option for [script]. Check: script->script->sonos_tts->sequence->3->delay. (See /root/.homeassistant/configuration.yaml, line 101). Please check the docs at https://home-assistant.io/components/script/

But if I change it to this (only removing the period):

{% set duration = states.media_player[where].attributes.media_duration %}

The config check outs fine, but upon initiating the script, it gives an error:

ERROR (MainThread) [homeassistant.core] Error doing job: Task exception was never retrieved
Traceback (most recent call last):
  File "/usr/local/lib/python3.5/dist-packages/homeassistant/helpers/config_validation.py", line 163, in time_period_str
    parsed = [int(x) for x in value.split(':')]
  File "/usr/local/lib/python3.5/dist-packages/homeassistant/helpers/config_validation.py", line 163, in <listcomp>
    parsed = [int(x) for x in value.split(':')]
ValueError: invalid literal for int() with base 10: '"0'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.5/dist-packages/voluptuous/schema_builder.py", line 192, in __call__
    return self._compiled([], data)
  File "/usr/local/lib/python3.5/dist-packages/voluptuous/schema_builder.py", line 625, in validate_callable
    return schema(data)
  File "/usr/local/lib/python3.5/dist-packages/homeassistant/helpers/config_validation.py", line 165, in time_period_str
    raise vol.Invalid(TIME_PERIOD_ERROR.format(value))
voluptuous.error.Invalid: offset "0:3:44" should be format 'HH:MM' or 'HH:MM:SS'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/lib/python3.5/asyncio/tasks.py", line 239, in _step
    result = coro.send(None)
  File "/usr/local/lib/python3.5/dist-packages/homeassistant/helpers/script.py", line 102, in async_run
    delay.async_render(variables))
  File "/usr/local/lib/python3.5/dist-packages/voluptuous/validators.py", line 264, in __call__
    raise e if self.msg is None else AllInvalid(self.msg)
  File "/usr/local/lib/python3.5/dist-packages/voluptuous/validators.py", line 262, in __call__
    v = schema(v)
  File "/usr/local/lib/python3.5/dist-packages/voluptuous/schema_builder.py", line 192, in __call__
    return self._compiled([], data)
  File "/usr/local/lib/python3.5/dist-packages/voluptuous/schema_builder.py", line 625, in validate_callable
    return schema(data)
  File "/usr/local/lib/python3.5/dist-packages/voluptuous/validators.py", line 230, in __call__
    raise error if self.msg is None else AnyInvalid(self.msg)
  File "/usr/local/lib/python3.5/dist-packages/voluptuous/validators.py", line 224, in __call__
    return schema(v)
  File "/usr/local/lib/python3.5/dist-packages/voluptuous/schema_builder.py", line 196, in __call__
    raise er.MultipleInvalid([e])
voluptuous.error.MultipleInvalid: offset "0:3:44" should be format 'HH:MM' or 'HH:MM:SS'

Ah so maybe the jinja auto puts the . in there? Well the new log shows it’s getting a time just not putting the 0’s in. I’ll check what I have when I get home later tonight and try to compare.

The other thing to check is see if you have a file in the TTS folder. If not, that may be part of the problem too.

This causes issues for me as well if tts is not able to fully load the file from Google to HA and then to Sonos. Is it possible to ensure that tts.google_say ends up loading the file and starting playing it before the script continues?

If I run the code without the . (where the config check says it’s all good), then the TTS plays on the Sonos speaker, but everything after that does not execute. So the sonos_restore command is not executed and the speaker just goes silent.

The error as stated above still remains the same, except the duration is being put in, just not formatted correctly with leading zeros if they are needed.

So I guess the problem has nothing to do with the . missing, as you stated above. It’s more to do with the formatting of the values [seconds, minutes, hours] and not having a leading zero where the value is less than 10.

If I comment out the below section of the code it works normally. I hear “Hallo” from my Sonos and after a few seconds (I changed delay to 4 seconds) the TV sounds resumes again.

- 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 %}
    "{{ [hours, minutes, seconds]|join(':') }}"

What about this one please:

https://community.home-assistant.io/t/script-issue-with-tts-and-sonos-mediaplayer-my-house-thank-you-p/17026

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):

{{ “%02i:%02i:%02i”|format(hours, minutes, seconds)}}

The full script below:

sonos_tts:
  alias: Sonos Text To Speech
  sequence:
    - service: media_player.sonos_snapshot
      data_template:
        entity_id: "{{ 'media_player.' ~ where }}"
    - service: tts.google_say
      data_template:
        entity_id: "{{ 'media_player.' ~ where }}"
        message: "{{ what }}"
    - 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 }}"

Now the script works pretty well, and its even faster to resume the sonos state!

Good luck!

3 Likes

UPDATE:

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.

Finally. MOved the HASS node to the local lan and this is working much better.

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
3 Likes