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

BlueZ GATT服务器Characteristic无法读取值及通知实现求助

GATT服务器Characteristic读取失败及通知功能问题排查

问题描述

在树莓派3B上搭建GATT服务器时,遇到两个核心问题:

  1. TxCharacteristic类的ReadValue()方法完全未被调用,即便设置测试返回值也无任何响应,且确认几乎未修改之前可用的代码。
  2. BLE通知功能实现存在问题,无法正常向客户端推送数据。

相关代码片段

class TxCharacteristic(Characteristic):
    """
    Transmit characteristic, sends data to the client
    """
    TX_CHRC_UUID = '0x0002'

    def __init__(self, bus, index, service):
        Characteristic.__init__(
                self, bus, index,
                self.TX_CHRC_UUID,
                ['read', 'notify'],
                service)
        self.notifying = False
        self.value = ""

    def StartNotify(self):
        if self.notifying:
            print('Already notifying, nothing to do')
            return

        self.notifying = True

    def StopNotify(self):
        if not self.notifying:
            print('Not notifying, nothing to do')
            return
        self.notifying = False

    def ReadValue(self):
        print("Tx read: " + bytes(self.value).decode)
        self.value = Comms.TxRead(Comms)
        return self.value

读取失败的原因及修复方法

1. UUID格式不符合规范

BLE特征的UUID格式要求严格,'0x0002'这种带0x前缀的写法可能无法被BlueZ等BLE栈正确识别,导致客户端无法发现该特征,自然不会发起读请求。
修复:
使用完整的128位UUID(推荐,避免冲突),或者正确的16位UUID格式:

# 完整128位UUID(基于蓝牙BASE UUID)
TX_CHRC_UUID = '00000002-0000-1000-8000-00805f9b34fb'
# 或简化的16位写法(不带0x前缀)
# TX_CHRC_UUID = '0002'

2. ReadValue方法签名不匹配

多数BLE框架(如BlueZ的gatt-python实现)中,ReadValue方法需要接收options参数,若签名缺失,父类方法不会被正确覆盖,导致自定义逻辑不执行。
修复:
修正方法签名,并确保返回值为字节数组:

def ReadValue(self, options):
    # 修复打印语句的语法错误(decode需加括号,字符串转字节用encode)
    print(f"Tx read: {self.value}")
    # 修正Comms.TxRead调用(若TxRead是类方法,无需传Comms类作为参数)
    self.value = Comms.TxRead()
    # 返回字节数组,符合BLE数据格式要求
    return bytes(self.value, 'utf-8')

3. 附加检查项

  • 用树莓派的bluetoothctl工具验证GATT服务和特征是否正确注册:
    1. 执行bluetoothctl进入交互模式
    2. 输入menu gatt进入GATT菜单
    3. 输入list-attributes查看已注册的特征,确认目标特征的UUID和属性(read/notify)存在
  • 检查LightBlue客户端是否正确连接设备,尝试读取特征时查看客户端的错误提示。

BLE通知功能优化建议

当前的StartNotify和StopNotify仅修改了notifying标志,未实现实际的推送逻辑。通知功能需要主动向客户端发送数据,可通过线程循环实现:

import threading
import time

def StartNotify(self):
    if self.notifying:
        print('Already notifying, nothing to do')
        return
    self.notifying = True

    # 启动后台线程循环发送通知
    def notify_loop():
        while self.notifying:
            # 获取待推送的数据
            data = Comms.TxRead()
            if data:
                # 调用SendValue向客户端推送字节数据
                self.SendValue(bytes(data, 'utf-8'), {})
            # 控制推送间隔,可根据需求调整
            time.sleep(1)
    
    # 设置守护线程,避免程序退出时残留线程
    threading.Thread(target=notify_loop, daemon=True).start()

def StopNotify(self):
    if not self.notifying:
        print('Not notifying, nothing to do')
        return
    self.notifying = False

内容的提问来源于stack exchange,提问作者Auri M

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 08:09:24