Bluetooth-Kommandozeilentool für FreeBSD auf Basis von blued (SSP-fähiges
Pairing) und virtual_oss (A2DP-Audio-Bridge). Testgetrieben entwickelt,
66 Tests grün, unittest (kein Zusatzpaket nötig).
btctl connect <adresse> macht für jedes Gerät:
- Pairing über
blued, falls noch nicht gepairt (SSP-fähig, im Gegensatz zuhcsecd). - ACL-Verbindungsaufbau über
hccontrol. - SDP-Profil-Erkennung über
sdpcontrol browse. - Nur wenn das Gerät ein Audio-Sink-Profil anbietet (A2DP/HSP/HFP,
erkennbar u.a. an Sennheiser HD 350BT), wird zusätzlich
virtual_ossgestartet, das eine/dev/dsp-Bridge zum Bluetooth-Audiokanal aufbaut. - Für alles andere (Maus, Tastatur, generisches HID/sonstiges Gerät) bleibt es bei Schritt 1+2 – kein virtual_oss-Prozess.
btctl/
models.py BluetoothDevice, DeviceKind, ConnectionState
process_utils.py gemeinsamer, mockbarer Wrapper um subprocess
hccontrol_client.py Scan/Connect/Status über `hccontrol`
sdp_client.py Profil-Erkennung über `sdpcontrol browse`
blued_client.py Pairing über blued (SSP)
virtual_oss_manager.py startet/stoppt virtual_oss pro Adresse
orchestrator.py verbindet alle Bausteine, enthält die
Headset-vs-Rest-Logik
controller.py GUI-unabhängige Geräteliste + Aktionen
cli.py `btctl scan|connect|disconnect|status`
gui.py Tkinter-Oberfläche (nutzt controller.py)
Jede Komponente kapselt genau ein externes Kommando und ist über
Dependency Injection im Orchestrator/Controller austauschbar/mockbar –
daher lassen sich alle 75 Tests ohne echte Bluetooth-Hardware, ohne
FreeBSD und ohne Display ausführen. Die GUI selbst enthält bewusst keine
eigene Bluetooth-Logik, sondern delegiert komplett an controller.py.
blued ist ein noch junges FreeBSD-Projekt ohne öffentlich stabil
dokumentierte Kommandozeilen-Syntax. blued_client.py nimmt aktuell an:
- Binary heißt
bluedctl - Subcommands:
scan,list,pair <adresse>,unpair <adresse> - Ausgabe tab-getrennt:
ADRESSE<TAB>NAME[<TAB>STATUS]
Vor dem ersten Einsatz bitte auf dem Zielsystem prüfen:
bluedctl --help # oder wie auch immer das CLI-Binary tatsächlich heißtFalls Name/Syntax abweichen, genügt eine Anpassung in blued_client.py
(Binary-Name ist sogar per Konstruktorparameter BluedClient(binary=...)
austauschbar) – der Rest des Programms bleibt unverändert, weil alles über
dieses eine Modul läuft.
bluedinstalliert und laufend (Ersatz fürhcsecd, SSP-fähig)sdpdlaufend (fürsdpcontrol browse)virtual_ossaus den ports mit Bluetooth/A2DP-Unterstützung gebaut (OptionBT_SPEAKER), Pfad standardmäßig/usr/local/sbin/virtual_oss. Die schlanke Base-System-Variante hat kein Bluetooth-Backend.- Bluetooth-Adapter mit funktionierendem
ubtN/ubtNhci(Realtek-Chips haben in der Praxis öfter funktioniert als manche Intel-Onboard-Adapter).
doas ./install.sh # oder: sudo ./install.shDas Skript (nur für FreeBSD, prüft uname -s):
- installiert
python3, das passendepyXY-tkinter(fürbtctl-gui),virtual_ossund – falls per pkg verfügbar –blued - legt ein eigenständiges venv unter
/usr/local/btctlan und installiertbtctldort hinein - verlinkt
btctlundbtctl-guinach/usr/local/bin
Fehlschläge einzelner pkg install-Schritte (z.B. weil blued noch nicht
gepackaged ist) brechen die Installation nicht ab, sondern geben eine
Warnung mit Hinweis auf den README-Abschnitt "Voraussetzungen" aus.
Anpassbar über Umgebungsvariablen: BTCTL_PREFIX (Standard
/usr/local/btctl), BTCTL_BIN_DIR (Standard /usr/local/bin),
BTCTL_PYTHON (Standard python3).
Deinstallieren mit doas ./uninstall.sh (entfernt nur, was install.sh
angelegt hat – installierte Pakete bleiben unangetastet).
python3 -m venv venv
source venv/bin/activate
pip install .Danach steht das Kommando btctl (und btctl-gui) im venv zur Verfügung.
Root-Rechte werden für hccontrol/virtual_oss typischerweise vorausgesetzt,
ähnlich wie bei pyfw.
btctl scan # sichtbare Geräte auflisten
btctl connect 00:16:94:14:13:AE # pairen (falls nötig) + verbinden;
# bei Headset automatisch virtual_oss
btctl status 00:16:94:14:13:AE # aktuellen Verbindungsstatus abfragen
btctl disconnect 00:16:94:14:13:AE # virtual_oss stoppen (falls aktiv)Oder als GUI, inspiriert vom GNOME-Settings-Bluetooth-Panel (Standard unter AlmaLinux/GNOME): zwei Listen "Meine Geräte" / "Verfügbare Geräte", Klick auf ein Gerät zeigt rechts eine Detailansicht mit Verbinden/Trennen/Vergessen (Unpair). Bluetooth-Aktionen laufen im Hintergrundthread, damit das Fenster nicht einfriert:
btctl-guitkinter muss dafür verfügbar sein (auf FreeBSD z.B. pkg install py311-tkinter,
je nach installierter Python-Version).
python3 -m unittest discover -s tests -vblued-CLI-Annahmen ungetestet gegen echte Hardware (s.o.) – erste Amtshandlung auf dem Zielsystem: Syntax verifizieren.- Keine automatische Geräteklassen-Erkennung vor der SDP-Abfrage (kein Class-of-Device-Parsing aus der Inquiry) – Klassifikation läuft ausschließlich über die SDP-Profile.
disconnectbeendet aktuell nur den virtual_oss-Prozess, keinen explizitenhccontrol-ACL-Disconnect (kann bei Bedarf ergänzt werden).- Kein systemweiter Dienst/rc.d-Skript – reines CLI-/GUI-Tool bisher.
- GUI wurde in dieser Umgebung nur syntaktisch geprüft (kein tkinter/Display vorhanden) – bitte auf deinem FreeBSD-System als erstes einmal öffnen und testen.
BSD 2-Clause, siehe LICENSE. Copyright (c) 2026 Robert Illner (Nihjo).
🤖 Dieses Projekt wurde mit Unterstützung von Claude (Anthropic) entwickelt.