Simple multiroom with Home Assistant

Video

Imgur

This is a multiroom configuration that allows you to stream music from any music app on your iPhone to speakers in your home. You can listen to music synchronously or individually in each room.

The following components are used:

Shairport-sync - https://github.com/mikebrady/shairport-sync
Snapcast - https://github.com/badaix/snapcast
mini-media-player - https://github.com/kalkih/mini-media-player
inotify - https://github.com/inotify-tools/inotify-tools/wiki

Install

  1. First of all, you need to install shairport-sync on the main device (server). I will not write instructions for installing it here. You can find instructions in the attached links. We will broadcast an audio stream from your phone to the main device. The broadcast will be via Airplay. Shairport-sync must be configured with the following flags: --with-pipe --with-metadata --with-mqtt-client

  2. After installing shairport-sync, you should edit its settings in the file /etc/shairport-sync.conf (when configuring, you specify the path to store the configuration file).
    There is a general group within which you can use the name tag to set the service name.

In the backend group, you need to uncomment the pipe parameter and specify

 name = "/tmp/snapfifo" 

This is the file that the audio stream from your phone will be sent to. It is necessary for the snapcast server to work. The Snapcast component reads this file and broadcasts the audio stream to its clients. At the same time, clients sync with the server and music plays synchronously in all zones. It is also highly recommended to install the client on the server itself,so that it is used for syncing. This will ensure minimal latency and smooth operation.

  1. Install snapcast server and snapcast client on the main device (server).

Edit the settings file snapcast server /etc/snap server.conf

In the stream group, specify

 stream = pipe:// / tmp/snap fifo?name=Snap server&sample format=44100:16:2 

you can specify any desired name and audio format

  1. Add to configuration.yaml file:
media_player:
  - platform: snapcast
    host: 192.168.1.x  # specify your own host
  1. Install snapcast client on your clients (what will you play music on)

  2. Install the mini-media-player component in your Home Assistant. In the mini-media-player settings, specify your snapcast clients and the necessary parameters (control buttons, power button, and so on). After that, cards will appear in your interface to manage all your snapcast clients.

Now you can use your multiroom media system.

In this configuration, you will stream music to just one Airplay device (your main device with shairport-sync). Then the audio stream will be transmitted to clients using snapcast server. This way simultaneous playback will work in all music zones. This is very convenient.

If you want to broadcast different sources of music to different zones, just install own shairport-sync on each client and choose each one individually.

Design

You can use Home Assistant themes to create your own unique interface design.

Metadata

To display the cover of a track (album) that is being played, do the following:

  1. Edit the /etc/shairport-sync.conf file

In the metadata group, uncomment metadata and specify parameters:

metadata = 
{ 
enabled = "yes"; 
include_cover_art = "yes"; 
cover_art_cache_directory = "/tmp/shairport-sync/.cache/coverart"; 
}
  1. In the cover_art_сache_directory parameter, the album cover will be saved along the specified path. The file will be saved with a unique name. It is desirable that when you change the track, the album cover also changes. This is why we will use the Camera component to display the album cover in the Home Assistant interface.

  2. In configuration.yaml file, specify:

camera:
  - platform: local_file
    file_path: /config/www/album_art.jpg
    scan_interval: 20

The scan interval is specified in seconds. You can set your own value.

  1. Next, we need to move the cover file to the /config/www/ folder every time you change a track. It is important that the cover always matches the track being played and the files always have the same name album_art.jpg (so that the camera component always accesses the same file). To do this, we will use the inotify component and a small script to move and rename cover files.

  2. Inotify is a convenient component that tracks changes in folders and files. To install it: sudo apt install inotify-tools

  3. Next, create a script file with any name, for example metadata.sh with the following content:

#!/bin/bash

SRC_DIR="/tmp/shairport-sync/.cache/coverart"
DST_DIR="/xxxx/xxxx/hass_config/www" # specify the exact path in your case

# Function that will perform the necessary actions
# In our case copy to another directory
make_action(){
    # Getting the destination directory
    DIR_TO_COPY_TO=${1/${SRC_DIR}/${DST_DIR}}
    # Creating it if it doesn't already exist
    mkdir -p $DIR_TO_COPY_TO
    # Copying the file
    cp $1$2 $DIR_TO_COPY_TO
    mv $1$2 /xxxx/xxxx/hass_config/www/album_art.jpg # specify the exact path in your case
}

IFS='
'
# Tracking the creation of new files
# Getting the output in the format we need
inotifywait -e create --format '%w %f' -m $SRC_DIR |\
(
while read
do
    # Getting the directory name
    DIR=$(echo $REPLY | cut -f 1 -d' ')
    # Getting the file name
    FILE=$(echo $REPLY | cut -f 2 -d' ')
    # Passing the directory and file names to the function
    make_action $DIR $FILE
done
)
  1. After saving the file, make it executable and add it to autorun so that it starts every time the system starts.

  2. To avoid displaying the camera component name specify in the Lovelace interface:

cards:
  - type: picture-entity
    entity: camera.local_file
    show_state: false
    name: " "

Now you will see which track / album is playing. You can even display this information on any additional display.

MQTT control

You can also control music playback via MQTT.

  1. Install MQTT broker in your system.

  2. Add to configuration.yaml file:

mqtt:
  broker: 192.168.1.x  # specify your own host
  1. Edit the /etc/shairport-sync.conf file

In the mqtt group, uncomment mqtt and specify parameters:

mqtt = 
{ 
enabled = "yes"; 
hostname = "192.168.1.x"; 
topic = "your/topic"; 
publish_parsed = "yes"; 
enable_remote = "yes";
}

Available commands are “command”, “beginff”, “beginrew”, “mutetoggle”, “nextitem”, “previtem”, “pause”, “playpause”, “play”, “stop”, “playresume”, “shuffle_songs”, “volumedown”, “volumeup”

Now you can control music playback via Home Assistant using MQTT commands.

Homekit

Now you can manage your columns via the Homekit component

  1. You can add your snapcast clients to the Homekit as MQTT lights. In the Homekit interface, define the room where the speaker is located and give it the name “Speaker” (or specify your own).

  2. Add to configuration.yaml file:

light:
  - platform: mqtt
    name: "Player1"  # specify your own name
    state_topic: "player1/state"
    command_topic: "player1/switch"
    brightness_state_topic: "player1/brightness"
    brightness_command_topic: "player1/set"
    optimistic: true
  1. Next, you need to create automation so that when you change the brightness value of MQTT light, the volume of the snapcast client also changes.

Add to automations.yaml file:

- id: 'Player1_volume'
  alias: Vol_1_1
  description: ''
  trigger:
  - above: '0'
    below: '25'
    entity_id: light.player1
    platform: numeric_state
    value_template: "{% if states.light.player1 %} \n  {{ state_attr(\"light.player1\"\
      ,'brightness') }}\n{% else %}\n??\n{% endif %}"
  condition: []
  action:
  - data:
      is_volume_muted: false
    entity_id: media_player.snapcast_client_74_de_2b_6a_fd_79  # specify your own snapclient
    service: media_player.volume_mute
  - data:
      volume_level: 0.1
    entity_id: media_player.snapcast_client_74_de_2b_6a_fd_79  # specify your own snapclient
    service: media_player.volume_set

The brightness parameter of MQTT light is set from 0 to 255. Repeat this automation by changing the values above, below and volume_level. You can set the desired step. In my case, I divided this scale into 10 steps for brightness (0-25, 25-50, 50-75, 75-100, 100-125, 125-150, 150-175, 175-200, 200-225, 225-255) and for volume level (0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1).

  1. After creating all the automations, you will get voice control of your speakers. You can adjust the volume in each room. You can also add additional music playback controls to the Homekit via MQTT commands.

Presence detection multiroom

You can install presence or motion sensors in different rooms of the house and make automation so that the music moves with your movement around the house. I haven’t done this yet, but I think it would be interesting.

If someone is implementing something like this, please share exactly how you did it.

Please share your ideas if anyone knows how to improve this configuration.

3 Likes

I’m in the process of creating something similar, can you share your Lovelace?

ui-lovelace.yaml

title: Multiroom
views:
  - background: var(--background-image)
    badges: []
    cards:
#Album art
      - type: picture-entity
        entity: camera.local_file
        show_state: false
        name: " "
#Player 1
      - entity: media_player.snapcast_client_74_de_2b_6a_fd_79
        type: custom:mini-media-player
        artwork: cover
        source: icon
        icon: mdi:cast-audio
        hide:
          power: true
          controls: true
          source: true
#Player 2
      - entity: media_player.snapcast_client_b8_27_eb_a7_68_e4
        type: custom:mini-media-player
        artwork: cover
        source: icon
        icon: mdi:cast-audio
        hide:
          power: true
          controls: true
          source: true
#Player 3
      - entity: media_player.snapcast_client_80_c1_6e_ea_df_95
        type: custom:mini-media-player
        artwork: cover
        source: icon
        icon: mdi:cast-audio
        hide:
          power: true
          controls: true
          source: true
#Player 4
      - entity: media_player.snapcast_client_b8_27_eb_9c_7a_51
        type: custom:mini-media-player
        artwork: cover
        source: icon
        icon: mdi:cast-audio
        hide:
          power: true
          controls: true
          source: true
#Main volume 
      - entity: light.player5
        name: Main volume
        type: light
        icon: mdi:play-circle-outline

    path: play
    theme: Dark - Gray
    title: Play

resources:
  - url: /local/mini-media-player-bundle.js?v=1.7.0
    type: module

1 Like

Thanks for this idea.

I’ve been running shairport-sync for a few years and want to integrate this now with HA.

I’ve set up the metadata pipe and can read it with shairport-sync-metadata-reader.

In the original post, a metadata parameter cover_art_cache_directory is set, but I can’t find any documentation on this. I’ve set this, but no album cover appears (for a variety of tracks played).

I tried to set the pipe timeout but it doesn’t seem to be the issue (I read that large album covers can cause issues).

Are there perhaps any suggestions?

UPDATE 1: The reason I’m asking here, even though it seems more directly related to the shairport-sync project, is that a config option is mentioned that I can’t find in the official docs. I’m happy to log an issue on Github too, but thought it’s better to start here.

UPDATE 2: I should upgrade shairport-sync since I’m on 3.2RC8. I’ll give further feedback once done.

UPDATE 3: Cover art is now saved. Running 3.3.7rc1-alac-OpenSSL-Avahi-ALSA-pipe-soxr-metadata-mqtt-sysconfdir:/etc.

1 Like