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

使用flutter_reactive_ble读取BLE设备特征值失败求助

使用flutter_reactive_ble读取BLE设备时间的问题与解决方案

问题描述

在使用flutter_reactive_ble包读取低功耗蓝牙设备特征值时,触发以下GATT异常:

[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: Exception: GenericFailure(code: CharacteristicValueUpdateError.unknown, message: "GATT exception from MAC address FF:24:01:06:20:E4, with type BleGattOperation{description='CHARACTERISTIC_READ'}")

当前已实现的可正常运行的代码:

1. 扫描设备

getDevice() {
  Uuid u1 = Uuid.parse('00001800-0000-1000-8000-00805f9b34fb');
  Uuid u2 = Uuid.parse('00001801-0000-1000-8000-00805f9b34fb');
  Uuid u3 = Uuid.parse('0000fff0-0000-1000-8000-00805f9b34fb');

  flutterReactiveBle.scanForDevices(withServices: [u1, u2, u3], scanMode: ScanMode.lowLatency).listen((device) {
    setState(() {
      name = device.name;
      id = device.id;
    });
  });
}

2. 连接设备

connectToDevice() {
  Uuid ser = Uuid.parse('0000fff0-0000-1000-8000-00805f9b34fb');
  Uuid cha = Uuid.parse('00000001-0000-1000-8000-00805f9b34fb');

  flutterReactiveBle.connectToDevice(
    id: id,
    servicesWithCharacteristicsToDiscover: {ser: [cha]},
    connectionTimeout: const Duration(seconds: 10),
  ).listen((connectionState) {
    setState(() {
      able = connectionState.connectionState.name;
    });
  }); 
}

3. 报错的读取代码

尝试读取设备时间时触发异常:

readFromDevice() async {
  Uuid ser = Uuid.parse('0000fff0-0000-1000-8000-00805f9b34fb');
  Uuid cha = Uuid.parse('0000fff1-0000-1000-8000-00805f9b34fb');
  
  final characteristic = QualifiedCharacteristic(serviceId: ser, characteristicId: cha, deviceId: id);

  final response = await flutterReactiveBle.readCharacteristic(characteristic).then((value) {
    print(value.toString());
  });
  
  print(response.toString());
  
}

设备文档说明:

  • Characteristic UUID:0xFFF2(属性:write,APP向设备发送指令)
  • Characteristic UUID:0xFFF1(属性:Notify,设备向APP推送数据)
  • 获取仪表时间需发送指令:0x01

解决方案

错误核心原因

你试图用readCharacteristic读取属性为Notify的0xFFF1特征,但Notify类型的特征不支持主动读取操作,只能通过订阅监听设备推送的数据。同时,获取时间的逻辑是先向0xFFF2写入指令,再通过0xFFF1接收返回结果。

修正后的代码实现

1. 更新连接时的特征发现

连接时需同时发现0xFFF1(Notify)和0xFFF2(Write)两个特征:

connectToDevice() {
  Uuid ser = Uuid.parse('0000fff0-0000-1000-8000-00805f9b34fb');
  Uuid chaNotify = Uuid.parse('0000fff1-0000-1000-8000-00805f9b34fb');
  Uuid chaWrite = Uuid.parse('0000fff2-0000-1000-8000-00805f9b34fb');

  flutterReactiveBle.connectToDevice(
    id: id,
    servicesWithCharacteristicsToDiscover: {ser: [chaNotify, chaWrite]},
    connectionTimeout: const Duration(seconds: 10),
  ).listen((connectionState) {
    setState(() {
      able = connectionState.connectionState.name;
    });
  }); 
}

2. 订阅Notify特征接收设备数据

在获取时间前,先监听0xFFF1的推送事件:

StreamSubscription? _timeNotifySubscription;

void startListeningToMeterTime() {
  Uuid ser = Uuid.parse('0000fff0-0000-1000-8000-00805f9b34fb');
  Uuid chaNotify = Uuid.parse('0000fff1-0000-1000-8000-00805f9b34fb');
  
  final characteristic = QualifiedCharacteristic(
    serviceId: ser, 
    characteristicId: chaNotify, 
    deviceId: id
  );

  _timeNotifySubscription = flutterReactiveBle.subscribeToCharacteristic(characteristic)
      .listen((data) {
        // 根据设备协议解析Uint8List格式的时间数据
        print('设备返回时间数据: $data');
        // 示例解析(需按实际协议调整)
        // String formattedTime = _parseTimeFromBytes(data);
        // setState(() { meterTime = formattedTime; });
      }, onError: (error) {
        print('监听时间推送失败: $error');
      });
}

3. 写入指令触发设备返回时间

向0xFFF2特征发送0x01指令:

Future<void> sendGetMeterTimeCommand() async {
  Uuid ser = Uuid.parse('0000fff0-0000-1000-8000-00805f9b34fb');
  Uuid chaWrite = Uuid.parse('0000fff2-0000-1000-8000-00805f9b34fb');
  
  final characteristic = QualifiedCharacteristic(
    serviceId: ser, 
    characteristicId: chaWrite, 
    deviceId: id
  );

  try {
    await flutterReactiveBle.writeCharacteristicWithoutResponse(
      characteristic, 
      value: Uint8List.fromList([0x01])
    );
    print('已发送获取时间指令');
  } catch (e) {
    print('写入指令失败: $e');
  }
}

4. 清理资源

在页面销毁或断开连接时取消订阅,避免内存泄漏:

@override
void dispose() {
  _timeNotifySubscription?.cancel();
  super.dispose();
}

注意事项

  • 必须确保设备处于connected状态后,再执行订阅和写入操作。
  • 数据解析需严格遵循设备提供的协议文档,不同设备的字节格式、编码方式可能不同。
  • 写入指令时,根据设备要求选择writeCharacteristic(带响应)或writeCharacteristicWithoutResponse(无响应)。

内容的提问来源于stack exchange,提问作者Serenity Emmanuel

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 00:54:52