Thomas shares makes

2021-09-09

Home Assistant Multi room audio setup

concept

I was able to cook up a fun audio setup controlled and automated with Home Assistant! It features

  • Multiple room synchronised audio speakers (fixed/analog, portable Bluetooth devices and via app on phone or tablet)
  • Playback of internet radio, Spotify streaming and local audio files.
  • Sound notifications for Doorbell, garden gate and other sensors and home alarm events.

In my setup, a docker container running on the Home Assistant machine takes care of retrieving audio from Spotify, internet radio streams and local storage.

Physical devices like raspberry pi's or an Android phone/tablet use a snapcast client to use drive speakers.

Overview

Adding sound to a smart home used to be a thing of fancy smart-home solutions sold with their own audio server modules that are wired up to multi-room speaker set-ups. Nowadays modular cloud connected voice assistants bring music and notifications to peoples homes.

If you can live without the fancy voice control and enjoy setting up some Linux services, then adding some of the more classic audio features is a doable task, soon to become easier due to a home assistant add-on.

During 2020's work-from-home regime I discovered radio, I listen extensively to radio and Spotify when I'm at home. I wanted to mix in audio notifications like the door bell and a garden gate sensor. This turned out to be easily mixed together using Snapcast.

To listen to music in the rooms next to our living room with an amp/speaker setup, I bought a Bluetooth speaker, figuring I could feed it music via a raspberry pi while at home, and still use it with my phone when in the garden or on the road.

concept

Home assistant integration

Being able to move the speaker along around the house while it's not tied to a particular smart phone (that sometimes walks off) is lovely.

I just had to install and configure existing software, a docker container runs the S6 service supervisor using s6-overlay, like home assistant add-ons. It manages

  • the Snapcast audio server, which starts librespot for Spotify playback
  • a MPD daemon to play music and internet radio
  • a MPD daemon to play notifications

The Snapcast server has a meta source type that will switch between audio sources based on priority which is very powerful yet simple concept. I set it up to prefer notifications over Spotify over music,

The Bluetooth speaker is integrated into home assistant using scripts and a MQTT template 'switch', showing its connection status in home assistant and providing Bluetooth disconnect and connect triggers when operating the switch in home assistant.

Snapcast

The Snapcast website explains it best:

Snapcast is a multi-room client-server audio player, where all clients are time synchronized with the server to play perfectly synced audio. It's not a standalone player, but an extension that turns your existing audio player into a Sonos-like multi-room solution.

concept

Snapcast overview (from the snapcast github page)

Audio is captured by the server and routed to the connected clients. Several players can feed audio to the server in parallel and clients can be grouped to play the same audio stream. One of the most generic ways to use Snapcast is in conjunction with the music player daemon (MPD) or Mopidy.

The Home Assistant Snapcast platform allows you to control Snapcast from Home Assistant.

To add Snapcast to your installation, add the following to your configuration.yaml file:

# Example configuration.yaml entry
media_player:
  - platform: snapcast
        host: YOUR_IP_ADDRESS

Configuration

The Snapserver is configured to accept audio from the MPD's provided at the same sample format of librespot.

The meta source does magic, it switches between sources based on the listed order.

[stream]
source = pipe:///tmp/snapfifo?name=Music&sampleformat=44100:16:2
source = pipe:///tmp/mpd-notify?name=Notify&sampleformat=44100:16:2
source = spotify:///librespot?name=Spotify&bitrate=320&enable-volume-normalisation&sampleformat=44100:16:2
source = meta:///Notify/Spotify/Music?name=Mixed&sampleformat=44100:16:2

MPD Music player daemon

The musicPD is an old-school tool, I believe I was already using it ~15 years ago. It is remarkably elegant, has myriad applications, a nice network protocol and support for lots of stuff.

Playing notifications

To play a notification, the usual home assistant service can be called to play audio on the dedicated MPD:

service: media_player.play_media
data:
  entity_id: media_player.mpd_notification
    media_content_type: music
      media_content_id: bark.wav

After adding the audio files to the music directory, don't forget to update the MPD database.

I had some difficulties with the first few seconds of audio disappearing, which I worked around until digging deeper. I used sox to add a few seconds of silence:

sox -n -r 44100 -c 2 silence.wav trim 0.0 1.5
sox silence.wav bark.wav delayedbark.wav

MPD Configuration

The MPD's are configured to have unique state, database and music paths. They feed their data into their own FIFO (named pipe), and are set to the same (non-standard) sample frequency librespot uses to avoid re-sampling by the Snapcast server.

audio_output {
    type            "fifo"
    name            "my pipe"
    path            "/tmp/snapfifo"
    #format          "48000:16:2"
    format          "44100:16:2"
    mixer_type      "software"
}

MPD Home Assistant integration

Both MPD's have an entry in the Home Assistant configuration.yaml:

# Example configuration.yaml entry
media_player:
  - platform: mpd
    host: IP_ADDRESS
    port: PORT

They run on the same host, but a different port.

Librespot

Librespot allows the Snapcast source to appear as a Spotify speaker on the local network. It announces itself using multicast DNS and automatically appears to local Spotify players.

Very little configuration at all (just the name it has to announce).

Wonderful piece of kit <3.

Raspberry pi with fixed speaker

The only remarkable thing here is that I use the hardware mixer, this allows control of the master volume via Snapcast.

pi@living:~ $ cat /etc/default/snapclient
# Start the client, used only by the init.d script
START_SNAPCLIENT=true

# Additional command line options that will be passed to snapclient
# note that user/group should be configured in the init.d script or the systemd unit file
# For a list of available options, invoke "snapclient --help"
SNAPCLIENT_OPTS="-h 192.168.x.xxx --hostID living --mixer hardware"

On Raspberry pi 2 with Ubuntu 21.01 with a HDMI screen connected, some extra configuration was needed:

SNAPCLIENT_OPTS="-h 192.168.x.xxx --hostID living --mixer hardware:Headphone -s plughw:CARD=Headphones,DEV=0"

Raspberry pi with Bluetooth speaker

I found a nice guide (dutch only) on using a bluetooth speaker with snapcast on the raspberry pi, which guided me to install https://github.com/bablokb/pi-btaudio .

photo of the bluetooth speaker and dongle

I ended up creating my own helper scripts and wrote a separate article about this. This configuration of software packages and scripts supports:

  • starting/stopping snapclient and a Bluetooth button event watcher.
  • network volume control of the Bluetooth speaker
  • re-initiating Bluetooth connection from home assistant

Home assistant add-on

I had a bit of a bad experience trying to create a Snapcast Home Assistant add-on. I built a container image based on the example and added the Snapcast server.

My local Add-on did not show up on the Supervisor tab (using { "image": }).

When I omitted the local image reference, the supervisor tried to build it for the wrong architecture (ARM7 instead of aarch64/arm8).

A long-term goal is to package this as an add-on, for now I run everything as a container on my main server.

More information

I still haven't published info on my snapclient-server-side docker container. TODO...


Liked something? Worked on something similar? Let me know what you think on Twitter!
You can discuss this article at this tweet https://twitter.com/thouters/status/1436066933250699270
You can direct-message me, or mention me @thouters