13 KiB
13 KiB
充电桩报文分离解析使用示例
概述
系统现在支持发送报文和接收报文分开解析,然后自动合并更新到充电桩管理界面。
数据流向图
┌─────────────────┐
│ 应用程序 │
└────────┬────────┘
│ 发送充电指令
▼
┌─────────────────────────────────────────────┐
│ CommunicationMessageService │
│ ┌─────────────────────────────────────┐ │
│ │ AddSendMessage() │ │
│ │ ├─ 记录发送报文 │ │
│ │ └─ ParseSendDataAndUpdateStation() │ │
│ │ ├─ 解析设定电压 │ │
│ │ ├─ 解析设定电流 │ │
│ │ └─ 更新充电桩设定值 │ │
│ └─────────────────────────────────────┘ │
└─────────────────┬───────────────────────────┘
│
▼
┌────────────────┐
│ ChargeStation │ ◄─── 设定值已更新
│ SetVoltage │
│ SetCurrent │
└────────┬───────┘
│
│ 同时...
│
┌─────────────────▼───────────────────────────┐
│ ChargeUdpService (监听端口40001) │
│ ├─ 接收充电桩返回的UDP报文 │
│ └─ 调用 AddReceiveMessage() │
└─────────────────┬───────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ CommunicationMessageService │
│ ┌─────────────────────────────────────┐ │
│ │ AddReceiveMessage() │ │
│ │ ├─ 记录接收报文 │ │
│ │ └─ ParseReceiveDataAndUpdateStation()│ │
│ │ ├─ 解析实时电压 │ │
│ │ ├─ 解析实时电流 │ │
│ │ ├─ 解析充电状态 │ │
│ │ ├─ 解析机构状态 │ │
│ │ └─ 更新充电桩实时数据 │ │
│ └─────────────────────────────────────┘ │
└─────────────────┬───────────────────────────┘
│
▼
┌────────────────┐
│ ChargeStation │ ◄─── 实时值已更新
│ RealTimeVoltage│
│ RealTimeCurrent│
│ Status │
│ MechanismStatus│
└────────┬───────┘
│
▼
┌─────────────────────────────┐
│ ChargeStationManagementForm │
│ (每2秒自动刷新) │
│ 显示: │
│ - 设定电压 vs 实时电压 │
│ - 设定电流 vs 实时电流 │
│ - 充电状态 │
│ - 机构状态 │
└─────────────────────────────┘
代码示例
1. 发送充电指令(自动解析发送报文)
// 在充电桩类中发送充电指令
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. 接收充电桩反馈(自动解析接收报文)
// 在 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. 在充电桩管理界面查看合并后的数据
// 在 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. 查看报文记录
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. 对比设定值与实时值
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. 监控解析错误
如果数据没有更新,检查以下几点:
- IP地址是否匹配:确保充电桩的IP地址在管理列表中
- 报文长度是否足够:发送报文至少10字节,接收报文至少30字节
- 字节位置是否正确:根据实际协议调整字节位置
- 数据类型是否正确:检查高低字节顺序、单位换算等
注意事项
⚠️ 字节位置:示例中的字节位置仅供参考,请根据实际通讯协议调整
⚠️ 报文格式:确保发送和接收的报文格式与解析规则一致
⚠️ 异常处理:解析失败不会影响报文记录,但数据不会更新
⚠️ 线程安全:CommunicationMessageService 使用单例模式,内部已做线程同步
总结
通过分离解析发送和接收报文,系统可以:
- 准确记录每次发送的指令参数
- 准确获取充电桩的实时反馈
- 自动合并两种数据到充电桩管理界面
- 便于对比分析和故障诊断
这种设计使得充电桩管理更加精确和可靠!