Sonos TTS to Dockerized Home Assistant across VLANs

Hi all,

After a good deal of messing around with firewall rules I have several Sonos speakers communicating from one VLAN to another container my Home Assistant instance. Home Assistant runs in a docker container with several ports exposed to the host as needed. Sister services (Node Red, Mosquitto, etc) communicate using internal docker networks, and users have access through a reverse proxy (Traefik).

The problem is that although I have these speakers added to Home Assistant and tweak controls etc, I can not get TTS working or local media working. No error messages or anything helpful that I can see. The current media stream simply pauses for a short period of time and then resumes. Radio Streams work fine. TTS (Piper and Google) performs as expected in other contexts. This is where I need some help.

Some details for my network configuration:

  • All ports from Home Assistant VLAN to Speaker VLAN allowed
  • Ports 1400 and 1443 from Speaker VLAN to Home Assistant VLAN allowed (see Sonos - Home Assistant)
  • The docker container does not run in host network mode. I explicitly expose certain ports as needed, and I am hesitant to change this.

Here is my docker compose service:

  homeassisstant:
    container_name: homeassistant
    image: ghcr.io/home-assistant/home-assistant:stable
    restart: unless-stopped
    volumes:
      - "${CONF_DIR}/homeassistant:/config"
      - "/etc/localtime:/etc/localtime:ro"
    environment:
      - PATH=/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
      - LANG=C.UTF-8
      - S6_BEHAVIOUR_IF_STAGE2_FAILS=2
      - S6_CMD_WAIT_FOR_SERVICES_MAXTIME=0
      - S6_CMD_WAIT_FOR_SERVICES=1
      - S6_SERVICES_READYTIME=50
      - WHEELS_LINKS=https://wheels.home-assistant.io/musllinux/
      - S6_SERVICES_GRACETIME=
      - TZ=${TZ}
    privileged: true
    ports:
      # sonos reply
      # https://www.home-assistant.io/integrations/sonos/#network-requirements
      - 1400:1400
      # sonos announce tts
      # https://www.home-assistant.io/integrations/sonos/#network-requirements
      - 1443:1443
    networks:
      proxy-server:
      ha-backend:
    depends_on:
      - zigbee2mqtt
      - mqtt
      - influxdb
      - unifi-network-application
    labels:
      # expose to traefik
      - "traefik.enable=true"
      # more traefik labels below...

… and Home Assistant yaml for Sonos:

media_player:
  hosts:
    # add all sonos speakers here. Fix IP addresses in DHCP server
    - !secret sonos_speaker_livingroom_left_ip_address
    - !secret sonos_speaker_livingroom_right_ip_address
  # need to specify HA host for TCP 1400 and 1443
  advertise_addr: !secret homeassistant_server_host_ip_address

Any suggestions? I can see from tcpdump that a lot of requests are being sent to ports 32000-60000 (seemingly at random).

Hi @boosh, I don’t own any Sonos speakers and I am no networking expert by any means, but you might want to try the custom Chime TTS integration.

The chime_tts.say_url service generates TTS MP3 files in your public /local (www) directory. Seeing as the folder is accessible publicly, it might “play nice” with your Sonos speakers.
It also offers a bunch of other features including adding chimes as part of the audio file, and adding different TTS segments with different TTS parameters.

HA actually sends a media URL to Sonos with an HA hostname, if not mistaken.
I’m not sure which hostname it uses, but it will likely fail in a VLAN configuration if the “*.local” host is used.

Use MacVlan

If mdns is involved at all it tends to fail if you run bridge. Macvlan solves that and you can still use bridge for internal container to container networking.

I put a bunch of info in this thread on macvlan

Neat tip @tmjpugh

I had not heard of macvlan in docker, but it definitely seems to fit the bill. In trying this out I realised that I had the firewall rules the wrong way around for 1400 and 1443 (i.e. these were enabled for the speaker source rather than the Home Assistant destination).

The traffic now flows as expected, but still no luck with TTS. With some clumsy workarounds I can now use the media_player.play_media service to play from URLs.

Thanks for letting me know about Chime TTS @Nimrod_Dolev. I will definitely be playing with this more. I took your advice and tried using this with the /local directory. It didn’t work initially as response_variable was using the internal docker network address (http://172.16.0.XXX/local/my-file.mp3), but I was able to stitch together a working URL with Jinja2 string manipulation.

The fact that it was using the internal docker network address, coupled with @koying comment, leads me to believe that this is the culprit. I’ll dig further and report back.

1 Like

@koying The URL was definitely the issue. Setting internal URL to http://:8123 and adjusting my firewall rules allowed TTS to work as expected.

Thanks all!