我有一个家庭作业,需要解码十六进制有效负载。我一直在尝试解码有效负载,但无法专门针对时间字段生成正确的输出。我希望能帮助您解码它。
任务描述:
为了监控电池的健康状况,我们决定将电池的数据发送到云端。该数据以十六进制格式传输并在我们的 AWS 账户中接收。
数据以十六进制字符串形式传输。每个有效负载由 8 个字节组成。由于空间优化,信息不是字节对齐的。字段可以从字节的中间开始。因此,我们需要位操作来解码有效负载。有效负载未以小端方式签名和编码。下表描述了有效负载中包含的数据字段及其位位置。
例如,类型在第一个字节中的 4 位上进行编码。充电状态在第 6 个字节的 8 位(1 字节)上进行编码。
时间:时间表示数据的时间戳。它是自 UNIX 纪元以来以秒为单位定义的。
State:state是一个字符串,对应的值如下:
0:“关闭电源”
1:“开机”
2:“放电”
3:“充电”
4:“充电完成”
5:“主机模式”
6:“关闭”
7:“错误”
8:“未定义”
充电状态:充电状态表示电池的电量。它是一个浮点数,值介于 0 到 100 之间,精度为 0.5。为了将其存储为整数,将其乘以 2。
电池温度:电池温度代表电池的温度。值可以在 -20 到 100 之间变化。精度为 0.5。为了将其存储为整数,我们添加了 20 并乘以 2。
测试数据示例
输入:F1E6E63676C75000
输出:{“时间”:1668181615,“状态”:“错误”,“充电状态”:99.5,“温度”:20.0}
我的脚本:
import base64
import struct
import json
from datetime import datetime
def lambda_handler(event):
# Extract device and payload from the event
device = event["device"]
payload_hex = event["payload"]
# Convert hexadecimal payload to bytes
payload_bytes = bytes.fromhex(payload_hex)
# Unpack the payload using struct
unpacked_data = struct.unpack('<I2Bh', payload_bytes)
# Extract individual fields
time = unpacked_data[0]
state = unpacked_data[1]
state = (state >> 4) & 0x0F
state_of_charge = unpacked_data[2] / 2.0
temperature = (unpacked_data[3] / 2.0) - 20.0
# Mapping state values to corresponding strings
state_mapping = {
0: "power off",
1: "power on",
2: "discharge",
3: "charge",
4: "charge complete",
5: "host mode",
6: "shutdown",
7: "error",
8: "undefined"
}
# Create the output dictionary
output_data = {
"device": device,
"time": time,
"state": state_mapping.get(state, "unknown"),
"state_of_charge": round(state_of_charge, 1),
"temperature": round(temperature, 1)
}
# Log the output data to stdout
print(json.dumps(output_data))
event = {'device': 'device1', 'payload': '6188293726C75C00'}
lambda_handler(event)
我目前正在努力获得正确的输出,这不仅仅取决于基于上述逻辑的 unpacked_data[0]。
struct
库并不是特别有用,因为数据不是字节对齐的,因此您需要执行一些手动位工作。如果您以前没有见过这个词,半个字节称为 nibble;该程序需要将字节拆分为半字节。
# parse the hexadecimal payload
payload = bytes.fromhex("6188293726C75C00")
# split the payload into individual bytes
b0, b1, b2, b3, b4, b5, b6, b7 = payload
# extact the type from the least significant 4 bits on the first byte
type = b0 & 0x0F
# extract the time from the next 32 bits
time_nibbles = [
b0 >> 4, # bits 0 - 4
b1 & 0x0F, b1 >> 4, # bits 5 - 12
b2 & 0x0F, b2 >> 4, # bits 13 - 20
b3 & 0x0F, b3 >> 4, # bits 21 - 28
b4 & 0x0F, # bits 29 - 32
]
time_bytes = [low | (high << 4) for low, high in zip(time_nibbles[::2], time_nibbles[1::2])]
time = int.from_bytes(time_bytes, byteorder="little")
print(f"{time = }")
# extract state
state = b4 >> 4
print(f"{state = }")
# extract state of charge
state_of_charge = b5 / 2
print(f"{state_of_charge = }")
# extract battery temperature
battery_temperature = (int.from_bytes([b6, b7], byteorder="little") / 2) - 20
print(f"{battery_temperature = }")
输出:
time = 1668454534
state = 2
state_of_charge = 99.5
battery_temperature = 26.0
ctypes
结构。向类添加属性也可以为您进行计算:
import ctypes as ct
import struct
class _Data(ct.Structure):
# Bitfield definitions
_fields_ = (('type', ct.c_uint64, 4),
('time', ct.c_uint64, 32),
('state', ct.c_uint64, 4),
('soc', ct.c_uint64, 8),
('temp', ct.c_uint64, 8))
states = ('power off', 'power on', 'discharge', 'charge',
'charge complete', 'host mode', 'shutdown',
'error', 'undefined')
class Data(ct.Union):
_fields_ = (('_u', ct.c_uint64),
('_d', _Data))
def __init__(self, data):
# Take raw byte data and unpack as 64-bit little-endian
self._u = struct.unpack('<Q', data)[0]
@property
def type(self):
return self._d.type
@property
def time(self):
return self._d.time
@property
def state(self):
try:
return self._d.states[self._d.state]
except IndexError:
return 'invalid'
@property
def state_of_charge(self):
return self._d.soc / 2
@property
def battery_temperature(self):
return self._d.temp / 2 - 20
def __repr__(self):
return (f'Data(type={self.type}, '
f'time={self.time}, '
f'state={self.state!r}, '
f'state_of_charge={self.state_of_charge}, '
f'temperature={self.battery_temperature})')
def as_dict(self):
return {'type': self.type,
'time': self.time,
'state': self.state,
'state_of_charge': self.state_of_charge,
'temperature': self.battery_temperature}
data = Data(bytes.fromhex('F1E6E63676C75000'))
print(data)
print(data.as_dict())
输出:
Data(type=1, time=1668181615, state='error', state_of_charge=99.5, temperature=20.0)
{'type': 1, 'time': 1668181615, 'state': 'error', 'state_of_charge': 99.5, 'temperature': 20.0}