215 lines
8.7 KiB
Python
Raw Normal View History

2025-01-18 09:10:52 +08:00
import struct
import logging
import binascii
from datetime import datetime
class Command25:
def __init__(self):
self.command = 0x25 # 充电信息命令
def parse_25h_charging_info(self, data):
"""
解析25H充电信息命令
:param data: 完整的25H命令报文
:return: 解析后的字典或None
"""
try:
# 验证基本帧格式
if len(data) < 14 or data[0:2] != b'JX' or data[2] != 0x25:
logging.warning(f"25H命令帧格式不正确原始报文: {binascii.hexlify(data)}")
return None
# 打印完整的原始报文以便调试
print(f"完整原始报文: {binascii.hexlify(data)}")
# 提取桩号
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
charging_voltage = struct.unpack("<H", data[current_index:current_index + 2])[0] / 10 # 0.1V
current_index += 2
charging_current = struct.unpack("<H", data[current_index:current_index + 2])[0] / 10 # 0.1A
current_index += 2
charging_power = struct.unpack("<I", data[current_index:current_index + 4])[0] / 100 # 0.01kW
current_index += 4
charging_duration = struct.unpack("<I", data[current_index:current_index + 4])[0] # 秒
current_index += 4
charging_amount = struct.unpack("<I", data[current_index:current_index + 4])[0] / 100 # 0.01kWh
current_index += 4
charging_fee = struct.unpack("<I", data[current_index:current_index + 4])[0] / 100 # 0.01元
current_index += 4
# 解析充电模块接入数量
charging_module_count = data[current_index]
current_index += 1
# 解析充电电费
charging_electricity_fee = struct.unpack("<I", data[current_index:current_index + 4])[0] / 100 # 0.01元
current_index += 4
# 解析服务费
service_fee = struct.unpack("<I", data[current_index:current_index + 4])[0] / 100 # 0.01元
current_index += 4
# 解析充电订单号17字节
charging_order_number = data[current_index:current_index + 17].decode('ascii').rstrip('\x00')
current_index += 17
# 解析时间段信息
time_periods = []
time_period_count = data[current_index]
current_index += 1
for _ in range(time_period_count):
# 每个时间段的解析
period_start_time = datetime(
year, month, day,
data[current_index],
data[current_index + 1]
)
current_index += 2
period_type = data[current_index] # 1-尖2-峰3-平4-谷
current_index += 1
period_electricity_price = struct.unpack("<I", data[current_index:current_index + 4])[
0] / 10000 # 0.0001元/kWh
current_index += 4
period_service_price = struct.unpack("<I", data[current_index:current_index + 4])[
0] / 10000 # 0.0001元/kWh
current_index += 4
period_electricity_amount = struct.unpack("<H", data[current_index:current_index + 2])[
0] / 100 # 0.01kWh
current_index += 2
period_electricity_fee = struct.unpack("<I", data[current_index:current_index + 4])[0] / 100 # 0.01元
current_index += 4
period_service_fee = struct.unpack("<I", data[current_index:current_index + 4])[0] / 100 # 0.01元
current_index += 4
time_periods.append({
"start_time": period_start_time,
"type": self.get_period_type_text(period_type),
"electricity_price": period_electricity_price,
"service_price": period_service_price,
"electricity_amount": period_electricity_amount,
"electricity_fee": period_electricity_fee,
"service_fee": period_service_fee
})
# 打印解析结果
print("\n25H充电信息命令解析结果:")
print(f"桩号: {pile_id_bytes.hex()}")
print(f"时间标识: {timestamp}")
print(f"充电电压: {charging_voltage}V")
print(f"充电电流: {charging_current}A")
print(f"充电功率: {charging_power}kW")
print(f"充电时长: {charging_duration}")
print(f"充电电量: {charging_amount}kWh")
print(f"充电金额: {charging_fee}")
print(f"充电模块接入数量: {charging_module_count}")
print(f"充电电费: {charging_electricity_fee}")
print(f"服务费: {service_fee}")
print(f"充电订单号: {charging_order_number}")
print("时间段信息:")
for period in time_periods:
print(f" - 开始时间: {period['start_time']}")
print(f" 类型: {period['type']}")
print(f" 电价: {period['electricity_price']}元/kWh")
print(f" 服务费率: {period['service_price']}元/kWh")
print(f" 电量: {period['electricity_amount']}kWh")
print(f" 电费: {period['electricity_fee']}")
print(f" 服务费: {period['service_fee']}")
return {
"pile_id": pile_id_bytes.hex(),
"timestamp": timestamp,
"charging_voltage": charging_voltage,
"charging_current": charging_current,
"charging_power": charging_power,
"charging_duration": charging_duration,
"charging_amount": charging_amount,
"charging_fee": charging_fee,
"charging_module_count": charging_module_count,
"charging_electricity_fee": charging_electricity_fee,
"service_fee": service_fee,
"charging_order_number": charging_order_number,
"time_periods": time_periods
}
except Exception as e:
logging.error(f"解析25H命令失败: {str(e)}")
logging.error(f"原始报文: {binascii.hexlify(data)}")
return None
def get_period_type_text(self, period_type):
"""
解析时间段类型
:param period_type: 时间段类型字节
:return: 时间段类型文本描述
"""
type_map = {
1: "",
2: "",
3: "",
4: ""
}
return type_map.get(period_type, f"未知类型 (0x{period_type:02X})")
def process_25h_charging_info(self, data):
"""
处理25H充电信息命令
:param data: 完整的25H命令报文
:return: 是否成功处理
"""
try:
parsed_data = self.parse_25h_charging_info(data)
if parsed_data is None:
logging.warning("25H命令解析失败")
return False
# 记录充电信息日志
logging.info(
f"收到桩号 {parsed_data['pile_id']} 的充电信息: "
f"充电电量 {parsed_data['charging_amount']}kWh, "
f"充电时长 {parsed_data['charging_duration']}秒, "
f"充电订单号 {parsed_data['charging_order_number']}"
)
return True
except Exception as e:
logging.error(f"处理25H命令出错: {str(e)}")
return False
# 测试用例
if __name__ == "__main__":
# 25H命令测试报文
test_25_data = bytes.fromhex(
"4A 58 25 03 17 66 56 11 36 06 37 01 61 00 19 01 09 0B 25 13 01 DA 07 00 00 00 00 00 00 22 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 31 38 37 37 31 39 37 38 30 31 36 31 35 35 35 36 36 31 30 00 00 00 00 00 00 00 00 00 00 00 00 00 01 19 01 09 0B 24 2D 19 01 09 0B 25 13 32 0F 00 00 AC 0D 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3B 4A 58 30 03 17 66 56 11 36 06 37 01 1C 00 19 01 09 0B 25 13 01 00 00 A0 0F 02 DA 07 A0 0F 00 00 00 00 00 00 00 00 00 00 00 00 ED")
parser = Command25()
# 测试解析25H命令
parser.process_25h_charging_info(test_25_data)