You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 23:54:05