181 lines
5.8 KiB
Python
181 lines
5.8 KiB
Python
import struct
|
||
import logging
|
||
from datetime import datetime
|
||
|
||
|
||
class Command191A:
|
||
def __init__(self):
|
||
self.command_19 = 0x19 # 卡鉴权命令
|
||
self.command_1a = 0x1A # 卡鉴权响应
|
||
|
||
def parse_19h(self, data):
|
||
"""解析19H卡鉴权命令"""
|
||
try:
|
||
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命令帧格式不正确")
|
||
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]
|
||
|
||
# 解析时间标识
|
||
time_bytes = data_field[0:6]
|
||
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}"
|
||
|
||
# 解析卡号 (16字节ASCII)
|
||
card_no = data_field[6:22].decode('ascii').rstrip('\x00')
|
||
|
||
result = {
|
||
"pile_id": pile_id,
|
||
"timestamp": timestamp,
|
||
"card_no": card_no
|
||
}
|
||
|
||
print("\n解析结果:")
|
||
print(f"桩号: {pile_id.hex().upper()}")
|
||
print(f"时间标识: {timestamp}")
|
||
print(f"卡号: {card_no}")
|
||
|
||
return result
|
||
|
||
except Exception as e:
|
||
logging.error(f"解析19H卡鉴权命令失败: {str(e)}")
|
||
print(f"解析失败: {str(e)}")
|
||
return None
|
||
|
||
def build_1a_response(self, pile_id, card_no, allow=True, balance=3493, reject_reason=0):
|
||
"""构建1AH卡鉴权响应"""
|
||
try:
|
||
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
|
||
frame = bytearray()
|
||
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) # 数据长度高字节
|
||
|
||
# 构建数据域
|
||
data = bytearray()
|
||
|
||
# 时间标识(保持接近原样,仅秒数+3)
|
||
now = datetime.now()
|
||
data.extend(struct.pack("<BBBBBB",
|
||
now.year - 2000, now.month, now.day,
|
||
now.hour, now.minute, now.second))
|
||
|
||
# 卡号(16字节,维持原样)
|
||
data.extend(card_no.encode().ljust(16, b'\x00'))
|
||
|
||
# 卡余额(0xA5 0E 0D 00 = 3493)
|
||
data.extend(struct.pack("<I", balance))
|
||
|
||
# 允许充电标志(0x01)
|
||
data.append(0x01 if allow else 0x02)
|
||
|
||
# 不可充电原因(0x00)
|
||
data.append(reject_reason)
|
||
|
||
# 计费模型选择(0x01)
|
||
data.append(0x01)
|
||
|
||
# 添加数据域
|
||
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"构建1AH卡鉴权响应失败: {str(e)}")
|
||
print(f"构建响应失败: {str(e)}")
|
||
return None
|
||
|
||
def process_and_respond(self, received_data, sock):
|
||
"""处理收到的19H命令并回复1AH"""
|
||
try:
|
||
print("\n处理卡鉴权命令...")
|
||
|
||
# 解析接收到的19H命令
|
||
parsed = self.parse_19h(received_data)
|
||
if not parsed:
|
||
return False
|
||
|
||
# 这里可以添加实际的卡鉴权逻辑
|
||
# 例如检查卡号是否有效、查询余额等
|
||
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:
|
||
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_auth():
|
||
"""测试卡鉴权命令处理"""
|
||
print("开始测试卡鉴权命令处理...")
|
||
|
||
# 创建处理器
|
||
handler = Command191A()
|
||
|
||
# 测试数据 - 使用实际收到的19H数据
|
||
test_data = bytes.fromhex("4A58190317665611360637011600190109 0C152B65363961323130330000000000000014")
|
||
|
||
print("\n测试数据:")
|
||
print(f"19H数据: {test_data.hex().upper()}")
|
||
|
||
# 创建模拟socket
|
||
class MockSocket:
|
||
def send(self, data):
|
||
print(f"\n模拟发送响应数据:")
|
||
print(f"1AH数据: {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_auth() |