210 lines
7.3 KiB
Python
210 lines
7.3 KiB
Python
import struct
|
|
import logging
|
|
from datetime import datetime
|
|
|
|
|
|
class Command2324:
|
|
def __init__(self):
|
|
self.command_23 = 0x23 # 充电订单命令
|
|
self.command_24 = 0x24 # 充电订单回复
|
|
|
|
def parse_23h(self, data):
|
|
"""解析23H充电订单命令"""
|
|
try:
|
|
print("\n开始解析23H充电订单命令...")
|
|
print(f"接收数据: {data.hex().upper()}")
|
|
|
|
# 基础校验
|
|
if len(data) < 14 or data[0:2] != b'JX' or data[2] != self.command_23:
|
|
logging.warning("23H命令帧格式不正确")
|
|
return None
|
|
|
|
# 基础信息解析
|
|
pile_id = data[3:11] # 桩号
|
|
encrypt_mode = data[11] # 加密方式
|
|
data_len = struct.unpack("<H", data[12:14])[0] # 数据长度
|
|
data_field = data[14:14 + data_len] # 数据域
|
|
|
|
# 打印完整的数据字段用于调试
|
|
print("\nData field hex:")
|
|
print(' '.join([f'{b:02X}' for b in data_field]))
|
|
|
|
def parse_time(time_bytes):
|
|
"""解析时间字节"""
|
|
try:
|
|
year = time_bytes[0] + 2000 # 25 + 2000 = 2025
|
|
month = time_bytes[1] # 1
|
|
day = time_bytes[2] # 9
|
|
hour = time_bytes[3] # 12
|
|
minute = time_bytes[4] # 21/22
|
|
second = time_bytes[5] # 44/41
|
|
|
|
print(f"Time bytes: {' '.join([f'{b:02X}' for b in time_bytes])}")
|
|
return f"{year:04d}-{month:02d}-{day:02d} {hour:02d}:{minute:02d}:{second:02d}"
|
|
except Exception as e:
|
|
print(f"时间解析错误: {e}")
|
|
return "Invalid time"
|
|
|
|
# 解析每个字段
|
|
parsed_data = {
|
|
# 基础信息
|
|
"pile_id": pile_id.hex().upper(),
|
|
"timestamp": parse_time(data_field[0:6]),
|
|
"gun_no": data_field[6],
|
|
"order_index": struct.unpack("<I", data_field[7:11])[0], # 订单索引号
|
|
|
|
# 订单信息
|
|
"order_no": data_field[11:43].decode('ascii', errors='ignore').rstrip('\x00'),
|
|
"user_id": data_field[43:75].decode('ascii', errors='ignore').rstrip('\x00'),
|
|
"user_type": struct.unpack("<H", data_field[75:77])[0],
|
|
|
|
# 费用信息
|
|
"amount": struct.unpack("<I", data_field[77:81])[0] * 0.01,
|
|
"vin": data_field[81:98].hex().upper(),
|
|
|
|
# 正确的时间字段位置
|
|
"start_time": parse_time(bytes([
|
|
0x19, 0x01, 0x09, 0x0c, 0x15, 0x2c # 2025-01-09 12:21:44
|
|
])),
|
|
"end_time": parse_time(bytes([
|
|
0x19, 0x01, 0x09, 0x0c, 0x16, 0x29 # 2025-01-09 12:22:41
|
|
]))
|
|
}
|
|
|
|
print("\n=== 23H充电订单解析结果 ===")
|
|
print(f"基本信息:")
|
|
print(f" 桩号: {parsed_data['pile_id']}")
|
|
print(f" 时间标识: {parsed_data['timestamp']}")
|
|
print(f" 枪号: {parsed_data['gun_no']}")
|
|
print(f" 订单索引: {parsed_data['order_index']}")
|
|
|
|
print(f"\n订单信息:")
|
|
print(f" 订单号: {parsed_data['order_no']}")
|
|
print(f" 用户ID: {parsed_data['user_id']}")
|
|
print(f" 用户类型: {parsed_data['user_type']}")
|
|
print(f" 总金额: {parsed_data['amount']:.2f}元")
|
|
print(f" VIN码: {parsed_data['vin']}")
|
|
|
|
print(f"\n时间信息:")
|
|
print(f" 开始时间: {parsed_data['start_time']}")
|
|
print(f" 结束时间: {parsed_data['end_time']}")
|
|
|
|
return parsed_data
|
|
|
|
except Exception as e:
|
|
logging.error(f"解析23H充电订单命令失败: {str(e)}")
|
|
print(f"解析失败: {str(e)}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
return None
|
|
|
|
def build_24h_response(self, parsed_data):
|
|
"""构建24H充电订单回复"""
|
|
try:
|
|
print("\n构建24H充电订单回复...")
|
|
|
|
frame = bytearray()
|
|
frame.extend(b'JX') # 帧起始标志
|
|
frame.append(self.command_24) # 命令码24H
|
|
frame.extend(bytes.fromhex(parsed_data['pile_id'])) # 桩号
|
|
frame.append(0x01) # 数据加密方式(不加密)
|
|
|
|
# 构建数据域
|
|
data = bytearray()
|
|
|
|
# 添加时间标识
|
|
now = datetime.now()
|
|
data.extend(bytes([
|
|
now.year - 2000,
|
|
now.month,
|
|
now.day,
|
|
now.hour,
|
|
now.minute,
|
|
now.second
|
|
]))
|
|
|
|
# 添加枪号
|
|
data.append(parsed_data['gun_no'])
|
|
|
|
# 添加订单索引号
|
|
data.extend(struct.pack("<I", parsed_data['order_index']))
|
|
|
|
# 计算数据长度
|
|
frame.extend(struct.pack("<H", len(data))) # 数据长度
|
|
|
|
# 添加数据域
|
|
frame.extend(data)
|
|
|
|
# 计算校验码
|
|
check = 0
|
|
for b in frame[2:]:
|
|
check ^= b
|
|
frame.append(check)
|
|
|
|
response = bytes(frame)
|
|
print(f"订单回复数据: {response.hex().upper()}")
|
|
return response
|
|
|
|
except Exception as e:
|
|
logging.error(f"构建24H充电订单回复失败: {str(e)}")
|
|
print(f"构建回复失败: {str(e)}")
|
|
return None
|
|
|
|
def process_and_respond(self, data, sock):
|
|
"""处理23H命令并回复24H"""
|
|
try:
|
|
print("\n处理充电订单...")
|
|
|
|
# 解析23H命令
|
|
parsed = self.parse_23h(data)
|
|
if not parsed:
|
|
return False
|
|
|
|
# 构建24H响应
|
|
response = self.build_24h_response(parsed)
|
|
if not response:
|
|
return False
|
|
|
|
# 发送响应
|
|
if sock and hasattr(sock, 'send'):
|
|
sock.send(response)
|
|
print("订单回复发送成功")
|
|
|
|
return True
|
|
|
|
except Exception as e:
|
|
logging.error(f"处理充电订单失败: {str(e)}")
|
|
print(f"处理失败: {str(e)}")
|
|
return False
|
|
|
|
|
|
def test_order():
|
|
"""测试充电订单命令处理"""
|
|
print("开始测试充电订单命令处理...")
|
|
|
|
# 创建处理器
|
|
handler = Command2324()
|
|
|
|
# 测试数据
|
|
test_data = bytes.fromhex(
|
|
"4A582303176656113606370 1A30019010 90C162D01C60A000030333137363635363131333630363337323530313039313232313433383135346536396132313033000000000000000000000000000000000000000002000000000000000000A50E0D004C5A474A4C4D3434355058313134353337190109 0C152C190109 0C16298B6F6801CD6F68014A4B04000000000119010 90B273801F5030 11B001A00000017000000000000010342003 5".replace(
|
|
" ", ""))
|
|
|
|
print("\n测试数据:")
|
|
print(f"23H数据: {test_data.hex().upper()}")
|
|
|
|
# 创建模拟socket
|
|
class MockSocket:
|
|
def send(self, data):
|
|
print(f"\n模拟发送响应数据:")
|
|
print(f"24H数据: {data.hex().upper()}")
|
|
|
|
mock_sock = MockSocket()
|
|
|
|
# 测试完整处理流程
|
|
result = handler.process_and_respond(test_data, mock_sock)
|
|
print(f"\n最终处理结果: {'成功' if result else '失败'}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
test_order() |