如何修改Movesense ECG测量间隔特征值?写入无效问题求助
问题:无法通过Bleak修改Movesense自定义固件的ECG采样间隔
我使用搭载Jonas Primbs基于v2.2.1分支开发的自定义movesense-ble-ecg-firmware的Movesense设备,通过Python脚本结合Bleak库可成功连接设备并读取0x2bdd特征的ECG电压,但无法通过写入ECG测量间隔特征(0x2be3)修改采样间隔。
尝试过写入允许的数值:2(500Hz)、4(250Hz)、8(125Hz)、10(100Hz),以及b'\x10\x00'、b'\x10'、b'\x00\x10'等多种格式,但读取结果始终为b'\x04\x00'(对应250Hz)。测试脚本如下:
import asyncio from bleak import BleakClient, BleakScanner # BLE device name DEVICE_NAME = 'Movesense 202930001412' # ECG sampling rates SAMPLE_500_HZ = b'\x02\x00' # 2 SAMPLE_250_HZ = b'\x04\x00' # 4 SAMPLE_125_HZ = b'\x08\x00' # 8 SAMPLE_100_HZ = b'\x10\x00' # 10 # ECG service and characteristics UUIDs ECG_SERIVCE = 0x1859 ECG_FREQ_READ_WRITE = 0x2be3 CORE_UUID = '0000{0:x}-0000-1000-8000-00805f9b34fb' ECG_SERIVCE_UUID = CORE_UUID.format(ECG_SERIVCE) ECG_FREQ_READ_WRITE_UUID = CORE_UUID.format(ECG_FREQ_READ_WRITE) async def find_device(name): # Scan to get device with desired name. devices = await BleakScanner.discover() for device in devices: if device.name == name: return device return None async def run(name): # Find device with desired name device = await find_device(name) if not device: print(f'Device with name {name} not found...') return # Connect to device as client async with BleakClient(device) as client: if not client.is_connected: print('Failed to connect to the BLE device...') return print('Connected to the BLE device.') # Write ECG sampling time await client.write_gatt_char(ECG_FREQ_READ_WRITE_UUID, b'\x10\x00', response=False) # Read ECG sampling time sample_freq = await client.read_gatt_char(ECG_FREQ_READ_WRITE_UUID) print('sample frequency', sample_freq) await asyncio.sleep(5) # Disconnect from device await client.disconnect() asyncio.run(run(DEVICE_NAME))
排查与解决建议
1. 修正字节序与数值错误
你当前定义的SAMPLE_100_HZ = b'\x10\x00'对应十进制16,而不是需要的10(100Hz对应间隔10ms)。Movesense使用小端字节序,十进制10的十六进制是0x0A,正确的字节数组应为b'\x0A\x00'。
修正后的采样间隔常量:
# 正确的小端字节序(对应十进制间隔值,频率=1000/间隔值 Hz) SAMPLE_500_HZ = b'\x02\x00' # 间隔2ms → 500Hz SAMPLE_250_HZ = b'\x04\x00' # 间隔4ms → 250Hz SAMPLE_125_HZ = b'\x08\x00' # 间隔8ms → 125Hz SAMPLE_100_HZ = b'\x0A\x00' # 间隔10ms → 100Hz
2. 使用带响应的写入
当前代码中response=False会触发无响应写入,设备可能不会处理请求或返回错误。改为response=True,强制等待设备确认,能直接获知写入是否成功:
await client.write_gatt_char(ECG_FREQ_READ_WRITE_UUID, SAMPLE_100_HZ, response=True)
3. 先停止ECG测量再修改参数
多数Movesense固件要求修改采样间隔前,必须停止当前的ECG数据输出。如果0x2bdd特征处于通知状态,写入操作会被忽略。需先关闭通知,修改间隔后再重新开启:
# 假设ECG数据特征UUID是0x2bdd ECG_DATA_UUID = CORE_UUID.format(0x2bdd) # 关闭ECG数据通知 await client.stop_notify(ECG_DATA_UUID) # 修改采样间隔 await client.write_gatt_char(ECG_FREQ_READ_WRITE_UUID, SAMPLE_100_HZ, response=True) # 重新开启ECG数据通知 await client.start_notify(ECG_DATA_UUID, ecg_callback)
4. 验证特征写入权限
通过代码确认0x2be3特征是否支持写入:
char = client.get_gatt_char(ECG_FREQ_READ_WRITE_UUID) print(f'特征属性:{char.properties}')
输出应包含write或write-without-response,否则固件可能限制了该特征的写入权限。
修改后的完整测试脚本
import asyncio from bleak import BleakClient, BleakScanner # BLE设备名称 DEVICE_NAME = 'Movesense 202930001412' # ECG采样间隔(小端字节序,间隔值对应ms,频率=1000/间隔值 Hz) SAMPLE_500_HZ = b'\x02\x00' # 500Hz SAMPLE_250_HZ = b'\x04\x00' # 250Hz SAMPLE_125_HZ = b'\x08\x00' # 125Hz SAMPLE_100_HZ = b'\x0A\x00' # 100Hz # ECG服务与特征UUID ECG_SERVICE = 0x1859 ECG_FREQ_READ_WRITE = 0x2be3 ECG_DATA_CHAR = 0x2bdd CORE_UUID = '0000{0:x}-0000-1000-8000-00805f9b34fb' ECG_SERVICE_UUID = CORE_UUID.format(ECG_SERVICE) ECG_FREQ_READ_WRITE_UUID = CORE_UUID.format(ECG_FREQ_READ_WRITE) ECG_DATA_UUID = CORE_UUID.format(ECG_DATA_CHAR) async def find_device(name): devices = await BleakScanner.discover() for device in devices: if device.name == name: return device return None async def run(name): device = await find_device(name) if not device: print(f'未找到设备:{name}') return async with BleakClient(device) as client: if not client.is_connected: print('连接BLE设备失败') return print('已连接BLE设备') # 检查特征写入权限 char = client.get_gatt_char(ECG_FREQ_READ_WRITE_UUID) print(f'ECG间隔特征属性:{char.properties}') try: # 先关闭ECG数据通知(如果之前开启过) await client.stop_notify(ECG_DATA_UUID) # 带响应写入采样间隔 await client.write_gatt_char(ECG_FREQ_READ_WRITE_UUID, SAMPLE_100_HZ, response=True) print('采样间隔写入请求已发送') except Exception as e: print(f'写入失败:{str(e)}') # 读取并解析当前采样间隔 sample_bytes = await client.read_gatt_char(ECG_FREQ_READ_WRITE_UUID) interval = int.from_bytes(sample_bytes, byteorder='little') print(f'当前采样间隔:{interval}ms,对应频率:{1000/interval}Hz') await asyncio.sleep(2) asyncio.run(run(DEVICE_NAME))
内容的提问来源于stack exchange,提问作者JRBoston
相关产品推荐
相关产品推荐

