Sendspin Bluetooth Bridge — turn any BT speaker into an MA player and HA

The bridge is .18
MA is 2.9.0b.9
Credentials for Mosquitto are correct, work for Frigate, work when the AI had me download a mqtt mosquitto docker directlya to the Pi and then connect there.

So in summary, I updated to v2.66.18. The log shows no “HA MQTT: connecting to…” line at all. The MQTT publisher is still not initializing. My config has “HA_INTEGRATION”: { “enabled”: true, “mode”: “mqtt” } with valid broker 192.168.1.55:1883 and credentials that work from other containers. The bridge connects to Music Assistant fine and plays audio. But the HA integration never starts. What additional debug can I enable to see why the HA MQTT publisher is not being initialized?

I’m not really a docker or networking expert so all I can do is use AI when it doesn’t work, so please don’t get mad at me for that. I’m really trying to help.

I just created a new report.

Q. Why am I doing a new report to Github each time rather than adding comments?

1 Like

Done a lot of testing, again with AI. Here’s what we see:

harry1@rooftop-bridge:~/sendspin-bt-bridge $ ^C
harry1@rooftop-bridge:~/sendspin-bt-bridge $ docker logs sendspin-client 2>&1 | grep -i "mqtt\|disconnect\|error" | tail -50
2026-04-30 15:58:57,533 - sendspin_bridge.bridge.client - ERROR - [Rooftop BT @ rooftop-bridge] daemon stderr: Failed to load cookie file from cookie: No such file or directory
2026-04-30 15:58:57,711 - sendspin_bridge.bridge.client - ERROR - [Rooftop BT @ rooftop-bridge] daemon stderr: Failed to load cookie file from cookie: No such file or directory
2026-04-30 15:58:57,883 - sendspin_bridge.bridge.client - ERROR - [Rooftop BT @ rooftop-bridge] daemon stderr: Failed to load cookie file from cookie: No such file or directory
2026-04-30 15:58:58,033 - sendspin_bridge.bridge.client - ERROR - [Rooftop BT @ rooftop-bridge] daemon stderr: Failed to load cookie file from cookie: No such file or directory
2026-04-30 15:58:58,198 - sendspin_bridge.bridge.client - ERROR - [Rooftop BT @ rooftop-bridge] daemon stderr: Failed to load cookie file from cookie: No such file or directory
2026-04-30 15:58:58,391 - sendspin_bridge.bridge.client - INFO - [Rooftop BT @ rooftop-bridge/proc] Server disconnected
2026-04-30 16:03:11,455 - sendspin_bridge.bridge.client - INFO - [Rooftop BT @ rooftop-bridge/proc] Server disconnected
2026-04-30 16:03:54,106 - sendspin_bridge.services.ha.ha_mqtt_publisher - INFO - HA MQTT: connecting to 192.168.1.55:1883
2026-04-30 16:03:55,378 - websockets.client - DEBUG - < TEXT '{"message_id":"4","error_code":12,"details":"In...and: subscribe_events"}' [80 bytes]
    raise TimeoutError()
TimeoutError
2026-04-30 16:03:55,576 - sendspin_bridge.web.routes.ma_groups - ERROR - MA mDNS discovery failed
    raise RuntimeError("Discovery failed")
RuntimeError: Discovery failed
2026-04-30 16:04:22,016 - sendspin_bridge.bridge.client - ERROR - [Rooftop BT @ rooftop-bridge] daemon stderr: Failed to load cookie file from cookie: No such file or directory
2026-04-30 16:04:22,516 - sendspin_bridge.bridge.client - ERROR - [Rooftop BT @ rooftop-bridge] daemon stderr: Failed to load cookie file from cookie: No such file or directory
2026-04-30 16:04:22,581 - sendspin_bridge.bridge.client - ERROR - [Rooftop BT @ rooftop-bridge] daemon stderr: Failed to load cookie file from cookie: No such file or directory
2026-04-30 16:04:22,645 - sendspin_bridge.bridge.client - ERROR - [Rooftop BT @ rooftop-bridge] daemon stderr: Failed to load cookie file from cookie: No such file or directory
2026-04-30 16:04:24,515 - sendspin_bridge.bridge.client - ERROR - [Rooftop BT @ rooftop-bridge] daemon stderr: Failed to load cookie file from cookie: No such file or directory
2026-04-30 16:04:24,567 - sendspin_bridge.bridge.client - ERROR - [Rooftop BT @ rooftop-bridge] daemon stderr: Failed to load cookie file from cookie: No such file or directory
2026-04-30 16:04:24,744 - sendspin_bridge.bridge.client - ERROR - [Rooftop BT @ rooftop-bridge] daemon stderr: Failed to load cookie file from cookie: No such file or directory
2026-04-30 16:04:24,991 - sendspin_bridge.bridge.client - ERROR - [Rooftop BT @ rooftop-bridge] daemon stderr: Failed to load cookie file from cookie: No such file or directory
2026-04-30 16:04:25,196 - sendspin_bridge.bridge.client - ERROR - [Rooftop BT @ rooftop-bridge] daemon stderr: Failed to load cookie file from cookie: No such file or directory
2026-04-30 16:04:25,329 - sendspin_bridge.bluetooth.dbus - DEBUG - D-Bus battery read failed: org.freedesktop.DBus.Error.InvalidArgs: No such interface 'org.bluez.Battery1'
2026-04-30 16:04:25,440 - sendspin_bridge.bridge.client - ERROR - [Rooftop BT @ rooftop-bridge] daemon stderr: Failed to load cookie file from cookie: No such file or directory
2026-04-30 16:04:25,633 - sendspin_bridge.bridge.client - ERROR - [Rooftop BT @ rooftop-bridge] daemon stderr: Failed to load cookie file from cookie: No such file or directory
2026-04-30 16:04:25,890 - sendspin_bridge.bridge.client - ERROR - [Rooftop BT @ rooftop-bridge] daemon stderr: Failed to load cookie file from cookie: No such file or directory
2026-04-30 16:04:37,599 - sendspin_bridge.bridge.client - ERROR - [Rooftop BT @ rooftop-bridge] daemon stderr: Failed to load cookie file from cookie: No such file or directory
2026-04-30 16:04:46,648 - sendspin_bridge.bridge.client - INFO - [Rooftop BT @ rooftop-bridge/proc] Server disconnected
2026-04-30 16:04:47,640 - sendspin_bridge.bridge.client - INFO - [Rooftop BT @ rooftop-bridge/proc] Disconnecting from previous server
2026-04-30 16:04:47,666 - sendspin_bridge.bridge.client - ERROR - [Rooftop BT @ rooftop-bridge] daemon stderr: Failed to load cookie file from cookie: No such file or directory
2026-04-30 16:04:47,762 - sendspin_bridge.bridge.client - ERROR - [Rooftop BT @ rooftop-bridge] daemon stderr: Failed to load cookie file from cookie: No such file or directory
2026-04-30 16:04:47,939 - sendspin_bridge.bridge.client - ERROR - [Rooftop BT @ rooftop-bridge] daemon stderr: Failed to load cookie file from cookie: No such file or directory
2026-04-30 16:04:48,164 - sendspin_bridge.bridge.client - ERROR - [Rooftop BT @ rooftop-bridge] daemon stderr: Failed to load cookie file from cookie: No such file or directory
2026-04-30 16:04:48,352 - sendspin_bridge.bridge.client - ERROR - [Rooftop BT @ rooftop-bridge] daemon stderr: Failed to load cookie file from cookie: No such file or directory
2026-04-30 16:04:48,545 - sendspin_bridge.bridge.client - ERROR - [Rooftop BT @ rooftop-bridge] daemon stderr: Failed to load cookie file from cookie: No such file or directory
2026-04-30 16:04:48,733 - sendspin_bridge.bridge.client - ERROR - [Rooftop BT @ rooftop-bridge] daemon stderr: Failed to load cookie file from cookie: No such file or directory
2026-04-30 16:04:48,975 - sendspin_bridge.bridge.client - ERROR - [Rooftop BT @ rooftop-bridge] daemon stderr: Failed to load cookie file from cookie: No such file or directory
2026-04-30 16:04:55,389 - sendspin_bridge.bluetooth.dbus - DEBUG - D-Bus battery read failed: org.freedesktop.DBus.Error.InvalidArgs: No such interface 'org.bluez.Battery1'
2026-04-30 16:05:18,778 - sendspin_bridge.bridge.client - INFO - [Rooftop BT @ rooftop-bridge/proc] Disconnecting from previous server
2026-04-30 16:05:18,884 - sendspin_bridge.bridge.client - ERROR - [Rooftop BT @ rooftop-bridge] daemon stderr: Failed to load cookie file from cookie: No such file or directory
2026-04-30 16:05:19,010 - sendspin_bridge.bridge.client - ERROR - [Rooftop BT @ rooftop-bridge] daemon stderr: Failed to load cookie file from cookie: No such file or directory
2026-04-30 16:05:19,206 - sendspin_bridge.bridge.client - ERROR - [Rooftop BT @ rooftop-bridge] daemon stderr: Failed to load cookie file from cookie: No such file or directory
2026-04-30 16:05:19,363 - sendspin_bridge.bridge.client - ERROR - [Rooftop BT @ rooftop-bridge] daemon stderr: Failed to load cookie file from cookie: No such file or directory
2026-04-30 16:05:19,549 - sendspin_bridge.bridge.client - ERROR - [Rooftop BT @ rooftop-bridge] daemon stderr: Failed to load cookie file from cookie: No such file or directory
2026-04-30 16:05:19,703 - sendspin_bridge.bridge.client - ERROR - [Rooftop BT @ rooftop-bridge] daemon stderr: Failed to load cookie file from cookie: No such file or directory
2026-04-30 16:05:19,886 - sendspin_bridge.bridge.client - ERROR - [Rooftop BT @ rooftop-bridge] daemon stderr: Failed to load cookie file from cookie: No such file or directory
2026-04-30 16:05:20,060 - sendspin_bridge.bridge.client - ERROR - [Rooftop BT @ rooftop-bridge] daemon stderr: Failed to load cookie file from cookie: No such file or directory
2026-04-30 16:05:20,257 - sendspin_bridge.bridge.client - INFO - [Rooftop BT @ rooftop-bridge/proc] Server disconnected
2026-04-30 16:05:25,410 - sendspin_bridge.bluetooth.dbus - DEBUG - D-Bus battery read failed: org.freedesktop.DBus.Error.InvalidArgs: No such interface 'org.bluez.Battery1'
harry1@rooftop-bridge:~/sendspin-bt-bridge $ docker logs sendspin-client 2>&1 | grep -i "HA MQTT" | tail -20
2026-04-30 15:32:12,577 - sendspin_bridge.services.ha.ha_mqtt_publisher - INFO - HA MQTT: connecting to 192.168.1.55:1883
2026-04-30 15:35:28,180 - sendspin_bridge.services.ha.ha_mqtt_publisher - INFO - HA MQTT: connecting to 192.168.1.55:1883
2026-04-30 15:51:09,423 - sendspin_bridge.services.ha.ha_mqtt_publisher - INFO - HA MQTT: connecting to 192.168.1.55:1883
2026-04-30 15:54:17,550 - sendspin_bridge.services.ha.ha_mqtt_publisher - WARNING - HA MQTT command loop error: Disconnected during message iteration
2026-04-30 15:57:32,056 - sendspin_bridge.services.ha.ha_mqtt_publisher - INFO - HA MQTT: connecting to 192.168.1.55:1883
2026-04-30 16:03:54,106 - sendspin_bridge.services.ha.ha_mqtt_publisher - INFO - HA MQTT: connecting to 192.168.1.55:1883
harry1@rooftop-bridge:~/sendspin-bt-bri

And here is what AI is saying:

Bridge version: 2.66.18
Mosquitto log shows client sendspin_b9d126e6f669 connected successfully with username harryfine. Bridge log shows “HA MQTT: connecting to 192.168.1.55:1883” but no connection success message.
Then “HA MQTT command loop error: Disconnected during message iteration” appears. The connection works but immediately fails during the message exchange. What MQTT messages is the bridge trying to send immediately after connecting? The developer needs to look at the bridge’s MQTT library implementation. The connection is being established at the TCP level, but the Python MQTT client is not completing its handshake properly. This is likely a bug in the async MQTT library that the bridge uses.

Further evidence that it does connect can be found in Home Assistant’s Mosquitto logs abouit 10 lines from the bottom:

[15:56:24] INFO: Starting NGINX for authentication handling...
[15:56:24] INFO: Starting mosquitto MQTT broker...
2026-04-30 15:56:24: Info: running mosquitto as user: root.
2026-04-30 15:56:24: Warning: Mosquitto should not be run as root/administrator.
2026-04-30 15:56:24: Restored 262 base messages
2026-04-30 15:56:24: Restored 262 retained messages
2026-04-30 15:56:24: Restored 0 clients
2026-04-30 15:56:24: Restored 0 subscriptions
2026-04-30 15:56:24: Restored 0 client messages
2026-04-30 15:56:24: mosquitto version 2.1.2 starting
2026-04-30 15:56:24: Config loaded from /etc/mosquitto/mosquitto.conf.
2026-04-30 15:56:24: Bridge support available.
2026-04-30 15:56:24: Persistence support available.
2026-04-30 15:56:24: TLS support available.
2026-04-30 15:56:24: TLS-PSK support available.
2026-04-30 15:56:24: Websockets support available.
2026-04-30 15:56:24: Loading plugin: /usr/share/mosquitto/go-auth.so
2026-04-30 15:56:24: ├── Username/password checking enabled.
2026-04-30 15:56:24: ├── TLS-PSK checking enabled.
2026-04-30 15:56:24: └── Extended authentication not enabled.
2026-04-30 15:56:24: Plugin has registered to receive 'reload' events.
2026-04-30 15:56:24: Plugin has registered to receive 'basic-auth' events.
2026-04-30 15:56:24: Plugin has registered to receive 'acl-check' events.
2026-04-30 15:56:24: Plugin has registered to receive 'psk-key' events.
2026-04-30 15:56:24: Opening ipv4 listen socket on port 1883.
2026-04-30 15:56:24: Opening ipv6 listen socket on port 1883.
2026-04-30 15:56:24: Opening ipv4 listen socket on port 1884.
2026-04-30 15:56:24: Opening ipv6 listen socket on port 1884.
2026-04-30 15:56:24: Opening ipv4 listen socket on port 8883.
2026-04-30 15:56:24: Opening ipv6 listen socket on port 8883.
2026-04-30 15:56:24: Opening ipv4 listen socket on port 8884.
2026-04-30 15:56:24: Opening ipv6 listen socket on port 8884.
2026-04-30 15:56:24: mosquitto version 2.1.2 running
2026-04-30 15:56:24: New connection from ::1:40378 on port 1883.
2026-04-30 15:56:24: Protocol error from ::1:40378: First packet not CONNECT (0A).
2026-04-30 15:56:24: Client ::1 [::1:40378] disconnected: protocol error.
[15:56:24] INFO: Successfully send discovery information to Home Assistant.
[15:56:25] INFO: Successfully send service information to the Supervisor.
2026-04-30 15:56:25: New connection from 172.30.33.2:45220 on port 1883.
2026-04-30 15:56:25: New client connected from 172.30.33.2:45220 as mqttjs_6082cb07 (p4, c1, k60, u'addons').
2026-04-30 15:56:26: New connection from 172.30.32.1:42347 on port 1883.
2026-04-30 15:56:26: New client connected from 172.30.32.1:42347 as 1VjouLUKiHJxLoLbzGtOZP (p4, c1, k60, u'homeassistant').
2026-04-30 15:56:31: New connection from 172.30.32.1:37082 on port 1883.
2026-04-30 15:56:31: New client connected from 172.30.32.1:37082 as frigate (p4, c1, k60, u'harryfine').
2026-04-30 15:56:48: New connection from 172.30.32.2:38854 on port 1883.
2026-04-30 15:56:48: Client 172.30.32.2 [172.30.32.2:38854] disconnected: connection closed by client.
2026-04-30 15:57:32: New connection from 192.168.1.117:35733 on port 1883.
2026-04-30 15:57:33: New client connected from 192.168.1.117:35733 as sendspin_b9d126e6f669 (p4, c1, k60, u'harryfine').
2026-04-30 15:58:48: New connection from 172.30.32.2:40848 on port 1883.
2026-04-30 15:58:48: Client 172.30.32.2 [172.30.32.2:40848] disconnected: connection closed by client.
2026-04-30 16:00:48: New connection from 172.30.32.2:58574 on port 1883.
2026-04-30 16:00:48: Client 172.30.32.2 [172.30.32.2:58574] disconnected: connection closed by client.
2026-04-30 16:01:22: New connection from 192.168.1.117:37936 on port 1883.
2026-04-30 16:01:22: New client connected from 192.168.1.117:37936 as auto-1C917D6B-39F5-62F9-FA23-1BC19BDB8B55 (p4, c1, k60, u'harryfine').
2026-04-30 16:01:22: Client auto-1C917D6B-39F5-62F9-FA23-1BC19BDB8B55 [192.168.1.117:37936] disconnected.
2026-04-30 16:02:48: New connection from 172.30.32.2:40524 on port 1883.
2026-04-30 16:02:48: Client 172.30.32.2 [172.30.32.2:40524] disconnected: connection closed by client.
2026-04-30 16:03:14: Client sendspin_b9d126e6f669 [192.168.1.117:35733] disconnected.
2026-04-30 16:03:54: New connection from 192.168.1.117:60003 on port 1883.
2026-04-30 16:03:55: New client connected from 192.168.1.117:60003 as sendspin_b9d126e6f669 (p4, c1, k60, u'harryfine').
2026-04-30 16:04:46: New connection from 192.168.1.117:52346 on port 1883.
2026-04-30 16:04:46: Client 192.168.1.117 [192.168.1.117:52346] disconnected: connection closed by client.
2026-04-30 16:04:48: New connection from 172.30.32.2:54086 on port 1883.
2026-04-30 16:04:48: Client 172.30.32.2 [172.30.32.2:54086] disconnected: connection closed by client.
2026-04-30 16:06:48: New connection from 172.30.32.2:49408 on port 1883.
2026-04-30 16:06:48: Client 172.30.32.2 [172.30.32.2:49408] disconnected: connection closed by client.
2026-04-30 16:08:48: New connection from 172.30.32.2:59832 on port 1883.
2026-04-30 16:08:48: Client 172.30.32.2 [172.30.32.2:59832] disconnected: connection closed by client.
1 Like

upgraded to 2.66.20. all is well again. thanks!

1 Like

Not sure what you did in 2.67 but:

Connected via MQTT to 192.168.1.55:1883

Thanks so much.

1 Like

Sendspin BT Bridge — v2.66.15 → v2.67.2 update :tada:

Big arc since the v2.66.14 post: the Home Assistant Configuration tab got a from-scratch UX overhaul, MQTT publisher reliability fixes lifted operators out of multi-minute reconnect gaps reported in #247 / #249, and the in-bridge Class of Device preset dropdown grew from a single Samsung-Q-series workaround into a full preset table covering more speaker families.


:house: HA Configuration tab — UX overhaul
The mode picker is now a three-option segmented control (Off / MQTT / Direct REST) so all transports are visible at a glance. The MQTT card grew a Test connection button that runs a TCP probe + full aiomqtt CONNACK round-trip against the values currently in the form (not the saved config) — so unreachable-broker / auth-failure / TLS-mismatch errors surface inline before you save. The REST card was brought to feature parity: Use auto-detect toggle (replaces the old auto plain-text trick), Suggest from hostname button, optional Bridge host / Bridge port override fields for setups behind a reverse proxy or NAT. Allow Supervisor pairing is now hidden outside HA add-on mode (it had no effect there). Inline indicators next to each mode show whether the Mosquitto add-on is running and whether the HACS custom_component has paired.

:satellite: Class of Device presets — broader hardware coverage
The CoD override widget grew from “custom hex only” into a documented preset dropdown:

  • 0x00010c — Computer / Laptop (Samsung Q-series soundbars)
  • 0x000100 — Computer / generic (broad fallback)
  • 0x000414 — A/V Loudspeaker (LG-style filters)
  • 0x240404 — A/V Headset (Anker Soundcore family)

Each preset corresponds to a documented case where that exact CoD unblocked pairing. Custom hex still available for outliers. Full reference table in the troubleshooting docs with bug-tracker / forum-thread links for every value.

:art: HACS integration ships its own icon
Per the new HA 2026.3 brands API, custom integrations now ship their own brand images. The bridge’s HACS integration ships icon.png (256×256) + [email protected] (512×512) directly — no more external PRs to home-assistant/brands. Older HA versions just render no icon (no functional regression).

:electric_plug: MQTT publisher — reliability under flaky links
Two long-tail bugs surfaced from #249 forum diagnostics:

  • Initial connect could hang silently for minutes. aiomqtt’s Client(timeout=N) only bounds CONNACK and per-op acks; the underlying paho.connect() runs in a thread executor without a wait_for, so a broker that silently drops SYN packets (Mosquitto add-on listening only on the Docker bridge, host firewall blocking the bridge container, etc.) left the publisher in state="connecting" indefinitely with no error log. Now wrapped in asyncio.timeout(15) + a pre-flight TCP probe; failures hit the reconnect loop on the normal path.
  • Mid-session disconnect detection. Network flakes / NAT timeouts / WiFi-BT coexistence on Pi Zero W-class boards used to kill the command-loop task while the publisher kept blocking on stop_event, relying on aiomqtt’s internal disconnect bubbling — observed as multi-minute reconnect gaps with the UI still claiming “connected”. The publisher now races stop / command / publish loops and surfaces worker-task exceptions to the outer reconnect loop.

:stethoscope: Diagnostics — host-side fixes called out specifically
Preflight now probes systemctl is-active bluetooth when no controller surfaces. If the BlueZ daemon comes back as inactive / failed, the onboarding step renames to “Bluetooth daemon (bluetoothd) is not running on the host” and leads with the actual fix — sudo systemctl start bluetooth — instead of the generic “Refresh adapters” UI prompt that several operators were chasing in vain.

:strawberry: Platform / deployment fixes

  • Live demo on Render is back. Service was orphaned since the v2.62 package move; render.yaml now sits at the repo root with a curated demo requirements list that skips the Linux-BT / D-Bus packages Render’s Native Python runtime can’t apt-install.
  • mDNS auto-detect no longer leaks 127.0.1.1. Debian / Ubuntu hosts map their hostname to that loopback alias in /etc/hosts, so the auto-detected REST advertise host was unreachable from HA. Resolution now filters loopback results and falls back to the standard open-UDP-socket-and-read-getsockname trick.
  • Docker HEALTHCHECK fixed. HA add-on mode binds the web server on the Supervisor’s dynamically-assigned ingress port; the old ${WEB_PORT:-8080} fallback never matched, marking the container (unhealthy) and triggering Watchdog restart loops every ~2 minutes. Now the resolved port is written at startup and the HEALTHCHECK reads it.
  • HA-coordinator event stream no longer spams AssertionError every reconnect — the route was setting Connection: keep-alive which WSGI forbids (PEP 3333). Waitress correctly tore the stream down; coordinators reconnected once a minute. Removed.
  • HACS auto-pair on HAOS now resolves the absolute HA URL even when zeroconf hands back the .local hostname instead of a 172.30.32.x IP.

:gear: Behind the scenes
HACS manifest.json version now bumps automatically on every release (it had drifted to 2.66.13 even after the bridge shipped 2.67.0, so HACS users wouldn’t see the update prompt).


As always — feedback and diagnostics reports via the Report button in the bridge UI.
Full changelog: github.com/trudenboy/sendspin-bt-bridge

2 Likes

@trudenboy you have done an amazing job at this. Thank you. You should do 2 things. Stop and enjoy your weekend. Put up a link for donations. :grinning:

1 Like

Hello @trudenboy

I have tried to donate to the project here a number of times with KoFi with both PayPal and credit card, but both times it said something went wrong:

1 Like

Hi @harryfine, thank you both for the kind words earlier and for actually trying to support the project. I really appreciate it.

And thank you for flagging the Ko-fi failure. The issue turned out to be on the PayPal-backed payment path that was servicing those transfers, so I’ve now moved the main donation route away from Ko-fi/Liberapay to WhyDonate. I also verified the new route end-to-end
myself, and it’s working correctly now.

So if you still want to donate, the current options are:

No pressure at all though, your feedback, testing, and reports already help the project a lot. Thanks again.

EDIT: Nevermind, I disabled the Bluetooth integration in Home Assistant, which released the adapter and allowed for pairing. Just a heads up for anyone else who tries this!

ORIGINAL:

Hey @trudenboy! First off, great work - I've seen lots of people asking for bluetooth audio in HA and you've clearly put a lot of effort in.

I'm afraid I have a fairly stupid question to ask. I'm cheap (or at least I was three years ago) and have HA (os) running on a Raspberry Pi 5. Works flawlessly, no complaints. I happen to have a bluetooth receiver hooked up to a set of outdoor speakers and have been trying to use your bluetooth bridge (as an HA add-on) to connect to them. Everything works - except actually finding/connecting/pairing to audio devices.

I'm at a loss - it picked up on my irrigation controller through four walls, but in my testing with various Bluetooth speakers, actual audio devices seem to be the only things that don't show up. I've used a computer to find the bluetooth Mac addresses, and have confirmed that they don't seem to be seen at all - including in the HA bluetooth advertisements page.

I don't understand very well how Bluetooth works - I think it's probably because I'm using the Pi's built-in adapter/bluetooth antennae, but I've never had issues connecting to bluetooth speakers with it before (with other OSs running on it). Thoughts? I'm currently brute-forcing the bridge's scanning page just to make sure, but I don't think I'll have any luck.

1 Like

Thanks for the heads up, @AwesomeCaden73 - and glad you got it working. This is a really useful gotcha for anyone running the addon against the Pi's built-in adapter, so I've added it as its own
section in the troubleshooting docs:

Troubleshooting | Sendspin BT Bridge

If you ever want to keep HA's Bluetooth integration around for other devices, the linked section also points at the cleaner long-term layout - built-in adapter for HA, plus a USB dongle dedicated to the bridge - which avoids the conflict entirely.

Sendspin BT Bridge — v2.67.2 → v2.69.0 update :tada:

A focused round since the v2.67.2 post: per-player sync delay is now drivable from Music Assistant, every bridged speaker shows its own model and manufacturer on the MA player card, settings saves through the dashboard apply more cleanly, and the bundled audio engine rolled forward with two fixes for audible glitches at speaker reconnect and delay changes.


:level_slider: Per-player sync delay in the MA UI (trudenboy/sendspin-bt-bridge#237)
The standard "Static playback delay (ms)" now appears next to every bridged Bluetooth speaker. Drag it in MA, the value applies live, persists across restarts, and stays in sync with the bridge's Web UI. Use it to align a slow Bluetooth speaker with faster Sonos / AirPlay players in the same sync group.

:label: Each speaker shows its own brand on the MA player card
Previously every bridged speaker looked like the same generic Sendspin BT Bridge from the host. Now ENEBY20, JBL Charge, WH-1000XM4 etc. show their own model and manufacturer, with a curated vendor map for common brands (Sony, Bose, JBL/Harman, IKEA, Apple, Samsung, Yandex, Beats, …).

:high_voltage: Settings saves are more honest
A pass over the dashboard's save path: a setting that couldn't reach the speaker process is now flagged as an error instead of silently showing the new value in the UI; slow acks appear as a neutral "Pending live" hint instead of a red banner; saving a global setting no longer triggers a simultaneous reconnect storm across speakers; changing log level in the main form takes effect on the bridge itself immediately.

:speaker_high_volume: Bundled Sendspin audio engine refresh — better sync, fewer glitches
The bundled audio engine rolled forward to upstream 7.3.0, which improves multiroom synchronization in two places that hit the bridge often:

  • No more audible catch-up artifact when a speaker rejoins a stream after a Bluetooth reconnect or a settings save that restarted it — the daemon now stays in sync from the very first sample on resume.
  • Dragging the new per-player delay slider in MA no longer produces a brief glitch — the new delta is applied without breaking sync.

:shield: HA add-on: "Release Bluetooth" survives a restart (trudenboy/sendspin-bt-bridge#276)
The released state used to be forgotten on addon / HA restart, the bridge re-grabbed the speaker, and the soundbar (or whatever else was using it) got cut off. The release now persists across restarts and only the operator can reclaim it.

:sparkling_heart: Sponsorship
Anyone can now buy me a coffee. The funding page accepts regular cards, Apple/Google Pay through WhyDonate, with a separate crypto coffee option for those who prefer it. :wink:


Feedback and diagnostics via the Report button in the bridge UI.
Full changelog: github.com/trudenboy/sendspin-bt-bridge

1 Like

I noticed a large number of errors in my Home Assistant core log this morning. Asked Claude and he said:

This is very clear-cut. Your entire log is dominated by a single repeating error, and it's a straightforward compatibility issue, not anything alarming.

What's happening:

Your Sendspin Bridge add-on (which connects Bluetooth speakers to Home Assistant via MQTT) is sending MQTT discovery messages that include an entity_category value of "sendspin_bridge.config". Home Assistant's MQTT integration only accepts "config" or "diagnostic" as valid values for that field — your version of HA is stricter about this than the Sendspin Bridge was coded for.

So every 30 seconds, Sendspin is republishing its device configuration (for your "Rooftop BT" speaker), and every time it does, HA throws ~8-9 errors — one for each entity (Enabled, BT management, Standby, Power save, Idle mode, Keep-alive method, Static delay, Power save delay).

The result: Those entities are probably not appearing in HA, or are appearing but with errors. The device itself (the Bluetooth speaker) may still work for basic playback, but the management controls via MQTT discovery are broken.

What to do:

The fix needs to come from the Sendspin Bridge side, not Home Assistant. Your options are:

  1. Check for a Sendspin Bridge update — this is likely a known bug they've already fixed. Look in your add-on store for an update to the Sendspin Bridge add-on.
  2. Report it to Sendspin if there's no update — the fix is simple on their end: change entity_category: 'sendspin_bridge.config' to just entity_category: 'config' in their MQTT discovery payload.
1 Like

Sendspin BT Bridge — v2.69.0 → v2.70.0 update :tada:

A pairing-UX & reconnect-stability round. Configured-but-never-paired speakers now get a dedicated remediation flow, a known AVDTP-collision reconnect loop on PipeWire stacks is fixed, and HA 2026.5+ stops rejecting MQTT discovery for per-device settings.


:new_button: Never-paired devices are now first-class (trudenboy/sendspin-bt-bridge#258, #260#263)
A speaker that was added to the bridge but never actually paired now shows a dedicated Start pairing card instead of the generic "needs re-pairing" / "is disconnected" hint, deep-links to the Bluetooth scan modal with the MAC pre-highlighted, and is auto-disabled after BT_MAX_RECONNECT_FAILS failed reconnects so it stops storming BlueZ. The bug-report modal now runs a local pre-submit classifier (never-paired, missing audio sink, MA not connected, no BT adapter) and shows a one-click remediation hint where it can.

:repeat_button: AVDTP-collision reconnect loop on WH-1000XM4 & similar A2DP sinks (trudenboy/sendspin-bt-bridge#269)
On PipeWire stacks the cached-sink fast-path used to race with the speaker's own AVDTP-Suspend, producing a SEP in bad state cluster in bluetoothd and a disconnect about 14 s after each reconnect. The reconnect path now consults org.bluez.MediaTransport1.State before taking the shortcut, and the anti-pop startup mute is deferred until the A2DP transport is actually pending/active.

:wrench: HA 2026.5+ MQTT discovery compliance @harryfine
The per-device settings entities (Enabled, BT management, Standby, Power save, Idle mode, Keep-alive method, Static delay, Power save delay) now ship the standard config entity_category. Older HA silently dropped the non-standard value; 2026.5 rejected each discovery message and broke those entities. As a side benefit they now group under Configuration on the device card.


Feedback and diagnostics via the Report button in the bridge UI.
Full changelog: github.com/trudenboy/sendspin-bt-bridge

Sendspin BT Bridge — v2.70.1 → v2.71.0 update :tada:

A Sendspin-observability & deployment-hardening round. Default port aligned with upstream MA, daemon-exit failures finally visible, RPi / Proxmox LXC installers hardened, and a whole class of silent CPU-baseline crashes is no longer silent.


:satellite: Daemon-exit events are now visible (#291)
Exit code, signal, lifetime and a tail of daemon output now show up on the device card and in a new --- SENDSPIN CONNECTION --- block in the diagnostics report (last 5 spawn cycles, expected/unexpected). The silent ~10 s reconnect loop also auto-detects (last three unexpected exits within ±1 s) and raises a specific guidance banner.

:electric_plug: Default Sendspin port aligned with upstream MA (8927) (#291)
The bridge used to default to 9000; MA's actual provider listens on 8927. Configs that pin 9000 keep working — the port probe runs every spawn and auto-shifts to 8927 if the configured port is closed. SENDSPIN_SERVER is now strictly validated (scheme prefix, embedded port, path, whitespace → clear actionable error), and there's a Test connection button on the MA settings card.

:penguin: Raspberry Pi & Proxmox LXC installer hardening

  • RPi installer auto-runs loginctl enable-linger on PipeWire stacks; preflight flags missing libspa-0.2-bluetooth.
  • Proxmox VM installer pulls libspa-0.2-bluetooth by default.
  • Proxmox LXC one-liner repaired after the lxc/deployment/lxc/ reorg; dbus-python build deps added; bulk pip switched to --ignore-installed, killing the "Cannot uninstall X, RECORD not found" class of error for good.

:brain: CPU-baseline crashes (SIGILL / signal=4) are no longer silent (#291)
On x86_64 hosts below the x86-64-v2 baseline (no SSE4.2 / POPCNT), the daemon's audio path (PyAV / ffmpeg / NumPy wheels) was hitting SIGILL and exiting before any Python try/except ran — looked like a ~10 s reconnect loop with no signal. v2.71.0 reports signal=4 directly. Docs now cover this on every installation page and in a new CPU-baseline crash troubleshooting section with the one-line grep -E 'sse4_2|popcnt' /proc/cpuinfo check.

:clipboard: Tested-hardware references

  • Bluetooth Adapters — new Community-tested adapters block with four Amazon ASINs from #295. Recommended: UGREEN 80889 (B08R8992YC), TP-Link UB500 Nano (B09C25VRXD). Avoid: TP-Link UB500 Plus (B0DHJHMHFS, external antenna) and ZEXMTE 180 m long-range (B0CP5WQ7L8) — the pattern is now documented: long-range / external-antenna BT 5.3 variants underperform vs plain RTL8761B BT 5.0 nano sticks for A2DP.
  • Bluetooth Speakers — new page. Three tiers (confirmed working / with caveats / documented quirks) covering IKEA ENEBY / VAPPEBY / Kallsup, Yandex Mini 2, Lenco LS-500, HUAWEI FreeClip, Soundcore Sport X10, Sony WH-1000XM4 (BlueZ ≥ 5.82), Samsung Q910B (CoD override), Synergy S65 (BlueZ 5.85 floor), JBL PartyBox Encore 2 (solo-only), HMDX Jam, EDIFIER B3, Anker Soundcore 2/3, Xiaomi Mi, STR-DN1080, HK Onyx Studio 3.

If your speaker or adapter isn't on either page, please open an issue with the model and a Diagnostics → Download bundle.

:package: sendspin 7.1.0 → 7.3.1 + dep bumps
Upstream fixes: server-command listener survives daemon reconnect, sendspin serve no longer crashes on Python 3.12, audio-sync delta correct after server-driven delay change, mid-stream joins no longer trigger catch-up burst, ALSA backend closes cleanly. Also cryptography 47 → 48, requests 2.33 → 2.34, idna 3.13 → 3.15, propcache 0.4 → 0.5, astral-sh/uv Docker base 0.11.11 → 0.11.14.

:blue_book: BlueZ ≥ 5.79 is now documented as a prerequisite for the v2.70.0 AVDTP-collision fix (#269)
On RPi OS Bookworm (BlueZ 5.66), MediaTransport1.State returns idle prematurely during AVDTP setup, so the bridge takes the fast-path-skip anyway and the WH-1000XM4 reconnect storm continues. EN + RU troubleshooting now spells out the version split and upgrade path (Debian Trixie / fresh RPi OS 12 / HAOS 17.1+ all ship BlueZ ≥ 5.82).


Full changelog: github.com/trudenboy/sendspin-bt-bridge
Docs: trudenboy.github.io/sendspin-bt-bridge

Hi @trudenboy!

I have a JBL speaker, the JBL app can wake the speaker from OFF state.
Would it be possible to give the Bridge that ability somehow?