Whirlwind volgt de ontwikkelingen van home automation met interesse en schrijft uit eigen ervaring zo nu en dan een artikel over dit onderwerp. In dit artikel maken we middels de Snapcast-software op een Raspberry Pi met HiFiBerry-geluidskaart een multi-room-audiosysteem dat gevoed wordt door een Chromecast Audio (of een ander apparaat dat op de line-in van de geluidskaart kan worden aangesloten). De Snapcast-software en de Chromecast Audio kunnen beide door de home automation software Home Assistant bediend worden.
Snapcast bestaat uit een server en client. Snapserver stuurt het geluid naar snapclients binnen het netwerk, waarna zij het geluid synchroon afspelen. Het is mogelijk om op dezelfde Raspberry Pi zowel snapserver als snapclient te installeren.
Op de Raspberry Pi maken we gebruik van het besturingssysteem Raspbian. Aangezien Raspbian gebaseerd is op de Linux-distributie Debian, kunnen we als volgt het Debian package van Snapcast downloaden. Op het moment van schrijven is Snapcast 0.16 de nieuwste versie. Zie https://github.com/badaix/snapcast/releases voor de actuele versie.
wget https://github.com/badaix/snapcast/releases/download/v0.16.0/snapserver_0.16.0_armhf.deb
Pak het Debian package als volgt uit en installeer het vervolgens:
sudo dpkg -i snapserver_0.16.0_armhf.deb
sudo apt-get -f install
Test snapserver als volgt. De tekst active (running) geeft aan dat snapserver draait.
sudo systemctl status snapserver
Herhaal de bovenstaande stappen voor de snapclient.
We gebruiken de HiFiBerry DAC+ ADC geluidskaart. De input van deze geluidskaart gebruiken we om de muziek van bijvoorbeeld een Chromecast Audio op te nemen en de output gebruiken we om de muziek af te spelen. Als volgt koppelen we snapclient aan de output van de geluidskaart. Met het onderstaande commando zoeken we eerst de naam van de geluidskaart op:
snapclient -l
Een lijst met geluidskaarten verschijnt. We lezen af dat default:CARD=sndrpihifiberry de naam van de geluidskaart is. Open het configuratiebestand van snapclient om de geluidskaart te koppelen:
sudo nano /etc/default/snapclient
Wijzig de waarde van SNAPCLIENT_OPTS als volgt:
SNAPCLIENT_OPTS="--soundcard default:CARD=sndrpihifiberry"
Standaard leest snapserver het FIFO-bestand /tmp/snapfifo uit. De muziekstream bevindt zich in dit bestand. Een FIFO-bestand (first in, first out) is een speciaal bestand waarbij geen data in het bestandssysteem wordt opgeslagen. Een FIFO-bestand is zodoende 0 bytes groot.
Normaal gesproken maakt snapserver het FIFO-bestand /tmp/snapfifo aan. Open het configuratiebestand om in te stellen dat snapserver enkel het FIFO-bestand dient te lezen; niet aanmaken.
sudo nano /etc/snapserver.conf
Wijzig de stream-instelling als volgt. Dankzij mode=read zal snapserver niet zelf het FIFO-bestand aanmaken.
stream = pipe:///tmp/snapfifo?name=default&mode=read
Sluit een Chromecast Audio of een ander apparaat met een 3,5 mm jack-aansluiting aan op de line-in (stereo input) van de HiFiBerry DAC+ ADC geluidskaart en sluit een speaker aan op de output. Speel bijvoorbeeld Spotify af op de Chromecast Audio. Start de opname op de Raspberry Pi als volgt:
arecord --device=plughw:1,0 --format=S16_LE --rate=48000 --channels=2 /tmp/snapfifo
Bovenstaand commando neemt het geluid van de Chromecast Audio op en stuurt deze naar /tmp/snapfifo. Snapserver krijgt het geluid binnen en stuurt dit naar de snapclients. Mocht het volume te laag zijn, gebruik dan alsamixer om het volume in te stellen. Het programma arecord kan beëindigd worden met Ctrl-C.
Tip: schakel middels de apparaatinstellingen van de Chromecast Audio in de Google Home app de optie Volledig dynamisch bereik in. Deze instelling is bedoeld voor hifi-systemen en verbetert de geluidskwaliteit.
Maak als volgt een service aan indien je de geluidsopname automatisch wilt starten bij het opstarten van de Raspberry Pi.
sudo nano /etc/systemd/system/arecord.service
Plaats het volgende in arecord.service:
[Unit]
Description=arecord
After=network-online.target snapserver.service
Requires=network-online.target snapserver.service
[Service]
User=pi
Group=pi
ExecStartPre=/home/pi/snapcast/arecord.sh
ExecStart=/usr/bin/arecord --device=plughw:1,0 --format=S16_LE --rate=48000 --channels=2 --fatal-errors /tmp/snapfifo
Restart=always
[Install]
WantedBy=multi-user.target
In de bovenstaande service is bij ExecStartPre vermeld dat het shell script arecord.sh gedraaid moet worden, voordat arecord wordt gestart (zie ExecStart). Het shell script doet het volgende:
De inhoud van het shell script is als volgt:
#!/bin/sh
# arecord stoppen
killall -q arecord
# Oude FIFO-bestanden verwijderen
find /tmp -maxdepth 1 -type p -name "snap*" -delete
# Oude bestanden verwijderen
find /tmp -maxdepth 1 -type f -name "snap*" -delete
# Nieuwe snapfifo aanmaken
mkfifo /tmp/snapfifo
Maak het shell script uitvoerbaar met chmod a+rx arecord.sh.
Zoals hierboven vermeld kan het gebeuren dat snapfifo-01, snapfifo-02, enzovoort in /tmp aangemaakt worden. Indien dit gebeurt, willen we dat de arecord service automatisch herstart wordt. De ExecStartPre van de arecord service zal dan namelijk het shell script arecord.sh aanroepen, dat de ongewenste bestanden verwijdert.
Middels de onderstaande path unit monitoren we de aanwezigheid van bestanden in /tmp waarvan de bestandsnaam met snapfifo- begint. Maak deze path unit aan in /etc/systemd/system/arecord-watcher.path.
[Unit]
Description=arecord-watcher
[Path]
PathExistsGlob=/tmp/snapfifo-*
[Install]
WantedBy=multi-user.target
Maak /etc/systemd/system/arecord-watcher.service aan. Deze service wordt gestart door de bovenstaande path unit indien bijvoorbeeld /tmp/snapfifo-01 gedetecteerd is. Overigens is het van belang dat de naam van de path unit en service hetzelfde zijn, vandaar de namen arecord-watcher.path en arecord-watcher.service.
[Unit]
Description=arecord-watcher
[Service]
Type=oneshot
ExecStart=systemctl restart arecord.service
[Install]
WantedBy=multi-user.target
Herlaad als volgt systemd en stel in dat arecord.service en arecord-watcher.path gestart moeten worden bij het opstarten van de Raspberry Pi:
sudo systemctl daemon-reload
sudo systemctl enable arecord.service
sudo systemctl enable arecord-watcher.path
Bekijk de status van de services en de path unit met:
sudo systemctl status arecord.service
sudo systemctl status arecord-watcher.service
sudo systemctl status arecord-watcher.path
Als je de Snapcast-clients wilt beheren in Home Assistant, schakel je als volgt de Snapcast-component in. Open het configuratiebestand van Home Assistant en plaats daarin het volgende:
media_player:
- platform: snapcast
host: 192.168.178.22
Vul het IP-adres van de Raspberry Pi in waarop snapserver draait. Na de herstart van Home Assistant verschijnt een media player waarmee het volume van de snapclients ingesteld kan worden.
Tip: gebruik in Home Assistant ook de Google Cast-integratie. Hiermee kan de Chromecast gepauzeerd worden en naar het vorige en volgende nummer gesprongen worden. Verder is het volume instelbaar en wordt de cover getoond.
Met de Spotcast custom component is het mogelijk om Spotify te starten op een idle Chromecast device. Dit maakt het mogelijk om een Spotify playlist te starten zonder gebruik te maken van de Spotify app, bijvoorbeeld na een druk op een knop.
Onderstaand een voorbeeld van een script dat Spotify via Spotcast start op een Chromecast:
spotify:
alias: Spotify
sequence:
- service: spotcast.start
data:
entity_id: media_player.chromecast
uri: 'spotify:playlist:21oVzNKpKHwtFsAYSVMkx9'
random_song: true