Files
StandardSence/StandardScene.Core/Docs/Charge/报文解析使用示例.md
T
2026-06-14 11:19:15 +08:00

321 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 充电桩报文分离解析使用示例
## 概述
系统现在支持**发送报文**和**接收报文**分开解析,然后自动合并更新到充电桩管理界面。
## 数据流向图
```
┌─────────────────┐
│ 应用程序 │
└────────┬────────┘
│ 发送充电指令
┌─────────────────────────────────────────────┐
│ 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` 使用单例模式,内部已做线程同步
## 总结
通过分离解析发送和接收报文,系统可以:
- 准确记录每次发送的指令参数
- 准确获取充电桩的实时反馈
- 自动合并两种数据到充电桩管理界面
- 便于对比分析和故障诊断
这种设计使得充电桩管理更加精确和可靠!