#python #hex #bluetooth-lowenergy #unpack
Вопрос:
Я собираю рекламные данные с устройства BLE. В частности, меня интересуют эти два байта:
b'x17dx0ex10x0exd7x02x1dx00Gx00Ux01x00'
b'x02xadx02x8dx00x9bx00x0ex01xf6x01xadx00xcfx00Vx01-x01 x00x00x00x00x00'
В руководстве по эксплуатации устройства, которое доступно здесь. Они дают структуру для рекламных данных. Я попытался следовать этому и использовать struct.unpack
, как показано ниже:
import struct
bte = b'x17dx0ex10x0exd7x02x1dx00Gx00Ux01x00'
struct.unpack('<BBHHHH', bte)
Однако я получаю эту ошибку «для распаковки требуется буфер размером 10 байт». Я думаю, что это как-то связано с первым байтом x17d
, так как struct.unpack
всегда возвращает эту ошибку, когда у вас есть байт с более чем двумя символами. Также байты x00G
и x00U
, поскольку я не уверен, что означают U и G. Также этот байт имеет длину 11, в то время как байт формата <BBHHHH
должен иметь длину всего 10.
Любая помощь была бы очень признательна.
Комментарии:
1.
BBHHHH
ожидает 10 байт (1 1 2 2 2 2), ноb'x17dx0ex10x0exd7x02x1dx00Gx00Ux01x00'
, похоже, 14 байт. Ваша строка формата отключена.2. кстати, первый байт есть
0x17
, а второй байт0x64
иначе известен в мире ascii как:d
.3. Да, я уже попадался на это раньше. Обратите внимание, что только две цифры после
x
являются частью этого литерала.x00G
в качестве другого примера можно привести нулевой байт (00
), и"G"
; таким образом, всего два байта.4. Вы имели в виду:
struct.unpack('<BBHHHH', bte[:10])
?
Ответ №1:
На устройствах Blue Maestro я не думаю, что они помещают данные в формате little endian в данные производителя рекламы.
Глядя на ваши данные, я бы ожидал, что это будет что-то вроде следующего:
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], byteorder='big', signed=True) / 10
data["temperature"] = int.from_bytes(pckt[10:12], byteorder='big', signed=True) / 10
pprint(data)
Что дает те же значения:
{'batt_lvl': 100,
'dew_point': 7.1,
'humidity': 54.1,
'interval': 3600,
'log_count': 3799,
'temperature': 8.5,
'version': 23}
x17d
, x00G
, и x00U
— это все два байта. Однако вторые байты являются значениями ASCII, поэтому Python при отображении услужливо отображает букву, а не значение байта.
Чтобы доказать это, мы можем ввести значения байтов и увидеть значение ASCII на выходе:
>>> b'x64x47x55'
b'dGU'
Есть несколько вещей, которые вы можете сделать, чтобы показать фактическое значение байта, чтобы помочь в отладке.
Используйте hexlify:
>>> binascii.hexlify(bte)
b'17640e100ed7021d004700550100'
Преобразуйте байты в список денарных значений:
>>> list(bte)
[23, 100, 14, 16, 14, 215, 2, 29, 0, 71, 0, 85, 1, 0]
Отформатируйте его в виде строки с шестнадцатеричными значениями:
>>> [f'{n:02X}' for n in bte]
['17', '64', '0E', '10', '0E', 'D7', '02', '1D', '00', '47', '00', '55', '01', '00']
Комментарии:
1. Большое вам спасибо, что отлично сработали для меня. Не знал об этом
int.from_bytes
методе. Также , как указывали другиеx17d
,x00G
, иx00U
-это все два байта, как вы сказали, что сбивало меня с толку. Я провел некоторую отладку с помощью приложения на моем телефоне, которое показывает температуру, и я думаю, что у вас могут быть неверно помечены некоторые значения, но в остальном это работает отлично!