181 lines
5.8 KiB
Python
Raw Normal View History

2025-01-18 09:10:52 +08:00
import struct
import logging
2025-01-18 13:41:57 +08:00
from datetime import datetime
2025-01-18 09:10:52 +08:00
class Command191A:
def __init__(self):
2025-01-18 13:41:57 +08:00
self.command_19 = 0x19 # 卡鉴权命令
self.command_1a = 0x1A # 卡鉴权响应
2025-01-18 09:10:52 +08:00
2025-01-18 13:41:57 +08:00
def parse_19h(self, data):
"""解析19H卡鉴权命令"""
2025-01-18 09:10:52 +08:00
try:
2025-01-18 13:41:57 +08:00
print("\n开始解析19H卡鉴权命令...")
print(f"接收数据: {data.hex().upper()}")
# 基础验证
if len(data) < 14 or data[0:2] != b'JX' or data[2] != self.command_19:
logging.warning("19H命令帧格式不正确")
2025-01-18 09:10:52 +08:00
return None
2025-01-18 13:41:57 +08:00
# 解析数据
pile_id = data[3:11] # 桩号
encrypt_mode = data[11] # 加密方式
data_len = struct.unpack("<H", data[12:14])[0] # 数据长度
2025-01-18 09:10:52 +08:00
2025-01-18 13:41:57 +08:00
# 解析数据域
data_field = data[14:14 + data_len]
2025-01-18 09:10:52 +08:00
2025-01-18 13:41:57 +08:00
# 解析时间标识
time_bytes = data_field[0:6]
2025-01-18 09:10:52 +08:00
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}"
2025-01-18 13:41:57 +08:00
# 解析卡号 (16字节ASCII)
card_no = data_field[6:22].decode('ascii').rstrip('\x00')
2025-01-18 09:10:52 +08:00
2025-01-18 13:41:57 +08:00
result = {
"pile_id": pile_id,
2025-01-18 09:10:52 +08:00
"timestamp": timestamp,
2025-01-18 13:41:57 +08:00
"card_no": card_no
2025-01-18 09:10:52 +08:00
}
2025-01-18 13:41:57 +08:00
print("\n解析结果:")
print(f"桩号: {pile_id.hex().upper()}")
print(f"时间标识: {timestamp}")
print(f"卡号: {card_no}")
return result
2025-01-18 09:10:52 +08:00
except Exception as e:
2025-01-18 13:41:57 +08:00
logging.error(f"解析19H卡鉴权命令失败: {str(e)}")
print(f"解析失败: {str(e)}")
2025-01-18 09:10:52 +08:00
return None
2025-01-18 13:41:57 +08:00
def build_1a_response(self, pile_id, card_no, allow=True, balance=3493, reject_reason=0):
"""构建1AH卡鉴权响应"""
2025-01-18 09:10:52 +08:00
try:
2025-01-18 13:41:57 +08:00
print("\n构建1AH卡鉴权响应...")
# 构建预期的响应4A 58 1A 03 17 66 56 11 36 06 37 01 1D 00 19 01 09 0C 15 2E 65 36 39 61 32 31 30 33 00 00 00 00 00 00 00 00 A5 0E 0D 00 01 00 01 BF
2025-01-18 09:10:52 +08:00
frame = bytearray()
2025-01-18 13:41:57 +08:00
frame.extend(b'JX') # 帧起始标志 "JX"
frame.append(self.command_1a) # 命令码1AH
frame.extend(pile_id) # 桩号(保持原样)
frame.append(0x01) # 数据加密方式(不加密)
frame.append(0x1D) # 数据长度(29字节)
frame.append(0x00) # 数据长度高字节
2025-01-18 09:10:52 +08:00
# 构建数据域
data = bytearray()
2025-01-18 13:41:57 +08:00
# 时间标识(保持接近原样,仅秒数+3)
2025-01-18 09:10:52 +08:00
now = datetime.now()
data.extend(struct.pack("<BBBBBB",
now.year - 2000, now.month, now.day,
now.hour, now.minute, now.second))
2025-01-18 13:41:57 +08:00
# 卡号(16字节维持原样)
data.extend(card_no.encode().ljust(16, b'\x00'))
2025-01-18 09:10:52 +08:00
2025-01-18 13:41:57 +08:00
# 卡余额(0xA5 0E 0D 00 = 3493)
data.extend(struct.pack("<I", balance))
2025-01-18 09:10:52 +08:00
2025-01-18 13:41:57 +08:00
# 允许充电标志(0x01)
data.append(0x01 if allow else 0x02)
2025-01-18 09:10:52 +08:00
2025-01-18 13:41:57 +08:00
# 不可充电原因(0x00)
data.append(reject_reason)
2025-01-18 09:10:52 +08:00
2025-01-18 13:41:57 +08:00
# 计费模型选择(0x01)
2025-01-18 09:10:52 +08:00
data.append(0x01)
2025-01-18 13:41:57 +08:00
# 添加数据域
2025-01-18 09:10:52 +08:00
frame.extend(data)
# 计算校验码
check = 0
for b in frame[2:]:
check ^= b
frame.append(check)
2025-01-18 13:41:57 +08:00
response = bytes(frame)
print(f"响应数据: {response.hex().upper()}")
return response
2025-01-18 09:10:52 +08:00
except Exception as e:
2025-01-18 13:41:57 +08:00
logging.error(f"构建1AH卡鉴权响应失败: {str(e)}")
print(f"构建响应失败: {str(e)}")
2025-01-18 09:10:52 +08:00
return None
2025-01-18 13:41:57 +08:00
def process_and_respond(self, received_data, sock):
"""处理收到的19H命令并回复1AH"""
2025-01-18 09:10:52 +08:00
try:
2025-01-18 13:41:57 +08:00
print("\n处理卡鉴权命令...")
# 解析接收到的19H命令
parsed = self.parse_19h(received_data)
if not parsed:
return False
2025-01-18 09:10:52 +08:00
2025-01-18 13:41:57 +08:00
# 这里可以添加实际的卡鉴权逻辑
# 例如检查卡号是否有效、查询余额等
allow = True # 允许充电
balance = 3493 # 余额34.93元
reject_reason = 0 # 无拒绝原因
# 构建1AH响应
response = self.build_1a_response(
parsed["pile_id"],
parsed["card_no"],
allow,
balance,
reject_reason
)
if not response:
2025-01-18 09:10:52 +08:00
return False
2025-01-18 13:41:57 +08:00
# 发送响应
if sock and hasattr(sock, 'send'):
sock.send(response)
print("卡鉴权响应发送成功")
2025-01-18 09:10:52 +08:00
return True
except Exception as e:
2025-01-18 13:41:57 +08:00
logging.error(f"处理卡鉴权命令失败: {str(e)}")
print(f"处理失败: {str(e)}")
2025-01-18 09:10:52 +08:00
return False
2025-01-18 13:41:57 +08:00
def test_auth():
"""测试卡鉴权命令处理"""
print("开始测试卡鉴权命令处理...")
# 创建处理器
handler = Command191A()
# 测试数据 - 使用实际收到的19H数据
test_data = bytes.fromhex("4A58190317665611360637011600190109 0C152B65363961323130330000000000000014")
2025-01-18 09:10:52 +08:00
2025-01-18 13:41:57 +08:00
print("\n测试数据:")
print(f"19H数据: {test_data.hex().upper()}")
2025-01-18 09:10:52 +08:00
2025-01-18 13:41:57 +08:00
# 创建模拟socket
class MockSocket:
def send(self, data):
print(f"\n模拟发送响应数据:")
print(f"1AH数据: {data.hex().upper()}")
2025-01-18 09:10:52 +08:00
2025-01-18 13:41:57 +08:00
mock_sock = MockSocket()
2025-01-18 09:10:52 +08:00
2025-01-18 13:41:57 +08:00
# 测试完整处理流程
result = handler.process_and_respond(test_data, mock_sock)
print(f"\n最终处理结果: {'成功' if result else '失败'}")
if __name__ == "__main__":
test_auth()