# 充电桩报文分离解析使用示例 ## 概述 系统现在支持**发送报文**和**接收报文**分开解析,然后自动合并更新到充电桩管理界面。 ## 数据流向图 ``` ┌─────────────────┐ │ 应用程序 │ └────────┬────────┘ │ 发送充电指令 ▼ ┌─────────────────────────────────────────────┐ │ CommunicationMessageService │ │ ┌─────────────────────────────────────┐ │ │ │ AddSendMessage() │ │ │ │ ├─ 记录发送报文 │ │ │ │ └─ ParseSendDataAndUpdateStation() │ │ │ │ ├─ 解析设定电压 │ │ │ │ ├─ 解析设定电流 │ │ │ │ └─ 更新充电桩设定值 │ │ │ └─────────────────────────────────────┘ │ └─────────────────┬───────────────────────────┘ │ ▼ ┌────────────────┐ │ ChargeStation │ ◄─── 设定值已更新 │ SetVoltage │ │ SetCurrent │ └────────┬───────┘ │ │ 同时... │ ┌─────────────────▼───────────────────────────┐ │ ChargeUdpService (监听端口40001) │ │ ├─ 接收充电桩返回的UDP报文 │ │ └─ 调用 AddReceiveMessage() │ └─────────────────┬───────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────┐ │ CommunicationMessageService │ │ ┌─────────────────────────────────────┐ │ │ │ AddReceiveMessage() │ │ │ │ ├─ 记录接收报文 │ │ │ │ └─ ParseReceiveDataAndUpdateStation()│ │ │ │ ├─ 解析实时电压 │ │ │ │ ├─ 解析实时电流 │ │ │ │ ├─ 解析充电状态 │ │ │ │ ├─ 解析机构状态 │ │ │ │ └─ 更新充电桩实时数据 │ │ │ └─────────────────────────────────────┘ │ └─────────────────┬───────────────────────────┘ │ ▼ ┌────────────────┐ │ ChargeStation │ ◄─── 实时值已更新 │ RealTimeVoltage│ │ RealTimeCurrent│ │ Status │ │ MechanismStatus│ └────────┬───────┘ │ ▼ ┌─────────────────────────────┐ │ ChargeStationManagementForm │ │ (每2秒自动刷新) │ │ 显示: │ │ - 设定电压 vs 实时电压 │ │ - 设定电流 vs 实时电流 │ │ - 充电状态 │ │ - 机构状态 │ └─────────────────────────────┘ ``` ## 代码示例 ### 1. 发送充电指令(自动解析发送报文) ```csharp // 在充电桩类中发送充电指令 public void StartCharging(double voltage, double current) { // 构造发送报文 byte[] sendData = new byte[10]; sendData[5] = 1; // 充电指令:启动 sendData[6] = (byte)((int)(voltage * 10) >> 8); // 设定电压高字节 sendData[7] = (byte)((int)(voltage * 10) & 0xFF); // 设定电压低字节 sendData[8] = (byte)((int)(current * 10) >> 8); // 设定电流高字节 sendData[9] = (byte)((int)(current * 10) & 0xFF); // 设定电流低字节 // 发送UDP报文 udpClient.Send(sendData, sendData.Length, endPoint); // 记录发送报文(自动解析并更新设定值) var messageService = CommunicationMessageService.Instance; messageService.AddSendMessage( ipAddress: endPoint.Address.ToString(), port: endPoint.Port, rawData: string.Join(",", sendData), stationId: this.StationId ); // ✅ 此时充电桩的 SetVoltage 和 SetCurrent 已自动更新 } ``` ### 2. 接收充电桩反馈(自动解析接收报文) ```csharp // 在 ChargeUdpService 中接收报文 private static async void ListenerProcess() { var messageService = CommunicationMessageService.Instance; using (UdpClient udpListener = new UdpClient(40001)) { while (true) { var result = await udpListener.ReceiveAsync(); var remoteEndPoint = result.RemoteEndPoint; var message = result.Buffer; // 记录接收报文(自动解析并更新实时数据) messageService.AddReceiveMessage( ipAddress: remoteEndPoint.Address.ToString(), port: 40001, rawData: string.Join(",", message) ); // ✅ 此时充电桩的实时数据已自动更新: // - RealTimeVoltage(实时电压) // - RealTimeCurrent(实时电流) // - Status(充电状态) // - MechanismStatus(机构状态) // - BatteryLevel(电量百分比) // - 等等... } } } ``` ### 3. 在充电桩管理界面查看合并后的数据 ```csharp // 在 ChargeStationManagementForm 中显示数据 private void LoadStations() { var stations = ChargeStationDataService.Instance.GetAllStations(); foreach (var station in stations) { // 显示设定值(来自发送报文解析) Console.WriteLine($"设定电压: {station.SetVoltage}V"); Console.WriteLine($"设定电流: {station.SetElectricCurrent}A"); // 显示实时值(来自接收报文解析) Console.WriteLine($"实时电压: {station.RealTimeVoltage}V"); Console.WriteLine($"实时电流: {station.RealTimeCurrent}A"); Console.WriteLine($"充电状态: {GetStatusText(station.Status)}"); Console.WriteLine($"机构状态: {GetMechanismStatusText(station.MechanismStatus)}"); Console.WriteLine($"电量: {station.BatteryLevel}%"); // 显示通讯时间 Console.WriteLine($"最后发送: {station.LastSendTime}"); Console.WriteLine($"最后接收: {station.LastReceiveTime}"); } } ``` ## 解析流程详解 ### 发送报文解析流程 ``` AddSendMessage() ↓ ParseSendDataAndUpdateStation() ↓ ParseSendRawData() ← 解析发送报文 ├─ ChargeCommand (字节5) ├─ SetVoltage (字节6-7) └─ SetCurrent (字节8-9) ↓ UpdateStationFromSendData() ← 更新设定值 ├─ station.SetVoltage = parsedData.SetVoltage ├─ station.SetElectricCurrent = parsedData.SetCurrent ├─ station.LastSendTime = parsedData.SendTime └─ station.ChargeCommandStatus = ... ``` ### 接收报文解析流程 ``` AddReceiveMessage() ↓ ParseReceiveDataAndUpdateStation() ↓ ParseReceiveRawData() ← 解析接收报文 ├─ CommStatus (字节28) ├─ ChargeCommandStatus (字节10) ├─ MechanismStatus (字节11) ├─ RealTimeVoltage (字节12-13) ├─ RealTimeCurrent (字节14-15) ├─ BatteryLevel (字节16) ├─ HasAlarm (字节20) ├─ Status (字节25) └─ CurrentVehicleId (字节26-29) ↓ UpdateStationFromReceiveData() ← 更新实时值 ├─ station.RealTimeVoltage = parsedData.RealTimeVoltage ├─ station.RealTimeCurrent = parsedData.RealTimeCurrent ├─ station.Status = parsedData.Status ├─ station.MechanismStatus = parsedData.MechanismStatus ├─ station.BatteryLevel = parsedData.BatteryLevel ├─ station.LastReceiveTime = parsedData.ReceiveTime └─ ... ``` ## 数据对比示例 | 数据项 | 来源 | 更新时机 | 用途 | |-------|------|---------|------| | SetVoltage | 发送报文 | 发送充电指令时 | 显示设定的目标电压 | | RealTimeVoltage | 接收报文 | 接收充电桩反馈时 | 显示当前实际电压 | | SetElectricCurrent | 发送报文 | 发送充电指令时 | 显示设定的目标电流 | | RealTimeCurrent | 接收报文 | 接收充电桩反馈时 | 显示当前实际电流 | | ChargeCommandStatus | 发送+接收 | 发送指令时更新,接收反馈时确认 | 显示充电指令执行状态 | | Status | 接收报文 | 接收充电桩反馈时 | 显示充电桩当前状态 | | MechanismStatus | 接收报文 | 接收充电桩反馈时 | 显示机构伸缩状态 | | BatteryLevel | 接收报文 | 接收充电桩反馈时 | 显示电池电量百分比 | | LastSendTime | 发送报文 | 发送充电指令时 | 显示最后发送时间 | | LastReceiveTime | 接收报文 | 接收充电桩反馈时 | 显示最后接收时间 | ## 优势 ✅ **数据分离**:发送和接收数据各自独立,不会互相覆盖 ✅ **完整记录**:同时保留设定值和实时值,便于对比分析 ✅ **自动合并**:系统自动将两种数据合并到同一个充电桩对象 ✅ **实时更新**:界面每2秒自动刷新,显示最新数据 ✅ **易于调试**:可以清楚看到发送的指令和接收的反馈 ## 调试技巧 ### 1. 查看报文记录 ```csharp var messageService = CommunicationMessageService.Instance; // 查看所有报文 var allMessages = messageService.GetAllMessages(); // 查看某个IP的报文 var ipMessages = messageService.GetMessagesByIp("192.168.1.101"); // 查看某个充电桩的报文 var stationMessages = messageService.GetMessagesByStationId("1"); foreach (var msg in allMessages) { Console.WriteLine($"[{msg.Direction}] {msg.IpAddress}:{msg.Port}"); Console.WriteLine($"时间: {msg.Timestamp}"); Console.WriteLine($"数据: {msg.RawData}"); Console.WriteLine("---"); } ``` ### 2. 对比设定值与实时值 ```csharp var station = ChargeStationDataService.Instance.GetStationByIp("192.168.1.101"); if (station != null) { // 电压对比 double voltageDiff = Math.Abs(station.SetVoltage - station.RealTimeVoltage); Console.WriteLine($"电压偏差: {voltageDiff}V"); // 电流对比 double currentDiff = Math.Abs(station.SetElectricCurrent - station.RealTimeCurrent); Console.WriteLine($"电流偏差: {currentDiff}A"); // 通讯延迟 if (station.LastSendTime != null && station.LastReceiveTime != null) { var delay = station.LastReceiveTime.Value - station.LastSendTime.Value; Console.WriteLine($"通讯延迟: {delay.TotalMilliseconds}ms"); } } ``` ### 3. 监控解析错误 如果数据没有更新,检查以下几点: 1. **IP地址是否匹配**:确保充电桩的IP地址在管理列表中 2. **报文长度是否足够**:发送报文至少10字节,接收报文至少30字节 3. **字节位置是否正确**:根据实际协议调整字节位置 4. **数据类型是否正确**:检查高低字节顺序、单位换算等 ## 注意事项 ⚠️ **字节位置**:示例中的字节位置仅供参考,请根据实际通讯协议调整 ⚠️ **报文格式**:确保发送和接收的报文格式与解析规则一致 ⚠️ **异常处理**:解析失败不会影响报文记录,但数据不会更新 ⚠️ **线程安全**:`CommunicationMessageService` 使用单例模式,内部已做线程同步 ## 总结 通过分离解析发送和接收报文,系统可以: - 准确记录每次发送的指令参数 - 准确获取充电桩的实时反馈 - 自动合并两种数据到充电桩管理界面 - 便于对比分析和故障诊断 这种设计使得充电桩管理更加精确和可靠!