问题描述
我正在从 BLE 设备中获取广告数据。我特别对这两个字节感兴趣:
b'\x17d\x0e\x10\x0e\xd7\x02\x1d\x00G\x00U\x01\x00'
b'\x02\xad\x02\x8d\x00\x9b\x00\x0e\x01\xf6\x01\xad\x00\xcf\x00V\x01-\x01+\x00\x00\x00\x00\x00'
在设备手册中,可用 here。他们给出了广告数据的结构。我试图遵循这一点并使用 struct.unpack
如下所示:
import struct
bte = b'\x17d\x0e\x10\x0e\xd7\x02\x1d\x00G\x00U\x01\x00'
struct.unpack('<BBHHHH',bte)
但是,我收到此错误“解包需要 10 个字节的缓冲区”。我认为这与第一个字节 \x17d\
有关,因为当您有一个超过两个字符的字节时,struct.unpack
总是会返回此错误。还有字节 \x00G\
和 \x00U\
因为我不确定 U 和 G 是什么意思。此外,此字节的长度为 11,而格式为 <BBHHHH
的字节应仅为 10。
任何帮助将不胜感激。
解决方法
在 Blue Maestro 设备上,我认为他们不会将数据以小端格式放入广告制造商数据中。
查看您的数据,我希望它类似于以下内容:
import binascii
from pprint import pprint
from struct import unpack
pckt = binascii.unhexlify('17640e100ed7021d004700550100')
data = {}
data["version"] = unpack(">B",pckt[0:1])[0]
data["batt_lvl"] = unpack(">B",pckt[1:2])[0]
data["interval"] = unpack(">H",pckt[2:4])[0]
data["log_count"] = unpack(">H",pckt[4:6])[0]
data["humidity"] = unpack(">h",pckt[6:8])[0] / 10
data["dew_point"] = unpack(">h",pckt[8:10])[0] / 10
data["temperature"] = unpack(">h",pckt[10:12])[0] / 10
pprint(data)
给出输出:
{'batt_lvl': 100,'dew_point': 7.1,'humidity': 54.1,'interval': 3600,'log_count': 3799,'temperature': 8.5,'version': 23}
您可以一次性打开包装,但您必须调整露点湿度和温度值:
unpack('>BBHHhhh',pckt[:12])
# (23,100,3600,3799,541,71,85)
在挑选单个值时,使用 int.from_bytes
功能会更清晰。
import binascii
from pprint import pprint
pckt = binascii.unhexlify('17640e100ed7021d004700550100')
data = {}
data["version"] = int.from_bytes(pckt[0:1],byteorder='big')
data["batt_lvl"] = int.from_bytes(pckt[1:2],byteorder='big')
data["interval"] = int.from_bytes(pckt[2:4],byteorder='big')
data["log_count"] = int.from_bytes(pckt[4:6],byteorder='big')
data["humidity"] = int.from_bytes(pckt[6:8],byteorder='big',signed=True) / 10
data["dew_point"] = int.from_bytes(pckt[8:10],signed=True) / 10
data["temperature"] = int.from_bytes(pckt[10:12],signed=True) / 10
pprint(data)
给出相同的值:
{'batt_lvl': 100,'version': 23}
\x17d
、\x00G
和 \x00U
都是两个字节。然而,第二个字节恰好是 ASCII 值,因此 Python 在显示时会显示字母而不是字节值。
为了证明这一点,我们可以输入字节值并在输出中查看 ASCII 值:
>>> b'\x64\x47\x55'
b'dGU'
您可以执行一些操作来显示实际字节值以帮助调试。
使用十六进制:
>>> binascii.hexlify(bte)
b'17640e100ed7021d004700550100'
将字节转换为一个 denary 值列表:
>>> list(bte)
[23,14,16,215,2,29,85,1,0]
将其格式化为带有十六进制值的字符串:
>>> [f'{n:02X}' for n in bte]
['17','64','0E','10','D7','02','1D','00','47','55','01','00']