如何通过D-Bus API连接蓝牙Profile并获取可用RFCOMM套接字
报错原因
你遇到的org.bluez.Error.NotAvailable错误是因为未提前向BlueZ注册自定义UUID对应的Profile,BlueZ无法处理该UUID的连接请求,导致ConnectProfile调用失败后底层连接自动断开。你认为Device1.ConnectProfile对应Android的createRfcommSocketToServiceRecord的假设基本正确,仅需额外增加Profile注册步骤即可实现相同效果。
修正后的实现代码
#!/usr/bin/env python3 from pydbus import SystemBus from gi.repository import GLib import os import socket PROFILE = 'b079b640-35fe-11e5-a432-0002a5d5c51b' ADDR = 'AA:BB:CC:DD:EE:FF' active_sock = None # 实现BlueZ要求的Profile1接口 class CustomRFCOMMProfile: def Release(self): print("Profile已释放") def NewConnection(self, device_path, fd_obj, props): global active_sock # 从D-Bus参数中获取套接字文件描述符 rfcomm_fd = fd_obj.take() # 包装为标准Python socket对象,可直接使用原有读写逻辑 active_sock = socket.fromfd(rfcomm_fd, socket.AF_BLUETOOTH, socket.SOCK_STREAM, socket.BTPROTO_RFCOMM) print("连接建立成功,可调用active_sock.send()/recv()读写数据") # 示例:发送测试数据 active_sock.send(b"Hello from D-Bus BlueZ client") def RequestDisconnection(self, device_path): global active_sock if active_sock: active_sock.close() active_sock = None print("连接已断开") def new_style(): bus = SystemBus() # 获取BlueZ Profile管理器 profile_manager = bus.get('org.bluez', '/org/bluez') # 实例化自定义Profile对象 rfcomm_profile = CustomRFCOMMProfile() # 把Profile对象暴露到D-Bus总线 bus.publish('org.bluez.Profile1', rfcomm_profile, ('/org/bluez/custom_rfcomm_profile', rfcomm_profile)) # 向BlueZ注册Profile profile_manager.RegisterProfile( '/org/bluez/custom_rfcomm_profile', PROFILE, { "Name": GLib.Variant('s', "Custom RFCOMM Client"), "Role": GLib.Variant('s', "client"), "AutoConnect": GLib.Variant('b', False) } ) # 获取目标蓝牙设备对象 dev_object_path = '/org/bluez/hci0/dev_' + ADDR.replace(':', '_') bt_device = bus.get('org.bluez', dev_object_path) def connect_task(): print("发起连接请求...") try: bt_device.ConnectProfile(PROFILE) except Exception as e: # 该异常不代表连接最终失败,连接成功会触发NewConnection回调 print(f"ConnectProfile调用返回: {str(e)}") # 延迟发起连接,确保Profile注册完成 GLib.timeout_add(250, connect_task) # 启动GLib主循环接收D-Bus事件 GLib.MainLoop().run() if __name__ == "__main__": new_style()
注意事项
- 运行脚本需要root权限,或者当前用户属于
bluetooth用户组 - 需提前完成两台蓝牙设备的配对,未配对的设备需要先调用
bt_device.Pair()方法完成配对再发起连接 - 拿到的
socket对象和传统bluetooth库返回的RFCOMM套接字用法完全一致,可直接复用原有业务逻辑
补充问题回复
- 该需求完全可以通过BlueZ D-Bus实现,传统的bluetooth库API已经被BlueZ官方标记为弃用,后续新版本会逐步移除支持,推荐使用D-Bus方案
- 完整实现仅比Android多了Profile注册的3步逻辑,整体简洁度和Android方案接近
- 不需要在属性变更回调里手动创建套接字,BlueZ会直接把已经建立好的套接字通过
NewConnection回调返回,完全符合你的预期
内容的提问来源于stack exchange,提问作者eehouse
相关产品推荐
相关产品推荐

