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.0.tar.gz (59.4 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.0-py3-none-any.whl (33.2 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: bluetooth_autoconnect-1.1.0.tar.gz
  • Upload date:
  • Size: 59.4 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.0.tar.gz
Algorithm Hash digest
SHA256 d720b02c129afeb437d078d6fd105a9dce77d5cc78880473cd1a4631d97c56bb
MD5 c3373a0355b7de4c29844546ca09d6a7
BLAKE2b-256 a49c7e4145075123db5e2aacd224d92c2a1616df2a068fdc5155392b452ae308

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for bluetooth_autoconnect-1.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f565f853c699a5782f88bf74879c23a9915d872ea9bb2d0f2dc1eb2bb8ac2047
MD5 31ff08fc77f11f36e9e63596aa0d8dd8
BLAKE2b-256 5a3fc20abe86500a2d56aaa5f76bf396f4be01ca699bac55bad015d964559e5c

See more details on using hashes here.

Release history Release notifications | RSS feed

1.2.0

2 files

1.1.1

2 files

This release

1.1.0 This release

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