148 lines
5.8 KiB
Python
148 lines
5.8 KiB
Python
import struct
|
|
import logging
|
|
|
|
|
|
class Command0A:
|
|
def __init__(self):
|
|
self.command = 0x0A # 0AH命令码
|
|
|
|
def parse_0ah(self, data):
|
|
"""
|
|
解析0AH遥测命令
|
|
|
|
:param data: 完整的0AH命令报文
|
|
:return: 解析后的字典或None
|
|
"""
|
|
try:
|
|
# 验证基本帧格式
|
|
if len(data) < 14 or data[0:2] != b'JX' or data[2] != 0x0A:
|
|
logging.warning("0AH命令帧格式不正确")
|
|
return None
|
|
|
|
# 提取桩号
|
|
pile_id_bytes = data[3:11]
|
|
|
|
# 提取时间标识
|
|
time_bytes = data[14:20]
|
|
year = time_bytes[0] + 2000
|
|
month, day, hour, minute, second = time_bytes[1:6]
|
|
timestamp = f"{year:04d}-{month:02d}-{day:02d} {hour:02d}:{minute:02d}:{second:02d}"
|
|
|
|
# 解析总体电气参数
|
|
current_index = 20
|
|
power_params = {
|
|
"A相电压": struct.unpack("<H", data[current_index:current_index + 2])[0] / 10, # 0.1V
|
|
"B相电压": struct.unpack("<H", data[current_index + 2:current_index + 4])[0] / 10,
|
|
"C相电压": struct.unpack("<H", data[current_index + 4:current_index + 6])[0] / 10,
|
|
"A相电流": struct.unpack("<H", data[current_index + 6:current_index + 8])[0] / 100, # 0.01A
|
|
"B相电流": struct.unpack("<H", data[current_index + 8:current_index + 10])[0] / 100,
|
|
"C相电流": struct.unpack("<H", data[current_index + 10:current_index + 12])[0] / 100,
|
|
"总电表电量": struct.unpack("<I", data[current_index + 12:current_index + 16])[0] / 100 # 0.01kWh
|
|
}
|
|
current_index += 16
|
|
|
|
# 解析温度相关参数
|
|
temp_params = {
|
|
"桩内温度": data[current_index] - 50, # 偏移量-50℃
|
|
"进风口温度": data[current_index + 1] - 50,
|
|
"出风口温度": data[current_index + 2] - 50,
|
|
"控制板温度": data[current_index + 3] - 50,
|
|
"桩内湿度": data[current_index + 4] # 0-100%RH
|
|
}
|
|
current_index += 5
|
|
|
|
# 跳过预留字节
|
|
current_index += 8
|
|
|
|
# 解析充电枪数量
|
|
gun_count = data[current_index]
|
|
current_index += 1
|
|
|
|
# 存储每个充电枪的遥测数据
|
|
gun_params = []
|
|
for i in range(gun_count):
|
|
gun_data = {
|
|
"gun_index": i + 1,
|
|
"电表电压": struct.unpack("<H", data[current_index:current_index + 2])[0] / 10, # 0.1V
|
|
"电表电流": struct.unpack("<H", data[current_index + 2:current_index + 4])[0] / 100, # 0.01A
|
|
"电表电量": struct.unpack("<I", data[current_index + 4:current_index + 8])[0] / 100, # 0.01kWh
|
|
"充电模块电压": struct.unpack("<H", data[current_index + 8:current_index + 10])[0] / 10, # 0.1V
|
|
"充电模块电流": struct.unpack("<H", data[current_index + 10:current_index + 12])[0] / 10, # 0.1A
|
|
"充电模块温度": data[current_index + 12] - 50, # 偏移量-50℃
|
|
"充电枪温度": data[current_index + 13] - 50
|
|
}
|
|
gun_params.append(gun_data)
|
|
current_index += 14
|
|
|
|
# 打印解析结果
|
|
print("\n0AH命令解析结果:")
|
|
print(f"桩号: {pile_id_bytes.hex()}")
|
|
print(f"时间标识: {timestamp}")
|
|
|
|
print("总体电气参数:")
|
|
for param, value in power_params.items():
|
|
print(f" {param}: {value}")
|
|
|
|
print("温度和湿度参数:")
|
|
for param, value in temp_params.items():
|
|
print(f" {param}: {value}")
|
|
|
|
print(f"充电枪数量: {gun_count}")
|
|
for gun in gun_params:
|
|
print(f"枪 {gun['gun_index']} 遥测数据:")
|
|
for param, value in gun.items():
|
|
if param != "gun_index":
|
|
print(f" {param}: {value}")
|
|
|
|
return {
|
|
"pile_id": pile_id_bytes.hex(),
|
|
"timestamp": timestamp,
|
|
"power_params": power_params,
|
|
"temp_params": temp_params,
|
|
"gun_count": gun_count,
|
|
"gun_params": gun_params
|
|
}
|
|
|
|
except Exception as e:
|
|
logging.error(f"解析0AH命令失败: {str(e)}")
|
|
return None
|
|
|
|
def process_0ah(self, data):
|
|
"""
|
|
处理0AH遥测命令
|
|
|
|
:param data: 完整的0AH命令报文
|
|
:return: 是否成功处理
|
|
"""
|
|
try:
|
|
parsed_data = self.parse_0ah(data)
|
|
|
|
if parsed_data is None:
|
|
logging.warning("0AH命令解析失败")
|
|
return False
|
|
|
|
# 记录遥测信息日志
|
|
log_message = (
|
|
f"桩号 {parsed_data['pile_id']} 遥测数据: "
|
|
f"A相电压 {parsed_data['power_params']['A相电压']}V, "
|
|
f"总电量 {parsed_data['power_params']['总电表电量']}kWh, "
|
|
f"桩内温度 {parsed_data['temp_params']['桩内温度']}℃"
|
|
)
|
|
|
|
logging.info(log_message)
|
|
|
|
return True
|
|
|
|
except Exception as e:
|
|
logging.error(f"处理0AH命令出错: {str(e)}")
|
|
return False
|
|
|
|
|
|
# 测试用示例
|
|
if __name__ == "__main__":
|
|
# 示例报文
|
|
test_data = bytes.fromhex(
|
|
"4A 58 0A 03 17 67 63 11 36 06 57 01 48 00 19 01 09 09 37 39 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 00 00 00 00 74 29 AD 00 00 00 00 00 00 67 00 00 00 00 00 00 00 00 27 63 F1 00 00 00 00 00 00 E1 00 00 00 00 F2")
|
|
|
|
parser = Command0A()
|
|
parser.process_0ah(test_data) |