TTS with Sonos

I am trying to get started with TTS using my Sonos player. To start with I am just entering some text using the regular Sonos Integration. This results in a message in the Sonon App (e.g. on my phone) saying “Unable to play … _google_translate.mp3’ - the connection to homeassistant.:8123 was lost.”

In the documentation for the Sonos Integration there is nothing to configure but obviously the Sonos player cannot access the files. I can see that the files are generated but where are they supposed to be stored, i.e. what URL to I use if I want to check that I can access them from a web browser?

I am using https with certificates from Let’s Encrypt and I have configured internal_url and base_url properly.

Anyone?

If not I will have to try a solution that does not rely on Home Assistant. Such as https://github.com/kevinvincent/hassio-addons/tree/master/sonos-audioclip-tts that can be installed in a separate container.

Sonos was one of the first Integrations that I setup and it has always worked well (apart from the odd spell where the accent changed to US between HA versions). If it helps here is my configuration.yaml:

tts:
  - platform: google_translate
    service_name: google_say
    cache: true
    cache_dir: /config/tts
    time_memory: 28800
    base_url: http://192.168.1.17:8123
    language: 'en-uk'

My devices were setup using the Sonos Integration:

image

Have a look in your TTS cache directory and see if Google translate is creating the mp3 files (mine is /config/tts as defined in the config above).

I do have a very similar configuration. Yes the files are created and I can access them from within the container running Home Assistant. This is why I am asking for the URL to try to access the files from e.g. a web browser.

tts:
  - platform: google_translate
    language: sv
    cache: true
    cache_dir: /tmp/tts
    time_memory: 300
    base_url: https://homeassistant.xxxx.yy:8123

AFAIK, the /tmp directory isn’t accessible from within HA unless you have explicitly whitelisted. Try changing it to a directory in /config or whitelist your /tmp directory. I know it’s used in the example (https://www.home-assistant.io/integrations/tts/#configuration-variables), but I don’t think that example actually works.

The other issue that I think is there is that Sonos devices, like Google devices, cannot handle self-signed certs. So, in your base_url, change it from https:// to just http:// and see if that works.

For my configuration, I don’t specify the cache_dir at all and have no issues with using TTS with my Sonos speakers.

tts:
  - platform: google_translate
  - platform: amazon_polly
    aws_access_key_id: !secret amazon_polly_key
    aws_secret_access_key: !secret amazon_polly_secret
    engine: neural
    voice: Salli

The /tmp directory is inside the container and not the /tmp directory in the host. As I said I can see the files so this is not the problem, but I tried to remove cach_dir from the config and it makes no difference.

Also, I am not using self signed certificates but tried http:// instead of https://. Again it makes no difference which is expected since Home Assistant is configured to use HTTPS only. I would expect that people are a setup with HTTPS and I would also expect that any issues / fixes would be documented, but maybe I am the first person to try this?

Again my rather basic question now is how am I supposed to access the files from a web browser? I.e. what URL https://homeassistant.xxxx.yy:8123/... is it that Sonos is trying to access?

1 Like

Ahhhh, ok. I forgot to ask if this was a container or a venv install. That makes more sense then.

To get the path that you can call, use the /api/tts_get_url rest API call. Issue a POST request to http[s]://[your_ha_url]:8123/api/tts_get_url. The example provided on the TTS page is old and doesn’t work, but this cURL command should. You’ll probably have to create a new token if you don’t have one handy (from your profile page).

curl -X POST -H "Authorization: Bearer [your_token]" -H "Content-Type:application/json" -d '{"message": "I am speaking now", "platform": "google_translate"}' http[s]://[your_ha_server]:8123/api/tts_get_url

It should spit out a URL for you to test with.

Thanks @code-in-progress this is probably quite helpful. I did not have time to do any more testing yet but just a thought; Sonos is not configured with any token so it that is required it would explain why it does not work. (Or are you saying that this is just to get the URL but if/when you have the URL you can access the file w/o any token?)

Yeah, your token is only needed to get the actual URL. The call from Sonos is just a regular GET to the folder that gets returned.

On my system, this is what is returned:

curl -X POST -H "Authorization: Bearer [token]" -H "Content-Type:application/json" -d '{"message": "I am speaking now", "platform": "amazon_polly"}' http://ha.home.lan:8123/api/tts_get_url

And the return result is:
{"url": "http://192.168.1.10:8123/api/tts_proxy/ace22c85e1db73d4c89012bf1ed2635a333faa26_en-us_43d0e90721_amazon_polly.mp3"}

1 Like

Now I did some more testing based on input from @code-in-progress. (It is super easy to use the API with the “API” node in Node-RED, the token is already configured since before.)

It turns out that everything works just fine if I paste the returned URL into the Chrome Browser, it will play the file.

So the conclusion is that there is an issue with the Sonos integration. Now the question is if I should try to fix it or just try to integrate Sonos directly with Node-RED without going through Home Assistant. (I am doing all my automation in Node-RED anyways.)

2 Likes

Like you, I use NodeRed for most of my automations, but I still keep a few critical ones in HA simply because if NodeRed goes down (it’s on a dedicated server), I don’t want to miss anything critical.

So, last night I decided to goof off and setup the NodeJS Sonos API on one of my test servers. To be honest, I think I’m going to use that for all my Sonos TTS needs. It handles pausing and resuming before and after TTS better than the HA integration does and joining/unjoining seems to be faster/smoother (although that could be just my own perception).

This works flawlessly:

Looks interesting indeed.

Apparently there is already a docker image; https://github.com/chrisns/docker-node-sonos-http-api

(I am currently running all my different services in separate containers on the same host.)

1 Like

I have a “utility” server that does the same thing. All the weird “odds and ends servers” (like Sonos API, Harmony API, Tautulli, Jackett, TasmoAdmin, etc) that I need are all housed on that server. I have a smattering of nodejs services (all managed by PM2) and Docker containers there and keepalived running to make sure that if that server fails, it’s redundant twin gets put into play.

So now I have tested to run the docker image with the Sonos HTTP API (that I linked to above). It works like a charm. (This is very good considering that everything else I have tried failed.)

Next I will set it up so that the tts folder that is used by Home Assistant is mapped to the static/clips folder in the Sonos container. In this way I will be able to use Google Cloud TTS that I have just configured in Home Assistant. I.e. by first generating the file with the tts_get_url request and then use the “Clip” command in the Sonos HTTP API.

1 Like

Have you been able to get the “saypreset” to work? For the sonos-http-api running on a NodeJS server, this is how I’d call it: http://192.168.1.2:5005/saypreset/home/front door is open

I’ve not been able to figure out how to call this from HA, nor how to build the url. saypreset uses json files in the presets folder in the sonos-http-api to group speakers and volume, so my “home” preset includes all internal speakers and “all” adds the pool speakers. I created home_night and all_night to have a quieter nighttime volume. I’ve been using this technique from WebCore for quite a while now with zero issues.

Any advice on getting this working?

I did not try this.

Ok, I’ve been trying to get your method to work, and gave up. I was able to use my NodeJS server though to give me TTS alerts when doors are open.

This is what I did. Since I already have NodeJS and sonos-http-api running on raspberrypi, I added the following to the configuration.yaml

# Rest commands
rest_command:
  sonos_bcast_home:
    url: http://10.1.1.2:5005/saypreset/home/{{ message }}
    method: GET

  sonos_bcast_home_all:
    url: http://10.1.1.2:5005/saypreset/home_all/{{ message }}
    method: GET

the two presets set the speaker groupings and volume. I have 6 Sonos speakers, two of which are outside. home means all internal, home_all is every speaker.

Next, in a simple automation when a door is opened, call the rest method as follows:

 alias: TEST - Sonos - Portal Open
  description: ''
  trigger:
  - device_id: 4f2b9a158d3e4fc29e8041df6c7ec329
    domain: binary_sensor
    entity_id: binary_sensor.hallway_door_contact
    platform: device
    type: opened
  condition: []
  action:
  - data_template:
      message: '{{ trigger.to_state.attributes.friendly_name }} is open'
    service: rest_command.sonos_bcast_home
  mode: single

I did have to go into the binary_sensor.hallway_door_contact and change the name to “Hallway Door” or I’d get “Hallway Door Contact is open” instead of “Hallway Door is open”

Hopefully this helps some of you out, as it’s a really easy way of broadcasting TTS to your Sonos speakers.

Up next is looking at switches to see if broadcast is turned on (turn it off at night when people might be sleeping).

I can share the Sonos config files if people need to see what they look like.

Just a quick addendum: I’ve also been messing with a Sonos One all day today. The only solution for me to output TTS on the Sonos was actually to disable ssl in configuration.yaml. That can’t be a solution in the long run after all…

#http:
# ssl_certificate: /ssl/fullchain.pem
# ssl_key: /ssl/privkey.pem

For the ones interested, I was looking into a solution for my Sonos ones without interrupting the Spotify playlist. After searching I’m now on the add-on from Kevin Vincent (also mentioned by petter_b). https://github.com/kevinvincent/hassio-addons/tree/master/sonos-audioclip-tts

Works great but have to see how it does in the long term. For now my songs are just lowered in volume, TTS will override it with a higher sound volume, and after it everything works normal again. It works the same as you say: Hey google, for example.

1 Like

Does your Sonos resume after the TTS using the node-sonos-http-api ?

I have set mine up (via docker) and i cannot for the life of me get it to resume after playing the TTS