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
|
|
|
|
|
|
|
|
2025-01-18 13:41:57 +08:00
|
|
|
class CommandHeartbeat:
|
2025-01-18 09:10:52 +08:00
|
|
|
def __init__(self):
|
|
|
|
self.command_0c = 0x0C # 桩心跳命令
|
2025-01-18 13:41:57 +08:00
|
|
|
self.command_0b = 0x0B # 平台心跳命令
|
2025-01-18 09:10:52 +08:00
|
|
|
|
|
|
|
def parse_0c_heartbeat(self, data):
|
2025-01-18 13:41:57 +08:00
|
|
|
"""解析0CH心跳命令"""
|
2025-01-18 09:10:52 +08:00
|
|
|
try:
|
2025-01-18 13:41:57 +08:00
|
|
|
print("\n开始解析0CH心跳命令...")
|
|
|
|
print(f"接收数据: {data.hex().upper()}")
|
|
|
|
|
|
|
|
# 基础验证
|
|
|
|
if len(data) < 14 or data[0:2] != b'JX' or data[2] != self.command_0c:
|
|
|
|
logging.warning("0CH命令帧格式不正确")
|
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
|
|
|
# 解析心跳数据
|
|
|
|
platform_timeout_count = data_field[6] # 平台心跳超时次数
|
|
|
|
gun_count = data_field[7] # 充电枪数量
|
|
|
|
gun_status = data_field[8] # 充电枪状态
|
|
|
|
work_mode = data_field[9] # 工作模式
|
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
|
|
|
"platform_timeout_count": platform_timeout_count,
|
2025-01-18 09:10:52 +08:00
|
|
|
"gun_count": gun_count,
|
2025-01-18 13:41:57 +08:00
|
|
|
"gun_status": gun_status,
|
|
|
|
"work_mode": work_mode
|
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"平台心跳超时次数: {platform_timeout_count}")
|
|
|
|
print(f"充电枪数量: {gun_count}")
|
|
|
|
print(f"充电枪状态: {gun_status:02X}")
|
|
|
|
print(f"工作模式: {work_mode:02X}")
|
|
|
|
|
|
|
|
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"解析0CH心跳命令失败: {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_0b_heartbeat(self, pile_id):
|
|
|
|
"""构建0BH心跳响应"""
|
2025-01-18 09:10:52 +08:00
|
|
|
try:
|
2025-01-18 13:41:57 +08:00
|
|
|
print("\n构建0BH心跳响应...")
|
|
|
|
|
2025-01-18 09:10:52 +08:00
|
|
|
frame = bytearray()
|
|
|
|
frame.extend(b'JX') # 帧起始标志
|
2025-01-18 13:41:57 +08:00
|
|
|
frame.append(self.command_0b) # 命令码0BH
|
|
|
|
frame.extend(pile_id) # 桩号
|
|
|
|
frame.append(0x01) # 数据加密方式(不加密)
|
2025-01-18 09:10:52 +08:00
|
|
|
|
|
|
|
# 构建数据域
|
|
|
|
data = bytearray()
|
|
|
|
|
2025-01-18 13:41:57 +08:00
|
|
|
# 添加时间标识
|
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
|
|
|
# 添加桩心跳超时次数(例如设为0)
|
2025-01-18 09:10:52 +08:00
|
|
|
data.append(0x00)
|
|
|
|
|
2025-01-18 13:41:57 +08:00
|
|
|
# 计算数据长度
|
|
|
|
data_len = len(data)
|
|
|
|
frame.extend(struct.pack("<H", data_len)) # 数据长度
|
2025-01-18 09:10:52 +08:00
|
|
|
|
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"构建0BH心跳响应失败: {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):
|
|
|
|
"""处理收到的0CH命令并回复0BH"""
|
2025-01-18 09:10:52 +08:00
|
|
|
try:
|
2025-01-18 13:41:57 +08:00
|
|
|
print("\n处理心跳命令...")
|
|
|
|
|
|
|
|
# 解析接收到的0CH命令
|
|
|
|
parsed = self.parse_0c_heartbeat(received_data)
|
|
|
|
if not parsed:
|
|
|
|
return False
|
2025-01-18 09:10:52 +08:00
|
|
|
|
2025-01-18 13:41:57 +08:00
|
|
|
# 构建0BH响应
|
|
|
|
response = self.build_0b_heartbeat(parsed["pile_id"])
|
|
|
|
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_heartbeat():
|
|
|
|
"""测试心跳命令处理"""
|
|
|
|
print("开始测试心跳命令处理...")
|
|
|
|
|
|
|
|
# 创建处理器
|
|
|
|
handler = CommandHeartbeat()
|
2025-01-18 09:10:52 +08:00
|
|
|
|
2025-01-18 13:41:57 +08:00
|
|
|
# 测试数据 - 使用实际收到的0CH数据
|
|
|
|
test_data = bytes.fromhex("4A580C0317665611360637010C001901090B25240102010101012B")
|
2025-01-18 09:10:52 +08:00
|
|
|
|
2025-01-18 13:41:57 +08:00
|
|
|
print("\n测试数据:")
|
|
|
|
print(f"0CH数据: {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"0BH数据: {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_heartbeat()
|