Multiroom-Audio aus IKEAs Zehn-Euro-Lautsprecher
Vier KALLSUP-Würfel, ein Bluetooth-Adapter, ein Container auf dem Heimserver und Home Assistant. Ansagen in jedem Raum, Radio wo man es will, und eine physikalische Grenze, die alles Weitere bestimmt hat.
Multiroom-Audio aus IKEAs Zehn-Euro-Lautsprecher
IKEA verkauft einen Bluetooth-Lautsprecher namens KALLSUP für etwa zehn Euro. Ein kleiner Würfel, der für das, was er ist, ordentlich klingt, und sobald ich ihn gesehen hatte, war klar: Ich will vier davon, einen pro Raum. Für zwei Aufgaben: gesprochene Durchsagen von Home Assistant in allen Räumen gleichzeitig und Radio in dem Raum, in dem ich gerade bin.
Vierzig Euro für Lautsprecher, ein USB-Bluetooth-Dongle, und daraus wurde eines der lehrreichsten Projekte, die ich bisher gemacht habe. Nicht weil die Software schwierig war. Sondern weil das Funkmedium es war.
Das Limit, das alles entscheidet
Bluetooth-Audio über A2DP mit dem Standard-Codec SBC kostet ungefähr 345 kbit/s pro Stream. Ein einzelner Dongle muss alle Streams in dasselbe 2,4-GHz-Fenster packen, zusammen mit dem WLAN und allem anderen in der Wohnung.
Der Realtek-Chip in einem typischen Dongle schafft zwei, vielleicht drei dieser Streams zuverlässig. Vier gehen nur mit reduzierter Bitrate und nur in einer ruhigen Funkumgebung. Daran ändert keine Software etwas. PipeWire, PulseAudio, Snapcast, BlueALSA: Jeder Stack erzeugt einen A2DP-Stream pro Lautsprecher, und die Sendezeit ist, wie sie ist.
Das wusste ich beim Start nicht. Es hat eine Weile gedauert, bis ich akzeptiert hatte, dass das Knistern Physik war und kein Bug. Danach ergab sich das Design fast von selbst.
Zwei Modi statt einem
Wenn vier hochwertige Streams nicht nebeneinander funktionieren, versuche ich es gar nicht erst. Stattdessen:
Durchsagemodus: alle vier Lautsprecher verbunden, niedrige SBC-Bitrate. Für Sprache reicht das. Das ist der Standardzustand.
Musikmodus: ein Raum, exklusiv. Alles andere wird getrennt, der eine verbleibende Lautsprecher bekommt den ganzen Kanal. Radio klingt dann wie Radio.
Der Wechsel zwischen beiden ist ein HTTP-Aufruf. Der Rest des Systems ist darauf ausgelegt, beide Modi robust zu machen, denn Bluetooth-Lautsprecher sind nicht dafür gebaut, dauerhaft an einem Linux-Rechner zu hängen, und verhalten sich entsprechend.
Die Kette
Fünf Bausteine. Jeder hat seinen Platz verdient.
1. Der Bluetooth-Container
Ein privilegierter Container auf dem Host, mit eigenem dbus-daemon und bluetoothd, damit er sich nicht mit dem Bluetooth-Stack des Hosts in die Quere kommt. Darauf läuft BlueALSA als A2DP-Source:
BlueALSA statt PulseAudio oder PipeWire, weil es das schlankeste ist, was headless A2DP-Source in einem Container kann, und weil die Projekte, die PulseAudio genau für diesen Zweck probiert haben, aus Stabilitätsgründen davon abgerückt sind.
Für jeden Lautsprecher gibt es eine Supervise-Schleife: Sobald das Gerät Connected: yes meldet, wird der Mixer auf voll gestellt und eine squeezelite-Instanz gestartet, die auf dieses BlueALSA-Gerät zeigt, mit einer gefälschten MAC-Adresse, damit Music Assistant vier verschiedene Player sieht. Stirbt squeezelite, etwa weil der Lautsprecher ausgeschaltet wurde oder außer Reichweite ist, gibt es alle fünfzehn Sekunden einen neuen Versuch.
2. Der Watchdog, und warum er eskaliert
Alle sechzig Sekunden wird alles wieder verbunden, was fehlt. Im Musikmodus nur der eine Raum, der da sein soll.
Dann kommt der Teil, auf den es ankommt: Ist fünfmal hintereinander kein Lautsprecher erreichbar, liegt es fast sicher nicht an den Lautsprechern. Die Realtek-Firmware hat sich aufgehängt. Das ist ein bekanntes, 2026 immer noch offenes Kernel-Problem, und die einzige Abhilfe ist ein USB-Reset des Adapters. Der Watchdog stoppt bluetoothd und bluealsa sauber, setzt das USB-Gerät zurück und beendet den Container, damit Docker ihn frisch neu startet. Begrenzt auf einmal alle dreißig Minuten, damit sich ein wirklich defekter Dongle nicht in einer Schleife selbst zurücksetzt.
Ohne das lief das Setup, bis es stillschweigend nicht mehr lief, und irgendwer hätte Stunden später gemerkt, dass es in der Küche still geworden ist.
3. Der Mode-Service
Home Assistant läuft in einer VM. Der Bluetooth-Container läuft auf dem Host. Die beiden können nicht direkt miteinander reden, also sitzt ein winziger HTTP-Service auf dem Host dazwischen, der genau zwei Befehle kennt:
- mode=music&room=X: die anderen trennen, X als exklusiv markieren, BlueALSA neu starten, X verbinden
- mode=normal: Exklusivität aufheben, BlueALSA neu starten, alle vier verbinden
Keine Authentifizierung. Er läuft im LAN, kann zwei Dinge, und beide macht das jeweils andere wieder rückgängig. Für etwas so Kleines ist das ein vertretbarer Kompromiss.
4. Music Assistant
Music Assistant übernimmt die eigentliche Wiedergabe. Die vier squeezelite-Player tauchen über den squeezelite-Provider auf und sind so eingebunden, dass sie in Home Assistant als normale mediaplayer-Entitäten erscheinen.
Zwei Einstellungen pro Player erledigen das meiste: ein kurzer Signalton vor jeder Durchsage und eine Lautstärkenormalisierung, damit eine TTS-Stimme und ein Radiostream nicht mit völlig unterschiedlichen Pegeln ankommen.
Die Durchsagefunktion von Music Assistant löst außerdem ein Problem, für das ich eigentlich Code schreiben wollte: Läuft in einem Raum gerade Musik, pausiert die Durchsage sie, spricht und setzt die Wiedergabe fort. Gratis.
5. Home-Assistant-Skripte
Ein Skript ist der einzige Einstiegspunkt für Durchsagen. Es nimmt ein Ziel und einen Text, wählt je nach Tageszeit eine Lautstärke (nachts leiser, tagsüber voll), erzeugt die Sprache mit Piper, schickt sie durch eine ffmpeg-EQ-Kette, damit sie nicht wie ein Telefonlautsprecher in einer Blechdose klingt, und übergibt sie mit gesetztem Announce-Flag an Music Assistant.
Die Radio-Schalter gibt es pro Raum: Läuft etwas, wird es gestoppt und es geht zurück in den Durchsagemodus; andernfalls wird in den Musikmodus gewechselt, gewartet, bis der Player da ist, eine sinnvolle Lautstärke gesetzt und der Stream gestartet.
Drumherum ein paar Auslöser: eine Aufwach-Automation, die zehn Minuten vor dem Handy-Wecker im Schlafzimmer das Radio startet und danach zurück in den Durchsagemodus wechselt, zwei günstige IKEA-Taster, ein Voice-Satellit, dessen Taste und Drehrad das Wohnzimmer steuern. Dazu eine Push-Benachrichtigung, wenn ein Raum länger als zehn Minuten nicht verfügbar ist, so erfahre ich von leeren Batterien.
Was noch nicht gelöst ist
Handys klauen Lautsprecher. Ein KALLSUP verbindet sich mit jedem bekannten Gerät, das anfragt. Hat sich ein Handy mit dem Schlafzimmer-Würfel gekoppelt, kann der Würfel einfach verschwinden. Es gibt keine Whitelist und kein Multipoint bei einem Zehn-Euro-Lautsprecher. Die einzige echte Gegenmaßnahme liegt bei den Handys: das Gerät vergessen oder die automatische Verbindung ausschalten. Der andere Trick, den ich noch nicht umgesetzt habe: im Musikmodus die drei ungenutzten Lautsprecher verbunden, aber untätig lassen, statt sie zu trennen. Eine verbundene Senke mit nur einer Quelle lässt sich nicht stehlen, und eine untätige Verbindung kostet fast keine Sendezeit.
Keine echte Synchronisation. Vier unabhängige A2DP-Streams driften auseinander. Bei Sprache spielt das keine Rolle. Bei Musik über mehrere Räume wäre es nicht akzeptabel, ein weiterer Grund, warum der Musikmodus nur einen Raum bedient.
Musik nur in einem Raum. Gewollt, siehe oben.
Ist das wirklich der beste Weg
Nach dem Bau habe ich einen Nachmittag lang ernsthaft geprüft, ob es eine sauberere Lösung gibt, unter der Bedingung, dass die Hardware exakt gleich bleibt. PipeWire mit combine-stream, PulseAudio mit combine-sink, Snapcast, Home-Assistant-Add-ons mit USB-Passthrough in die VM, bessere Codecs, andere Player.
Fast alle scheitern am selben Punkt: Sie ändern nichts an der Zahl der A2DP-Streams auf dem Dongle und können deshalb das Problem, das wirklich wehtut, nicht beheben. Hochwertigere Codecs machen es schlimmer, weil sie die Bitrate erhöhen. Passthrough in die VM würde den USB-Reset auf Host-Ebene entfallen lassen, und der ist das wichtigste Stück des Watchdogs.
Ein Projekt ist einen Parallelversuch wert: eine kürzlich noch aktive Bluetooth-Bridge für das Sendspin-Protokoll von Music Assistant, die squeezelite, den Mode-Service und den Großteil meiner Skripte durch ein gepflegtes Tool mit Weboberfläche und nativen Durchsagen ersetzen würde. Es ist jung und PulseAudio-basiert, deshalb wechsle ich erst, wenn es vier Lautsprecher mindestens so stabil betreibt wie das aktuelle Setup. Tut es das nicht, ist die selbstgebaute Variante objektiv die bessere, und das über ein Bash-Skript sagen zu können, ist ein seltsames und zufriedenstellendes Gefühl.
Hat es sich gelohnt
Vierzig Euro für Lautsprecher, ein Dongle für fünfzehn Euro und Hardware, die ich schon hatte. Dafür kann jetzt jeder in der Küche der ganzen Wohnung etwas durchsagen, das Schlafzimmer weckt mit Radio, und ich verstehe Bluetooth-Audio weit besser, als ich je wollte.
Die Lehre, auf die ich immer wieder zurückkomme: erst die physikalische Grenze finden. Jede Stunde, die ich verbracht habe, bevor ich die Realität von zwei bis drei Streams akzeptiert hatte, ging dafür drauf, das Falsche zu reparieren. Danach war jede Designentscheidung leicht.