Files
petwash/MODBUS_INTEGRATION.md
GukSang.Jin 9c66b6cd82
2026-03-03 16:55:02 +08:00

253 lines
6.9 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.
# Modbus TCP 设备集成说明
## 概述
系统已集成 Modbus TCP 通信功能,用于与洗宠设备进行实时通信和控制。使用 NModbus 3.0.81 库实现,支持生产环境部署。
## 配置参数
`ConfigurationService.cs` 中配置 Modbus TCP 连接参数:
```csharp
// Modbus TCP 配置
public string ModbusIpAddress { get; set; } = "192.168.1.10"; // 设备 IP 地址
public int ModbusPort { get; set; } = 502; // Modbus TCP 端口
public byte ModbusSlaveId { get; set; } = 1; // 从站 ID
public int ModbusConnectTimeoutMs { get; set; } = 5000; // 连接超时(毫秒)
public int ModbusReadTimeoutMs { get; set; } = 3000; // 读写超时(毫秒)
```
## 功能特性
### 1. 自动连接与重连
- 系统初始化时自动连接设备
- 连接失败时自动重试
- 心跳检测每10秒确保连接稳定
- 连接断开时自动尝试重连
### 2. 连接状态监控
- `IsModbusConnected` 属性实时反映连接状态
- `ConnectionStatusChanged` 事件通知连接状态变化
- 界面显示连接状态提示
### 3. 完整的 Modbus 功能
#### 读取操作
```csharp
// 读取保持寄存器
ushort[] values = await _modbusService.ReadHoldingRegistersAsync(startAddress, count);
// 读取输入寄存器
ushort[] inputs = await _modbusService.ReadInputRegistersAsync(startAddress, count);
// 读取线圈状态
bool[] coils = await _modbusService.ReadCoilsAsync(startAddress, count);
```
#### 写入操作
```csharp
// 写入单个寄存器
await _modbusService.WriteSingleRegisterAsync(address, value);
// 写入多个寄存器
await _modbusService.WriteMultipleRegistersAsync(startAddress, values);
// 写入单个线圈
await _modbusService.WriteSingleCoilAsync(address, true);
// 写入多个线圈
await _modbusService.WriteMultipleCoilsAsync(startAddress, coilStates);
```
## 使用示例
### 在 MainViewModel 中使用
```csharp
// 1. 读取设备温度(假设温度存储在寄存器地址 100
try
{
var tempData = await _modbusService.ReadHoldingRegistersAsync(100, 1);
WaterTemperature = tempData[0] / 10.0; // 假设温度值需要除以10
}
catch (Exception ex)
{
_logger.LogError("读取温度失败", ex);
}
// 2. 控制设备门(假设门控制在线圈地址 0
try
{
await _modbusService.WriteSingleCoilAsync(0, true); // 打开门
IsDoorOpen = true;
}
catch (Exception ex)
{
_logger.LogError("控制门失败", ex);
}
// 3. 启动洗护流程(假设控制寄存器在地址 200
try
{
ushort[] controlData = new ushort[] { 1, 30 }; // 启动30分钟
await _modbusService.WriteMultipleRegistersAsync(200, controlData);
}
catch (Exception ex)
{
_logger.LogError("启动洗护失败", ex);
}
// 4. 读取液位传感器(假设在输入寄存器 300-302
try
{
var levels = await _modbusService.ReadInputRegistersAsync(300, 3);
Shampoo1Level = levels[0];
Shampoo2Level = levels[1];
Shampoo3Level = levels[2];
}
catch (Exception ex)
{
_logger.LogError("读取液位失败", ex);
}
```
## 设备地址映射示例
根据实际设备的 Modbus 地址映射表进行配置:
### 保持寄存器(读写)
| 地址 | 功能 | 数据类型 | 说明 |
|------|------|----------|------|
| 0 | 系统状态 | UINT16 | 0=待机, 1=运行, 2=故障 |
| 100 | 水温设定 | UINT16 | 单位0.1°C |
| 101 | 室温设定 | UINT16 | 单位0.1°C |
| 200 | 流程控制 | UINT16 | 0=停止, 1=启动 |
| 201 | 流程时长 | UINT16 | 单位:分钟 |
### 输入寄存器(只读)
| 地址 | 功能 | 数据类型 | 说明 |
|------|------|----------|------|
| 100 | 当前水温 | UINT16 | 单位0.1°C |
| 101 | 当前室温 | UINT16 | 单位0.1°C |
| 300 | 沐浴露1液位 | UINT16 | 0-100% |
| 301 | 沐浴露2液位 | UINT16 | 0-100% |
| 302 | 沐浴露3液位 | UINT16 | 0-100% |
### 线圈(读写)
| 地址 | 功能 | 说明 |
|------|------|------|
| 0 | 门控制 | 0=关闭, 1=打开 |
| 1 | 喷水阀 | 0=关闭, 1=打开 |
| 2 | 热风机 | 0=关闭, 1=打开 |
| 3 | 冷风机 | 0=关闭, 1=打开 |
| 4 | 紫外线灯 | 0=关闭, 1=打开 |
## 错误处理
### 连接错误
- 连接超时:检查网络连接和设备 IP 地址
- 连接被拒绝:检查设备是否启用 Modbus TCP 服务
- 设备无响应:检查从站 ID 是否正确
### 读写错误
- 非法地址:检查寄存器地址是否在设备支持范围内
- 非法数据值:检查写入的数据是否符合设备要求
- 超时:增加 `ModbusReadTimeoutMs`
## 日志记录
所有 Modbus 操作都会记录到日志系统:
```
[INFO] 正在连接 Modbus TCP 设备: 192.168.1.10:502
[INFO] Modbus TCP 连接成功: 192.168.1.10:502
[INFO] 读取保持寄存器成功: 地址=100, 数量=1
[INFO] 写入单个线圈成功: 地址=0, 值=True
[ERROR] 读取保持寄存器失败: 地址=100
[WARNING] 心跳检测: 连接已断开,尝试重连...
```
## 生产环境部署建议
### 1. 网络配置
- 确保控制端与设备在同一网络或可路由网络
- 配置静态 IP 地址避免地址变化
- 使用专用网络隔离 Modbus 通信
### 2. 超时设置
- 根据网络延迟调整超时参数
- 局域网环境:连接超时 3-5 秒,读写超时 1-3 秒
- 跨网段环境:适当增加超时时间
### 3. 错误恢复
- 启用自动重连机制(已实现)
- 监控连接状态并记录日志
- 设置告警通知管理员
### 4. 性能优化
- 批量读写操作使用 `ReadMultiple``WriteMultiple` 方法
- 避免频繁的单个寄存器读写
- 合理设置心跳检测间隔
### 5. 安全考虑
- 使用防火墙限制 Modbus TCP 端口访问
- 实施访问控制和身份验证
- 定期更新设备固件
## 测试验证
### 1. 连接测试
```csharp
// 测试基本连接
var connected = await _modbusService.ConnectAsync();
Assert.IsTrue(connected);
Assert.IsTrue(_modbusService.IsConnected);
```
### 2. 读写测试
```csharp
// 测试读取
var data = await _modbusService.ReadHoldingRegistersAsync(0, 1);
Assert.IsNotNull(data);
// 测试写入
await _modbusService.WriteSingleRegisterAsync(0, 100);
var verify = await _modbusService.ReadHoldingRegistersAsync(0, 1);
Assert.AreEqual(100, verify[0]);
```
### 3. 断线重连测试
- 断开网络连接
- 观察日志中的重连尝试
- 恢复网络连接
- 验证自动重连成功
## 故障排查
### 问题:无法连接设备
1. 检查设备 IP 和端口是否正确
2. 使用 ping 命令测试网络连通性
3. 使用 Modbus 测试工具验证设备响应
4. 检查防火墙设置
### 问题:连接频繁断开
1. 检查网络稳定性
2. 增加超时时间
3. 检查设备负载
4. 查看设备日志
### 问题:读写操作失败
1. 验证寄存器地址是否正确
2. 检查从站 ID 配置
3. 确认数据格式符合设备要求
4. 查看详细错误日志
## 技术支持
如遇到问题,请提供以下信息:
- 设备型号和固件版本
- 网络拓扑结构
- 完整的错误日志
- Modbus 地址映射表
- 问题复现步骤