如何解码特征的字节值Python

问题描述

对于一个项目,我目前正在尝试通过蓝牙le从传感器(Polar OH1)获取一些与心脏有关的数据(ppg)。 传感器制造商使用的服务记录得不好。现在,当读取服务的特征值时,我得到了大量的字节数据:

'''\ r \ xb1 \ x1aQ \ xb4x \ xa3C \ x83 \ xdcv \ xd3Q \ x12 \ xbdJ \ x7f \ x82 \ xbf \ x06 \ x91s \ x07 \ xb7,\ xb4 \ xd5 \ xa59 \ xf1 \ xf8 \ x8e \ xabeF @ 2 \ xe0 \ x10 \ xcb {\ xe5 \ xfd \ x8dC \ x10f \ x8ca \ xe6 \ x98 \ xb2 \ xf9I \ xaa \ xb7 \ xff \ xe3 \ xab \ x13'\ x03J \ xd4 \ xb5 * / ...'''

不幸的是,使用utf-8,utf-16(le,be)或utf-32解码此数据均无效。 我如何找出如何解码这种神秘的混乱?因为这是我第一次使用Bluetooth Le,所以我真的很受困扰。

我在Linux(Ubuntu)上使用python3

最诚挚的问候

解决方法

在特征中存在BLE数据的情况下,一个特征内通常会有多个字段。例如,官方的心率测量特征可以长8个八位位组,并且在一个特征中具有用于标志,HRM值,能量消耗和RR间隔的字段。

如果使用蓝牙标准进行心率测量,则特征UUID将为0000 2A37 -0000-1000-8000-00805F9B34FB。官方UUID通常写为缩短到16位值,因此它应该是0x2A37。

您可以阅读有关16-bit UUID Numbers Document中的值的信息。另一个有用的文档是GATT Specification Supplement,它指定了如何在正式特性中表示值。

如果制造商使用了自定义特性,则这些文档几乎没有帮助。自定义特征由UUID值表示,该值不在0000xxxx-0000-1000-8000-00805F9B34FB范围内

要探索数据,通常使用nRF Connect之类的通用蓝牙低功耗扫描和探索工具会很有帮助

如果将二进制值拆分为每个项代表一个八位字节的列表,则在Python中通常更易于理解二进制值。例如:

>>> data = b'\r\xb1\x1aQ\xb4x\xa3C\x83\xdcv\xd3Q\x12\xbdJ\x7f\x82\xbf\x06\x91s\x07\xb7'
>>> list(data)
[13,177,26,81,180,120,163,67,131,220,118,211,18,189,74,127,130,191,6,145,115,7,183]
>>> [f'{i:02x}' for i in data]
['0d','b1','1a','51','b4','78','a3','43','83','dc','76','d3','12','bd','4a','7f','82','bf','06','91','73','07','b7']

要注意的另一件事是,在八位字节和整数之间转换时,int类型具有方法from_bytesto_bytes。例如,如果我们知道某个值的类型为sint16,则将其签名并占用2个八位位组。还要注意的另一件事是,BLE数据通常为little endian格式。

>>> int.from_bytes([0x82,0xbf],byteorder='little',signed=True)
-16510
>>> int(-16510).to_bytes(2,signed=True)
b'\x82\xbf'
>>> int.from_bytes(b'\x82\xbf',signed=True)
-16510
,

尝试使用cp1250编码。我认为您的字节数据不兼容,应该先整理一下

b'\xe5\xfd\x8dC\x10f\x8ca\xe6'.decode('cp1250')