蓝牙应用层dbus接口
文章目录
- 1. 核心概念:什么是 DBus?
- 2. 蓝牙架构中的 DBus 层
- 3. DBus 核心概念(在蓝牙上下文中)
- a) 对象路径(Object Path)
- b) 接口(Interface)
- c) 方法、信号和属性
- 4. 实践:使用 `dbus-send` 和 `gdbus` 进行命令行操作
- 示例 1:获取适配器属性
- 示例 2:开始扫描设备
- 示例 3:停止扫描
- 示例 4:配对设备 (需要替换成你的设备地址)
- 5. 编程示例:使用 Python 和 `dbus-python`
- 6. 官方 API 文档
- 学习路径建议
1. 核心概念:什么是 DBus?
DBus(Desktop Bus) 是一个进程间通信(IPC)的系统,主要用于 Linux 桌面环境(如 GNOME, KDE)。它允许不同的应用程序相互通信、共享信息和调用彼此的功能。
- 总线(Bus):
- 系统总线(System Bus):用于系统级服务,如蓝牙、网络管理器、打印机服务。所有用户和应用程序都可以连接。
- 会话总线(Session Bus):用于单个用户的桌面会话,实现同一用户下不同应用程序的通信。
蓝牙服务在 Linux 上(通常由 bluez 实现)通过系统总线暴露其 API,任何想要使用蓝牙功能的应用程序都必须通过 DBus 与 bluez 通信。
2. 蓝牙架构中的 DBus 层
在典型的 Linux 蓝牙栈中:
+-----------------------------+
| 你的应用程序 (Python, C++, Go, 等) |
+-----------------------------+| (使用 DBus 绑定/库,如 dbus-python, GDBus, sd-bus)
+-----------------------------+
| DBus 总线 |
+-----------------------------+| (使用 DBus 协议)
+-----------------------------+
| BlueZ 守护进程 (bluetoothd) |
+-----------------------------+| (使用蓝牙协议栈,如 L2CAP, RFCOMM, HCI)
+-----------------------------+
| 蓝牙硬件控制器 |
+-----------------------------+
- BlueZ: 是 Linux 官方的蓝牙协议栈。它的核心守护进程
bluetoothd在后台运行,并管理所有蓝牙操作。 - DBus 的角色:
bluetoothd将其所有功能(如发现设备、配对、连接等)作为一系列 DBus 对象 暴露在系统总线上。你的应用程序通过向这些对象发送 方法调用、监听 信号 和读取 属性 来控制蓝牙。
3. DBus 核心概念(在蓝牙上下文中)
要理解蓝牙 DBus API,你必须掌握三个核心概念:
a) 对象路径(Object Path)
类似于文件系统中的路径,它唯一标识一个 DBus 对象。BlueZ 为每个管理的实体都创建一个对象路径。
- 适配器:
/org/bluez/hci0(第一个蓝牙适配器),/org/bluez/hci1(第二个) - 发现的设备:
/org/bluez/hci0/dev_XX_XX_XX_XX_XX_XX(其中XX_...是设备的 MAC 地址) - GATT 服务:
/org/bluez/hci0/dev_XX_XX_XX_XX_XX_XX/serviceXXcharYY
b) 接口(Interface)
接口定义了一组相关的方法、信号和属性。一个 DBus 对象可以实现多个接口。BlueZ 为不同类型的对象定义了不同的接口。
- 适配器接口:
org.bluez.Adapter1 - 设备接口:
org.bluez.Device1 - GATT 服务接口:
org.bluez.GattService1 - GATT 特征接口:
org.bluez.GattCharacteristic1 - 媒体控制接口:
org.bluez.MediaControl1等等。
c) 方法、信号和属性
- 方法(Methods): 你可以调用的函数。例如:
Adapter1.StartDiscovery(),Device1.Connect()。 - 信号(Signals): 当某些事件发生时,BlueZ 发出的异步通知。例如:当发现新设备时,会发出
org.bluez.Adapter1.InterfacesAdded信号。 - 属性(Properties): 描述对象状态的键值对。例如:
Device1.Address(MAC地址),Device1.Connected(布尔值,表示连接状态)。
4. 实践:使用 dbus-send 和 gdbus 进行命令行操作
在学习编程之前,先用命令行工具熟悉 API 是非常有效的方法。
示例 1:获取适配器属性
# 使用 gdbus (更现代,推荐)
gdbus introspect --system --dest org.bluez --object-path /org/bluez/hci0# 或者使用 dbus-send (经典)
dbus-send --system --print-reply --dest=org.bluez /org/bluez/hci0 org.freedesktop.DBus.Properties.GetAll string:"org.bluez.Adapter1"
# gdbus introspect --system --dest org.bluez --object-path /org/bluez/hci0
node /org/bluez/hci0 {interface org.freedesktop.DBus.Introspectable {methods:Introspect(out s xml);signals:properties:};interface org.bluez.Adapter1 {methods:StartDiscovery();SetDiscoveryFilter(in a{sv} properties);StopDiscovery();RemoveDevice(in o device);GetDiscoveryFilters(out as filters);signals:properties:readonly s Address = '10:A5:62:0B:E6:EB';readonly s AddressType = 'public';readonly s Name = 'BlueZ 5.64';readwrite s Alias = 'Mower_X4_187358';readonly u Class = 0;readwrite b Powered = true;readwrite b Discoverable = true;readwrite u DiscoverableTimeout = 180;readwrite b Pairable = false;readwrite u PairableTimeout = 0;readonly b Discovering = false;readonly as UUIDs = ['00001801-0000-1000-8000-00805f9b34fb', '00001800-0000-1000-8000-00805f9b34fb', '00001200-0000-1000-8000-00805f9b34fb', '6e400001-b5a3-f393-e0a9-e50e24dcca91', '0000180a-0000-1000-8000-00805f9b34fb'];readonly s Modalias = 'usb:v1D6Bp0246d0540';readonly as Roles = ['central', 'peripheral'];readonly as ExperimentalFeatures;};interface org.freedesktop.DBus.Properties {methods:Get(in s interface,in s name,out v value);Set(in s interface,in s name,in v value);GetAll(in s interface,out a{sv} properties);signals:PropertiesChanged(s interface,a{sv} changed_properties,as invalidated_properties);properties:};interface org.bluez.GattManager1 {methods:RegisterApplication(in o application,in a{sv} options);UnregisterApplication(in o application);signals:properties:};interface org.bluez.LEAdvertisingManager1 {methods:RegisterAdvertisement(in o advertisement,in a{sv} options);UnregisterAdvertisement(in o service);signals:properties:readonly y ActiveInstances = 0x01;readonly y SupportedInstances = 0x04;readonly as SupportedIncludes = ['appearance', 'local-name'];readonly as SupportedSecondaryChannels;};
};
示例 2:开始扫描设备
# 使用 gdbus 调用 StartDiscovery 方法
gdbus call --system --dest org.bluez --object-path /org/bluez/hci0 --method org.bluez.Adapter1.StartDiscovery# 使用 dbus-send
dbus-send --system --print-reply --dest=org.bluez /org/bluez/hci0 org.bluez.Adapter1.StartDiscovery
示例 3:停止扫描
gdbus call --system --dest org.bluez --object-path /org/bluez/hci0 --method org.bluez.Adapter1.StopDiscovery
示例 4:配对设备 (需要替换成你的设备地址)
# 首先获取设备的对象路径,比如 /org/bluez/hci0/dev_AA_BB_CC_DD_EE_FF
gdbus call --system --dest org.bluez --object-path /org/bluez/hci0/dev_AA_BB_CC_DD_EE_FF --method org.bluez.Device1.Pair
5. 编程示例:使用 Python 和 dbus-python
以下是一个简单的 Python 脚本,演示了如何发现蓝牙设备。
注意: dbus-python 是一个较旧的库,但对于学习来说很简单。在生产环境中,你可能需要考虑 pydbus 或 GDBus 的 Python 绑定。
#!/usr/bin/env python3
import dbus
import dbus.mainloop.glib
from gi.repository import GLib# 使用 GLib 主循环来处理异步信号
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)# 连接到系统总线
bus = dbus.SystemBus()# 获取 BlueZ 的根对象 (ObjectManager)
bluez_root = bus.get_object('org.bluez', '/')
bluez_interface = dbus.Interface(bluez_root, 'org.freedesktop.DBus.ObjectManager')def interfaces_added_handler(object_path, interfaces):"""处理新接口添加的信号(例如发现新设备)"""device_interface = interfaces.get('org.bluez.Device1')if device_interface:address = device_interface.get('Address')name = device_interface.get('Name', 'Unknown')print(f"发现新设备: {name} ({address}) 路径: {object_path}")def properties_changed_handler(interface, changed_properties, invalidated_properties, object_path):"""处理属性变化的信号"""if interface == 'org.bluez.Device1':if 'RSSI' in changed_properties:rssi = changed_properties['RSSI']print(f"设备 {object_path} RSSI 更新: {rssi}")# 监听 InterfacesAdded 信号
bus.add_signal_receiver(interfaces_added_handler,signal_name='InterfacesAdded',dbus_interface='org.freedesktop.DBus.ObjectManager',path_keyword='object_path')# 监听 PropertiesChanged 信号
bus.add_signal_receiver(properties_changed_handler,signal_name='PropertiesChanged',path_namespace='/org/bluez') # 监听所有 /org/bluez 下的路径# 获取初始已存在的设备
managed_objects = bluez_interface.GetManagedObjects()
for object_path, interfaces in managed_objects.items():interfaces_added_handler(object_path, interfaces)# 开始发现
adapter_path = '/org/bluez/hci0' # 根据你的系统调整
adapter_object = bus.get_object('org.bluez', adapter_path)
adapter_interface = dbus.Interface(adapter_object, 'org.bluez.Adapter1')
adapter_interface.StartDiscovery()print("开始扫描... 按 Ctrl+C 停止")try:# 启动主循环来等待信号loop = GLib.MainLoop()loop.run()
except KeyboardInterrupt:print("\n停止扫描...")adapter_interface.StopDiscovery()loop.quit()
6. 官方 API 文档
学习 DBus 蓝牙最重要的资源是 BlueZ 官方文档。
- BlueZ D-Bus API 文档: https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc
- 这里有你需要的所有接口定义:
adapter-api.txt,device-api.txt,gatt-api.txt等。务必仔细阅读。
- 这里有你需要的所有接口定义:
学习路径建议
- 从命令行开始: 使用
gdbus和dbus-send手动调用方法,理解对象路径和接口。 - 阅读官方文档: 查阅
adapter-api.txt和device-api.txt,了解可用的方法、属性和信号。 - 写简单脚本: 用 Python 实现设备发现、配对和连接。
- 探索高级功能: 尝试 GATT(低功耗蓝牙)客户端/服务器操作,或者音频控制(A2DP, HFP)。
- 使用现代库: 当你熟悉概念后,转向更现代、更易用的库,如 Python 的
pydbus。
DBus 层的蓝牙学习曲线可能有些陡峭,但一旦掌握,你将拥有对 Linux 系统蓝牙功能的完全控制权。祝你学习顺利!
