Skip to main content

bluetooth-autoconnect

bluetooth-autoconnect

Automatically reconnect paired Bluetooth devices on Linux — no desktop environment required.
Event-driven, systemd-native, zero-configuration.

PyPI Python Tests Lint Release License

InstallUsageConfigHow it worksTroubleshootingContributing


Why bluetooth-autoconnect?

Most Linux Bluetooth tools reconnect devices only when a desktop session is available. bluetooth-autoconnect is different:

  • Runs as a system service — reconnects at boot, before any user logs in
  • Talks to BlueZ directly over D-Bus — no shelling out to bluetoothctl, no polling
  • Handles the "silent return" gap — devices that come back into range without firing a D-Bus event are caught by a periodic background scanner
  • Backs off per device — a flaky headset won't block your keyboard from reconnecting
  • Works headlessly on servers, Raspberry Pi, embedded Linux, kiosk machines, and normal desktops alike

✨ Feature Highlights

Feature Details
Instant event-driven reconnect Subscribes to BlueZ D-Bus signals; reacts within milliseconds of adapter power-on, device appearance, or disconnect
Periodic background scan Wakes every 30 s (configurable) to catch devices that return silently — fixes the most common reconnect gap
Per-device exponential backoff 1 min → 2 → 4 → 8 → 16 min cap; each MAC is tracked independently
Multi-adapter support Scans all powered adapters simultaneously
Safe by default Only ever connects Paired: yes + Trusted: yes devices; no automatic pairing
systemd integration System-wide and per-user service units; structured journal logging
Health check bluetooth-autoconnect doctor — instant PASS/FAIL diagnostics
Zero runtime dependencies Pure Python D-Bus client; no native extensions required

📦 Installation

Choose the method that fits your workflow.

Option 1 — PyPI (quickest)

pip install bluetooth-autoconnect

Requires Python 3.10+. For journal integration install the optional extra:

pip install "bluetooth-autoconnect[journal]"

Then install the systemd service manually:

# System-wide (runs at boot, recommended)
sudo install -Dm644 /path/to/systemd/bluetooth-autoconnect.service \
    /usr/lib/systemd/system/bluetooth-autoconnect.service
sudo systemctl daemon-reload
sudo systemctl enable --now bluetooth-autoconnect

Option 2 — Automatic installer (recommended for full setup)

Clones the repo, installs deps, creates an isolated virtualenv, wires up systemd, and starts the service — all in one step:

git clone https://github.com/Zero-day-Exploit-np/bluetooth-autoconnect.git
cd bluetooth-autoconnect
sudo bash scripts/install.sh

Done. The service is running.

Option 3 — Native distro packages

For proper package-manager-managed installs with dependency tracking:

Distro family Build guide
Debian / Ubuntu / Kali / Mint packaging/debian/README.md
Arch Linux / Manjaro packaging/arch/README.md
Fedora / openSUSE packaging/fedora/README.md

🖥️ Supported Distributions

Distribution Status Package manager
Ubuntu 22.04 / 24.04 ✅ Tested apt
Debian 12 (Bookworm) ✅ Tested apt
Kali Linux (rolling) ✅ Tested apt
Linux Mint 21+ ✅ Tested apt
Fedora 39 / 40 ✅ Tested dnf
Arch Linux ✅ Tested pacman
Manjaro ✅ Tested pacman
openSUSE Tumbleweed ✅ Tested zypper

Requirements: Python 3.10+, BlueZ ≥ 5.x, systemd, D-Bus.


🚀 Usage

bluetooth-autoconnect [--daemon] [--debug] [--rescan-interval SECONDS]
                      [--max-attempts N] [--max-concurrency N] [--version]
                      [doctor]

Commands

Command Behaviour
bluetooth-autoconnect One-shot scan — connect all paired+trusted devices once, then exit
bluetooth-autoconnect --daemon Run continuously; reconnects via D-Bus events and periodic scans
bluetooth-autoconnect doctor Run health checks; print PASS/FAIL for each system component
bluetooth-autoconnect --version Print installed version and exit

Flags

Flag Default Description
--debug off Structured DEBUG-level logging with per-device fields
--max-attempts N 5 Connect attempts per device before giving up
--max-concurrency N 5 Maximum simultaneous connect attempts
--rescan-interval SECONDS 30 Periodic background scan interval. 0 = disable

Exit codes

Code Meaning
0 All eligible devices connected (or none were needed)
1 At least one eligible device failed to connect
2 Fatal D-Bus / BlueZ startup error
130 Interrupted by Ctrl-C

Examples

# Connect everything right now (one-shot)
bluetooth-autoconnect

# Run as a daemon — the same mode the systemd service uses
bluetooth-autoconnect --daemon

# Debug a device that isn't reconnecting
bluetooth-autoconnect --daemon --debug

# Scan more aggressively (every 10 s instead of every 30 s)
bluetooth-autoconnect --daemon --rescan-interval 10

# Disable periodic scanning; rely only on D-Bus events
bluetooth-autoconnect --daemon --rescan-interval 0

# Allow more retries for a flaky headset
bluetooth-autoconnect --max-attempts 10

# Check system health before troubleshooting
bluetooth-autoconnect doctor

⚙️ Configuration

The config file lives at /etc/bluetooth-autoconnect/config.yaml.
It is never overwritten by updates.

retry:
  max_attempts: 5       # connect attempts per device before giving up
  base_delay: 1.0       # seconds before first retry
  max_delay: 60.0       # cap on per-attempt delay
  multiplier: 2.0       # exponential backoff factor

daemon:
  rescan_interval_seconds: 30   # periodic scan interval (0 = disabled)
  max_concurrency: 5            # simultaneous connect attempts

logging:
  level: INFO           # change to DEBUG for verbose output

# Per-device priority (higher value = connect first)
# device_priorities:
#   AA:BB:CC:DD:EE:FF: 250

# Prevent specific devices from ever auto-connecting
# blacklist:
#   - AA:BB:CC:DD:EE:FF

🔄 Automatic Reconnect Behavior

bluetooth-autoconnect uses two complementary mechanisms.

1 — Event-driven reconnect (instant)

The daemon subscribes to BlueZ D-Bus signals and fires an immediate connect attempt when any of these events arrive:

D-Bus signal Trigger condition
Adapter.Powered = true Bluetooth adapter switched on
InterfacesAdded (Device) Known device object appeared on the bus
Device.Connected = false A connected device dropped off
Device.RSSI updated Device advertisement received — it's back in range
Device.Trusted = true Device was just marked trusted
Device.Paired = true Device was just paired

2 — Periodic background scan (the silent-return fix)

Some devices return to range without advertising any D-Bus event — slowly waking headphones, congested RF environments, BLE devices with long advertisement intervals. The event-driven path never fires for these.

The periodic scanner wakes every rescan_interval_seconds (default 30 s), enumerates all disconnected trusted devices, skips any still inside their backoff window, and retries the rest.

t=0s     Device disconnects → immediate attempt (fails: page-timeout)
t=1s     Backoff: wait 60 s
t=61s    Periodic scan → device unreachable → fail (backoff: 120 s)
t=181s   Periodic scan → device unreachable → fail (backoff: 240 s)
  ···
t=Xm     Device returns silently — no D-Bus event
t=Xm+30s Periodic scan → reconnect succeeds → backoff cleared ✓

Per-device backoff schedule

Each MAC address tracks its own backoff independently:

Consecutive failures Cooldown before next attempt
1 1 minute
2 2 minutes
3 4 minutes
4 8 minutes
5+ 16 minutes (hard cap: 30 minutes)

Backoff resets immediately on:

  • Successful reconnect
  • Device.RSSI signal (device is in range)
  • Device.Connected = true (device connected on its own)

Trigger an immediate rescan at any time

sudo systemctl kill -s SIGHUP bluetooth-autoconnect

🔧 How Device Selection Works

A device is auto-connected only when BlueZ reports both:

  • Paired: yes — you completed the pairing handshake, and
  • Trusted: yes — you (or BlueZ) marked the device as trusted

Unpaired devices, paired-but-untrusted devices, and unknown nearby devices are silently skipped and logged at DEBUG level. This tool never pairs or trusts devices on its own.

To trust an already-paired device:

bluetoothctl trust AA:BB:CC:DD:EE:FF

🛠️ Service Management

Two systemd units ship with the project:

Unit Scope Starts at
bluetooth-autoconnect.service System-wide (runs as root) Boot
bluetooth-autoconnect.service (user) Per-user session Login

System-wide service

# View status
sudo systemctl status bluetooth-autoconnect

# Control
sudo systemctl start   bluetooth-autoconnect
sudo systemctl stop    bluetooth-autoconnect
sudo systemctl restart bluetooth-autoconnect

# Enable / disable at boot
sudo systemctl enable  bluetooth-autoconnect
sudo systemctl disable bluetooth-autoconnect

# Stream live logs
journalctl -u bluetooth-autoconnect -f

# Trigger an immediate full rescan without restarting
sudo systemctl kill -s SIGHUP bluetooth-autoconnect

Per-user service

# Enable at login
systemctl --user enable --now bluetooth-autoconnect

# Stream live logs
journalctl --user -u bluetooth-autoconnect -f

🔍 Diagnostics

bluetooth-autoconnect doctor checks every prerequisite and prints a clear report:

bluetooth-autoconnect doctor

  [PASS] bluetooth.service — active
  [PASS] D-Bus system bus  — socket reachable
  [PASS] BlueZ available   — org.bluez found
  [PASS] Adapter hci0      — powered, address=AA:BB:CC:DD:EE:FF
  [PASS] Trusted device: JBL Speaker — connected
  [WARN] Trusted device: Sony WH-1000XM5 — not connected (mac=11:22:33:44:55:66)

Exit code 0 = all checks passed. Exit code 1 = at least one hard failure.


🔄 Update

cd bluetooth-autoconnect
sudo bash scripts/update.sh

Pulls the latest source, upgrades the package, refreshes systemd units, and restarts the service.


🗑️ Uninstall

cd bluetooth-autoconnect
sudo bash scripts/uninstall.sh

Removes the service, binary symlink, and virtualenv. Optionally removes the configuration directory. Your Bluetooth pairing data in BlueZ is never touched.


❓ Troubleshooting

org.bluez is not available on the system bus

BlueZ is not running. Start it:

sudo systemctl enable --now bluetooth
sudo systemctl status bluetooth

Devices are found but never connect

  1. Confirm the device is paired and trusted:
    bluetoothctl info AA:BB:CC:DD:EE:FF
    # Must show:  Paired: yes   Trusted: yes
    
  2. If Trusted: no: bluetoothctl trust AA:BB:CC:DD:EE:FF
  3. Run with --debug to see per-attempt structured logs

Permission denied on Connect()

The system-wide service has full BlueZ access. The per-user service may need your user in the bluetooth group:

sudo usermod -aG bluetooth "$USER"
# Log out and back in

Daemon doesn't react when a device comes back into range

Enable the periodic scanner (it's on by default). If you've disabled it, re-enable it:

bluetooth-autoconnect --daemon --rescan-interval 30

Or in the config file:

daemon:
  rescan_interval_seconds: 30

For the full guide, see docs/TROUBLESHOOTING.md.


👩‍💻 Development

git clone https://github.com/Zero-day-Exploit-np/bluetooth-autoconnect.git
cd bluetooth-autoconnect
make venv
source .venv/bin/activate
Task Command
Run test suite (coverage ≥ 90%) make test
Lint make lint
Auto-format make format
Type-check make typecheck
Build wheel make build

Project layout

src/bluetooth_autoconnect/
├── cli.py              argument parsing and entry point
├── connector.py        retry / backoff / concurrency
├── daemon.py           event loop, periodic scan, signal handling
├── dbus_client.py      BlueZ D-Bus wrapper (dbus-next)
├── doctor.py           health-check diagnostics
├── exceptions.py       exception hierarchy
├── logging_setup.py    stdout + journal logging
└── models.py           Adapter / Device dataclasses

tests/                  pytest suite — no real D-Bus required
systemd/                system + user service units
scripts/                install.sh   uninstall.sh   update.sh
packaging/              debian/   arch/   fedora/
docs/                   INSTALL.md   TROUBLESHOOTING.md   FAQ.md

🤝 Contributing

Contributions are welcome. Please:

  1. Fork the repository
  2. Create a feature branch — git checkout -b feat/my-feature
  3. Add tests for new behaviour
  4. Verify make test lint typecheck all pass
  5. Open a pull request with a clear description

For bug reports, use the issue tracker and include the output of bluetooth-autoconnect doctor and journalctl -u bluetooth-autoconnect --since "1 hour ago".


📄 License

MIT — see LICENSE.


👤 Author

Bikram Kumar Das · github.com/Zero-day-Exploit-np


If bluetooth-autoconnect saves you frustration, consider giving it a ⭐ on GitHub.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

bluetooth_autoconnect-1.1.1.tar.gz (59.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

bluetooth_autoconnect-1.1.1-py3-none-any.whl (33.3 kB view details)

Uploaded Python 3

File details

Details for the file bluetooth_autoconnect-1.1.1.tar.gz.

File metadata

  • Download URL: bluetooth_autoconnect-1.1.1.tar.gz
  • Upload date:
  • Size: 59.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.14.6

File hashes

Hashes for bluetooth_autoconnect-1.1.1.tar.gz
Algorithm Hash digest
SHA256 d1455610423846162b1f185e1680fad38e0bf7cbe5aa68919022700dd6b8b4c3
MD5 109bc4d64f424385766b506d45672466
BLAKE2b-256 edc80a7e9da2ffd4e5bf3079f4283e49920722aa6c72fc54aefd6895f0dbc27a

See more details on using hashes here.

File details

Details for the file bluetooth_autoconnect-1.1.1-py3-none-any.whl.

File metadata

File hashes

Hashes for bluetooth_autoconnect-1.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 b0ee0247919ebe50949578b775afda85690f46998b434dc0cf1ab3b8d1357aa6
MD5 f1ef64a23cd246618bb87f4fea15984b
BLAKE2b-256 1daa6997e566a3712213535fb194dcdc4cae0f455f5995103e4745321cb95974

See more details on using hashes here.

Release history Release notifications | RSS feed

1.2.0

2 files

This release

1.1.1 This release

2 files

1.1.0

2 files

1.0.2

2 files

1.0.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page