185 lines
6.0 KiB
Python
Raw Normal View History

2025-01-18 09:10:52 +08:00
import struct
import logging
import binascii
class Command191A:
def __init__(self):
self.command_19 = 0x19 # 卡鉴权上报命令
self.command_1a = 0x1A # 平台回复卡鉴权命令
def parse_19_card_auth(self, data):
"""
解析19H卡鉴权上报命令
:param data: 完整的19H命令报文
:return: 解析后的字典或None
"""
try:
# 验证基本帧格式
if len(data) < 14 or data[0:2] != b'JX' or data[2] != 0x19:
logging.warning(f"19H命令帧格式不正确原始报文: {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}"
# 提取卡号通常是ASCII字符串
card_number_start = 22
card_number_end = card_number_start + 16
card_number = data[card_number_start:card_number_end].decode('ascii').rstrip('\x00')
# 打印解析结果
print("\n19H卡鉴权上报命令解析结果:")
print(f"桩号: {pile_id_bytes.hex()}")
print(f"时间标识: {timestamp}")
print(f"卡号: {card_number}")
return {
"pile_id": pile_id_bytes.hex(),
"timestamp": timestamp,
"card_number": card_number
}
except Exception as e:
logging.error(f"解析19H命令失败: {str(e)}")
logging.error(f"原始报文: {binascii.hexlify(data)}")
return None
def generate_1a_card_auth_response(self, card_number):
"""
生成1AH卡鉴权响应命令
:param card_number: 卡号
:return: 1AH响应报文
"""
try:
# 构建帧
frame = bytearray()
frame.extend(b'JX') # 帧起始标志
frame.append(self.command_1a) # 命令码
frame.extend(bytes.fromhex('0317665611360637')) # 桩号(固定值)
frame.append(0x01) # 数据加密方式
# 构建数据域
data = bytearray()
# 时间标识(当前时间)
from datetime import datetime
now = datetime.now()
data.extend(struct.pack("<BBBBBB",
now.year - 2000, now.month, now.day,
now.hour, now.minute, now.second))
# 卡号16字节ASCII不足补0
card_number_bytes = card_number.ljust(16, '\x00').encode('ascii')
data.extend(card_number_bytes)
# 卡余额假设为0
data.extend(struct.pack("<I", 0)) # 4字节分辨率0.01元
# 允许充电标志1-可充电2-禁止充电)
data.append(0x01)
# 不可充电原因如果允许充电则为0
data.append(0x00)
# 计费模型选择1-使用本地计费模型)
data.append(0x01)
# 计费模型版本假设为1
data.extend(struct.pack("<H", 1))
# 停车费费率假设为0
data.extend(struct.pack("<I", 0))
# 时段数假设为1个
data.append(0x01)
# 第1个时段起始时间假设为全天
data.extend([0x00, 0x00]) # 起始时
# 第1个时段类型平段
data.append(0x03)
# 第1个时段电价费率假设为0.1元/kWh
data.extend(struct.pack("<I", 1000))
# 第1个时段服务费率假设为0.05元/kWh
data.extend(struct.pack("<I", 500))
# 数据域长度
frame.extend(struct.pack("<H", len(data)))
# 加入数据域
frame.extend(data)
# 计算校验码
check = 0
for b in frame[2:]:
check ^= b
frame.append(check)
print("1AH卡鉴权响应数据构建成功:")
print(f"数据内容: {frame.hex()}")
print(f"数据长度: {len(frame)}字节")
return bytes(frame)
except Exception as e:
logging.error(f"生成1AH卡鉴权响应出错: {str(e)}")
return None
def process_19_card_auth(self, data):
"""
处理19H卡鉴权上报命令
:param data: 完整的19H命令报文
:return: 是否成功处理
"""
try:
parsed_data = self.parse_19_card_auth(data)
if parsed_data is None:
logging.warning("19H命令解析失败")
return False
# 记录卡鉴权信息日志
logging.info(f"收到桩号 {parsed_data['pile_id']} 的卡鉴权请求,卡号 {parsed_data['card_number']}")
return True
except Exception as e:
logging.error(f"处理19H命令出错: {str(e)}")
return False
# 测试用例
if __name__ == "__main__":
# 19H命令测试报文
test_19_data = bytes.fromhex(
"4A 58 19 03 17 66 56 11 36 06 37 01 16 00 19 01 09 0C 15 2B 65 36 39 61 32 31 30 33 00 00 00 00 00 00 00 00 14")
# 1AH命令测试报文
test_1a_data = bytes.fromhex(
"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")
parser = Command191A()
# 测试解析19H命令
parser.process_19_card_auth(test_19_data)
# 测试生成1AH响应
card_number = "e69a21033"
response = parser.generate_1a_card_auth_response(card_number)
print("\n1AH卡鉴权响应:")
print(response.hex())