On Orange Pi 3B, the built-in Bluetooth chip Spreadtrum UWE5622 is connected via UART (/dev/ttyBT0). Unlike USB adapters, it requires:
- Loading firmware and calibration data before initialization
- Running
hciattach_opiwith correct flags - Correct startup order: chip initialization first, then BlueZ daemon
Symptoms:
bluetoothctl scan on→No default controller availablebtmgmt info→Index list with 0 itemshciconfig -ashowshci0, butbluetoothctldoesn’t see it- Error
org.bluez.Error.Busywhen trying to power on
Cause: The service orangepi3b-sprd-bluetooth.service runs hciattach_opi with the -n flag (no-detach), which holds the device and prevents BlueZ from registering the controller.
✅ Solution: Two Steps
Step 1: Install Missing Utilities
sudo apt update
sudo apt install -y rfkill bluez
rfkillis needed to unblock the adapter,bluezis the Bluetooth stack itself.
Step 2: Fix the Initialization Service
Option A: Quick Fix (Manual)
# 1. Stop everything
sudo systemctl stop orangepi3b-sprd-bluetooth
sudo systemctl stop bluetooth
sudo killall -9 hciattach_opi 2>/dev/null
sleep 2
# 2. Load drivers and unblock adapter
sudo modprobe -a sprdbt_tty sprdwl_ng
sudo rfkill unblock all
# 3. Run initialization WITHOUT -n flag (hciattach will detach automatically)
sudo /usr/bin/hciattach_opi -s 1500000 /dev/ttyBT0 sprd
# ← Process will complete in 2-3 seconds if chip responded
# 4. Start BlueZ - it will pick up the ready hci0
sudo systemctl start bluetooth
sleep 2
# 5. Verify
btmgmt info
# Expected: Index list with 1 item, hci0: Primary controller
sudo bluetoothctl power on
sudo bluetoothctl scan on
# Expected: Changing power on succeeded, device appears in scan
Option B: Permanent Fix (via systemd)
# 1. Open service for editing
sudo systemctl edit orangepi3b-sprd-bluetooth
# 2. Override ExecStart (remove -n):
[Service]
ExecStart=
ExecStart=/usr/bin/hciattach_opi -s 1500000 /dev/ttyBT0 sprd
# 3. Apply and restart
sudo systemctl daemon-reload
sudo systemctl restart orangepi3b-sprd-bluetooth
sudo systemctl restart bluetooth
# 4. Verify
btmgmt info
sudo bluetoothctl power on
sudo bluetoothctl scan on
💡 Why
-nbreaks things: Theno-detachflag keepshciattachrunning in the background and holding the UART. BlueZ can’t register the controller because the device is already busy.
🔧 If It Doesn’t Work: Diagnostics
# Check if kernel sees the chip
dmesg | grep -iE "ttyBT|sprd|uwe5622"
# Check if drivers are loaded
lsmod | grep -iE "sprd|bt"
# Check for blocks
rfkill list
# If Soft blocked: yes → sudo rfkill unblock bluetooth
# Check if bluetoothd is running with required flags
ps aux | grep bluetoothd
# For passive scanning (required for HA): needs --experimental
# Check device permissions
ls -l /dev/hci0 /dev/ttyBT0
# Should be: root:bluetooth, permissions 660
🐳 For Docker: Passing Through to Container
If you’re running Home Assistant or another app in Docker:
services:
home-assistant:
volumes:
- /run/dbus:/run/dbus:ro # ← Required for Bluetooth access
# Don't run bluetoothctl inside the container!
# Manage pairing on the host, the app will pick it up via D-Bus
⚠️ Don’t use
network_mode: hostjust for Bluetooth - it breaks network isolation. Mounting/run/dbusis enough.