Flutter中flutter_reactive_ble读取BLE设备血压数据的解析问题
解析BLE血压测量特征数据获取血压与心率
问题描述
我使用flutter_reactive_ble包编写代码,尝试从BLE设备读取收缩压、舒张压(单位mmHg)及心率(单位bpm),但不知如何解析数据。控制台输出如下:
D/BluetoothGatt(21288): setCharacteristicNotification() - uuid: 00002a35-0000-1000-8000-00805f9b34fb enable: true
I/flutter (21288): Received raw data for blood pressure measurement: [222, 136, 244, 32, 243, 255, 7, 228, 7, 1, 19, 22, 55, 0, 188, 242, 1, 68, 1]
用户的Flutter代码如下:
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('BLE Scanner'), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ ElevatedButton( onPressed: _scanForDevices, child: Text('Scan for Devices'), ), SizedBox(height: 20), Text('Discovered Devices:'), Expanded( child: ListView.builder( itemCount: devices.length, itemBuilder: (context, index) { final device = devices[index]; return ListTile( title: Text(device.name ?? 'Unknown'), subtitle: Text(device.id), onTap: () { _connectToDevice(device.id); _subscribeToBloodPressureMeasurement(device.id); }, ); }, ), ), ], ), ), ); } void _scanForDevices() { flutterReactiveBle.scanForDevices( withServices: [], scanMode: ScanMode.lowLatency, ).listen( (device) { final existingDeviceIndex = devices.indexWhere((d) => d.id == device.id); if (existingDeviceIndex != -1) { setState(() { devices[existingDeviceIndex] = device; }); } else { setState(() { devices.add(device); }); } }, onError: (error) { print('Error: $error'); }, ); } void _connectToDevice(String deviceId) { flutterReactiveBle .connectToDevice( id: deviceId, servicesWithCharacteristicsToDiscover: { Uuid.parse('00001810-0000-1000-8000-00805f9b34fb'): [ // 血压测量特征 Uuid.parse('00002a35-0000-1000-8000-00805f9b34fb'), // 血压特征 Uuid.parse('00002a49-0000-1000-8000-00805f9b34fb'), ], }, connectionTimeout: const Duration(seconds: 2), ) .listen( (connectionState) { // 处理连接状态更新 if (connectionState == DeviceConnectionState.connected) { print("Connected successfully to device: $deviceId"); _subscribeToBloodPressureMeasurement(deviceId); } }, onError: (error) { print('Error connecting to device: $error'); // 处理连接错误 }, ); } void _subscribeToBloodPressureMeasurement(String deviceId) { final bloodPressureCharacteristic = QualifiedCharacteristic( characteristicId: Uuid.parse('00002a35-0000-1000-8000-00805f9b34fb'), deviceId: deviceId, serviceId: Uuid.parse('00001810-0000-1000-8000-00805f9b34fb'), ); // 订阅血压测量特征 flutterReactiveBle .subscribeToCharacteristic(bloodPressureCharacteristic) .listen( (data) { print('Received raw data for blood pressure measurement: $data'); // 在此处处理通知数据 }, onError: (error) { print('Error subscribing to blood pressure measurement: $error'); // 处理订阅错误 }, ); }
解析方案
一、BLE血压测量特征(0x2A35)标准格式
BLE官方定义的血压测量特征(UUID: 00002a35-0000-1000-8000-00805f9b34fb)数据结构如下:
- 第1字节:Flags标志位,用于标记后续字段的存在状态和单位:
- Bit 0: 0=血压单位为mmHg,1=kPa
- Bit 4: 1=数据包含心率(脉率)
- Bit 6: 1=数据包含舒张压
- Bit 7: 1=数据包含收缩压
- 后续字段:根据Flags的标记,依次出现以下数据(每个数值为2字节的SFLOAT浮点数):
- 收缩压 → 舒张压 → 心率(若对应标志位为1)
- SFLOAT格式规则:数值 = 尾数 × 10^指数,其中尾数是12位补码,指数为3位值减4(范围-4到+3)
二、实现解析代码
在_subscribeToBloodPressureMeasurement的listen回调中添加解析逻辑:
void _subscribeToBloodPressureMeasurement(String deviceId) { final bloodPressureCharacteristic = QualifiedCharacteristic( characteristicId: Uuid.parse('00002a35-0000-1000-8000-00805f9b34fb'), deviceId: deviceId, serviceId: Uuid.parse('00001810-0000-1000-8000-00805f9b34fb'), ); flutterReactiveBle .subscribeToCharacteristic(bloodPressureCharacteristic) .listen( (data) { print('Received raw data for blood pressure measurement: $data'); _parseBloodPressureData(data); }, onError: (error) { print('Error subscribing to blood pressure measurement: $error'); }, ); } void _parseBloodPressureData(List<int> data) { if (data.isEmpty) return; // 解析Flags标志位 final flags = data[0]; final isMmhg = (flags & 0x01) == 0; // Bit0=0 → mmHg final hasSystolic = (flags & 0x80) != 0; // Bit7=1 → 有收缩压 final hasDiastolic = (flags & 0x40) != 0; // Bit6=1 → 有舒张压 final hasHeartRate = (flags & 0x10) != 0; // Bit4=1 → 有心率 int offset = 1; // 跳过Flags字节 // 解析收缩压 if (hasSystolic) { final systolic = _parseSfloat(data[offset], data[offset+1]); print('收缩压: ${systolic.toStringAsFixed(1)} ${isMmhg ? 'mmHg' : 'kPa'}'); offset +=2; } // 解析舒张压 if (hasDiastolic) { final diastolic = _parseSfloat(data[offset], data[offset+1]); print('舒张压: ${diastolic.toStringAsFixed(1)} ${isMmhg ? 'mmHg' : 'kPa'}'); offset +=2; } // 跳过平均动脉压(如果存在,Bit5=1) if ((flags & 0x20) !=0) offset +=2; // 解析心率 if (hasHeartRate) { final heartRate = _parseSfloat(data[offset], data[offset+1]); print('心率: ${heartRate.toStringAsFixed(0)} bpm'); offset +=2; } // 若需要解析时间戳、用户ID等其他字段,可继续按规范扩展 } double _parseSfloat(int byte1, int byte2) { // 小端字节序,组合成16位值 final int16Value = (byte2 << 8) | byte1; // 拆分SFLOAT的符号位、指数位、尾数位 final sign = (int16Value >> 15) & 0x01; final exponent = ((int16Value >> 12) & 0x07) -4; int mantissa = int16Value & 0x0FFF; // 处理负数尾数 if (mantissa > 0x07FF) { mantissa -= 0x1000; } // 计算最终数值 double value = mantissa * pow(10, exponent); return sign == 1 ? -value : value; }
三、针对你的原始数据的说明
将你的数据代入上述标准解析代码后,得到的结果不符合实际血压/心率范围,说明你的设备可能未遵循BLE官方规范,使用了自定义编码格式。建议:
- 查阅设备官方文档,确认数据编码规则
- 尝试调换字节序解析,或按
无符号整数×0.01等简化规则测试 - 联系设备厂商获取专属协议文档
内容的提问来源于stack exchange,提问作者al ice
相关产品推荐
相关产品推荐

