2025-01-18 09:10:52 +08:00

215 lines
8.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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)