Bluetooth and Docker (part 2)

Yes, I know there is already a topic on this subject, but it’s out of date.

I have HA running in docker. I have 2 Bluetooth radios, and from the Linux OS I used hciconfig to confirm the OS can see the radios.

docker@foo:~$ hciconfig
hci1:   Type: Primary  Bus: USB
        BD Address: 00:1A:7D:DA:71:15  ACL MTU: 310:10  SCO MTU: 64:8
        UP RUNNING 
        RX bytes:2444 acl:0 sco:0 events:158 errors:0
        TX bytes:3246 acl:0 sco:0 commands:158 errors:0

hci0:   Type: Primary  Bus: USB
        BD Address: C0:B6:F9:8D:A6:75  ACL MTU: 1021:4  SCO MTU: 96:6
        UP RUNNING 
        RX bytes:1965 acl:0 sco:0 events:97 errors:0
        TX bytes:2858 acl:0 sco:0 commands:97 errors:0

docker@foo:~$

I then used bluetoothctl, to scan for devices. I discovered the device (a SwitchBot) I was looking for:

[NEW] Device E9:2B:61:A9:60:9D E9-2B-61-A9-60-9D

My problem is, HA isn’t seeing either radio. I remember some time ago I had to pass in the radio as a volume, like

 - /opt/bluetooth:/var/lib/bluetooth

But I can’t find a directory for the radios. FYI I installed bluez if that is somehow relevant.

sudo apt install bluez

And to cap it all off, I did a docker exec -it homeassistant /bin/bash to enter the container, and ran hciconfig and I see both radios.

Any suggestions on how to get HA to see my Bluetooth radio and get SwitchBot working with HA?

Did you do this?

1 Like

Hello,
i have added everything, which is described as instructions:

 "Volumes": {
                "/config": {},
                "/dev": {},
                "/etc/asound.conf": {},
                "/etc/machine-id": {},
                "/etc/pulse/client.conf": {},
                "/media": {},
                "/run/audio": {},
                "/run/dbus": {},
                "/run/udev": {},
                "/share": {},
                "/ssl": {}

dbus-broker:

● dbus-broker.service - D-Bus System Message Bus
     Loaded: loaded (/lib/systemd/system/dbus-broker.service; enabled; vendor preset: enabled)
     Active: active (running) since Sun 2022-11-13 17:22:58 EET; 12min ago
TriggeredBy: ● dbus.socket
       Docs: man:dbus-broker-launch(1)
   Main PID: 702 (dbus-broker-lau)
      Tasks: 2 (limit: 9319)
     Memory: 5.9M
     CGroup: /system.slice/dbus-broker.service
             ├─702 /usr/bin/dbus-broker-launch --scope system --audit
             └─708 dbus-broker --log 4 --controller 9 --machine-id 2880c2c5af404678b6e9f4050366da65 --max-bytes 536870912 --max-fds 4096 --max-matches 131072 --audit

BlueZ :

Package: bluez
Version: 5.64-0ubuntu1
Priority: optional
Section: admin
Origin: Ubuntu
Maintainer: Ubuntu Bluetooth team <[email protected]>
Original-Maintainer: Debian Bluetooth Maintainers <[email protected]>
Bugs: https://bugs.launchpad.net/ubuntu/+filebug
Installed-Size: 3759 kB
Depends: libc6 (>= 2.34), libdbus-1-3 (>= 1.9.14), libglib2.0-0 (>= 2.31.8), libreadline8 (>= 6.0), libudev1 (>= 196), kmod, udev, lsb-base, dbus
Suggests: pulseaudio-module-bluetooth
Conflicts: bluez-audio (<= 3.36-3), bluez-utils (<= 3.36-3)
Breaks: udev (<< 170-1)
Replaces: bluez-audio (<= 3.36-3), bluez-input, bluez-network, bluez-serial, bluez-utils (<= 3.36-3), udev (<< 170-1)
Homepage: http://www.bluez.org
Task: ubuntu-desktop-minimal, ubuntu-desktop, ubuntu-desktop-raspi, kubuntu-desktop, xubuntu-core, xubuntu-desktop, lubuntu-desktop, ubuntustudio-desktop-core, ubuntustudio-desktop, ubuntukylin-desktop, ubuntu-mate-core, ubuntu-mate-desktop, ubuntu-budgie-desktop, ubuntu-budgie-desktop-raspi
Download-Size: 1106 kB
APT-Manual-Installed: yes
APT-Sources: http://bg.archive.ubuntu.com/ubuntu jammy/main amd64 Packages
Description: Bluetooth tools and daemons
 This package contains tools and system daemons for using Bluetooth devices.
 .
 BlueZ is the official Linux Bluetooth protocol stack. It is an Open Source
 project distributed under GNU General Public License (GPL).

But still no one of my BT devices at home appear in my HA.
What I missing ?

I am facing the same issues

Home Assistant 2022.12.1 on docker on a rpi4. Source: linuxserver/homeassistant - LinuxServer.io

After login to HA (on Portainer), I could see bluetooth adapters (hcitool dev), scan and see BLT devices (hcitool lescan). But Bluetooth passive monitoring shows no Xiaomi Bluetooth Thermometer (running customized firmware). In the meantime, on HA OS running on another rpi3, I can see my devices.

I tried to enable log for bluetooth plugins and got some errors.

HCIdump thread: Something wrong - interface hci0 not ready, and will be skipped for current scan period.

The thing is I bought a “compatible” bluetooth USB dongle as mentioned somewhere, but that does not seems to help.

Looked up and found this: [Bug]: HCIdump thread: Something wrong - interface hci0 not ready, and will be skipped for current scan period. · Issue #827 · custom-components/ble_monitor · GitHub
That ticket is still open.

Tried many things like setting permission so python can use bluetooth script/devices. Bind /run/dbus. Install dbus-broker.

No luck so far.

Is anyone pushing to solve this extremely annoying issue?

1 Like

Not sure if this helps, but I had a similar issue (running lsio HA on Ubuntu server 22.04 LTS miniPC) and I solved it by apt install dbus-broker. After restarting, HA picked up Bluetooth

esp bluetooth proxy solved it for me

Having similar problem. I am running HA on top of docker (compose) and the container CAN see the bluetooth dongle’s MAC address upon running hciconfig & hcitool dev. However, trying to add the Bluetooth integration just gives me the “0 devices found” error. The OS is also able to use the bluetooth adapter at the same time.

Any suggestions?

Thanks!

Same for me

Thank you for this post. Thats the first time I read about .

For some, but probably not all, the actual issue can be seen in the logs searching for “dbus”. If you see “EXTERNAL, REJECTED” there it’s an issue with the python library dbus-fast and running H-A in a rootless Docker container (or podman).

It’s probably this error, which has unfortunately been closed as a configuration issue (it isn’t): Bluetooth in container (podman) gives dbus-related error: authentication failed: REJECTED: ['EXTERNAL']) · Issue #76429 · home-assistant/core · GitHub

I spent way too much time looking into this today, since not being able to set up bluetooth stopped me from being able to use ESPHome. It turns out that dbus-fast isn’t authenticating the way it should, and patching the code makes it work.

My dirty patch follows.

Enter your container using docker exec, then:

# vi /usr/local/lib/python3.11/site-packages/dbus_fast/auth.py

Add a line to this function:

   def _authentication_start(self, negotiate_unix_fd: bool = False) -> str:                                                
        self.negotiate_unix_fd = negotiate_unix_fd                                                                          
        self.uid = UID_NOT_SPECIFIED                                                                                        
        uid = self.uid 

Save, restart your container. The information behind this patch comes from a discussion on libdbus: libdbus client should try "AUTH EXTERNAL\r\n" first? (#195) · Issues · dbus / dbus · GitLab

I now have host bluetooth working fine inside my rootless docker H-A container without resorting to using --privileged or other security problems.

1 Like

Thanks for the input, it works indeed. The edited function shall look as follows:

def _authentication_start(self, negotiate_unix_fd: bool = False) -> str:
        self.negotiate_unix_fd = negotiate_unix_fd
        self.uid = UID_NOT_SPECIFIED
        uid = self.uid
        if uid == UID_NOT_SPECIFIED:
            return "AUTH EXTERNAL"
1 Like

I didn’t have a problem with dbus authentication, but even though I could see the bluetooth interface from inside the running docker and the bluetooth integration found the interface, the logs were getting

[custom_components.ble_monitor] HCIdump thread: Something wrong - interface hci0 not ready, and will be skipped for current scan period.

I discovered that the linuxserver.io docker image explictly sets a capability on the python executable in etc/s6-overlay/s6-rc.d/svc-homeassistant/run just before starting Home Assistant, which undoes the setting advised in the BLE Monitor FAQ.

With the changes below I have a docker image running as non-root and getting BLE updates from temperature sensors. It’s possible that some of them aren’t necessary.

In /etc/s6-overlay/s6-rc.d/svc/homeassistant/run change
setcap ‘cap_net_bind_service+ep’ /usr/local/bin/python3.12
to
setcap ‘cap_net_bind_service,cap_net_raw,cap_net_admin+eip’ /usr/local/bin/python3.12

install aioblescan & janus in the image (apk add aioblescan janus)

Start the docker image with --cap-add=NET_ADMIN --cap-add=NET_RAW --netwok=host
Pass through the device /var/run/dbus:/var/run/dbus:ro

@troed @TriplEight do you think it makes sense to upstream the changes you suggested to GitHub - Bluetooth-Devices/dbus-fast: A faster version of dbus-next? That way, the fix would propagate to Home Assistant when they update the dependency

1 Like

Is your patch still working, or did you find out some other way to solve it? I have the same problem, running podman rootless, but adding that line (now for python 3.13) does not work since it seems to reset on container restart. Im quite new to this though, so might be doing something else wrong :slight_smile:

One possible workaround that does not require modifying the container image is to patch the code at runtime. You can do this with a minimal custom component. Create the following two files:

==> custom_components/dbus_userns_patch/__init__.py <==
"""Patch to allow DBus connections from inside a user namespace."""

from __future__ import annotations

import dbus_fast.auth

from homeassistant.core import HomeAssistant
from homeassistant.helpers.typing import ConfigType

async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
    dbus_fast.auth.UID_NOT_SPECIFIED = None
    for entry in hass.config_entries.async_entries('bluetooth', False, False):
        hass.config_entries.async_schedule_reload(entry.entry_id)
    return True
==> custom_components/dbus_userns_patch/manifest.json <==
{
    "domain": "dbus_userns_patch",
    "integration_type": "system",
    "name": "DBus User Namespace Patch",
    "version": "1"
}

and enable it with dbus_userns_patch: in your config.

The downside of this method is that because the bluetooth integration is loaded before custom components, it will fail to initialize the first time, so you will still get the error in your logs, but this component will reload the Bluetooth adapters automatically.

1 Like

Works great with rootless podman container.
Thanks @smaeul !

There is even a more easy approach if using docker compose.

For future readers who falls into this rabbit hole and want to add the default bluetooth device, instead of an external bluetooth device:

  1. Run outside of docker on host hciconfig -a you might see somthing like this : hci0: Type: Primary BusL UART. You know your device is at /dev/hci0
  2. Modify docker-compose.yaml and add your bluetooth device:
services:
---
  homeassistant:
    container_name: homeassistant
    image: ghcr.io/home-assistant/home-assistant:stable
    network_mode: host
    privileged: true
    devices:
      - /dev/hci0:/dev/hci0 #bluetooth device
    volumes:
      - /path/to/config:/config
      - /run/dbus:/run/dbus
    restart: unless-stopped

or more secure:
if you want full priveleged mode and minimal permissions:

services:
---
  homeassistant:
    container_name: homeassistant
    image: ghcr.io/home-assistant/home-assistant:stable
    network_mode: host
    cap_add:
      - NET_ADMIN
      - NET_RAW
    devices:
      - /dev/hci0:/dev/hci0 # bluetooth device
    volumes:
      - /path/to/config:/config
      - /run/dbus:/run/dbus
    restart: unless-stopped
  1. Restart home assistant
docker compose down homeassistant && docker compose up -d homeassistant
  1. test bluetooth controller:
docker exec -it homeassistant bluetoothctl show

If the bluetooth controller details appear, the setup is working

It’s still working fine (with the change to the Python version). You need to apply the patch to a docker image you build yourself from though to get it to stick.