diff --git a/PetWash.Api/petwash.db b/PetWash.Api/petwash.db
index 99322d5..78b26c0 100644
Binary files a/PetWash.Api/petwash.db and b/PetWash.Api/petwash.db differ
diff --git a/PetWashControl/Services/ModbusService.cs b/PetWashControl/Services/ModbusService.cs
index 5572a42..ab32329 100644
--- a/PetWashControl/Services/ModbusService.cs
+++ b/PetWashControl/Services/ModbusService.cs
@@ -551,4 +551,90 @@ public class ModbusService : IDisposable
}
#endregion
+
+ #region 复归型按钮控制方法
+
+ ///
+ /// 触发关闭门并开始洗护按钮 M80(复归型)
+ /// M80 是复归型按钮,需要写入脉冲信号:true → 延迟 → false
+ ///
+ public async Task TriggerStartWashAsync()
+ {
+ try
+ {
+ if (_modbusMaster != null && _isConnected)
+ {
+ const ushort START_WASH_BUTTON_ADDRESS = 80; // M80 复归型按钮
+ _logger.LogInfo($"[Modbus] 触发关闭门并开始洗护按钮 M{START_WASH_BUTTON_ADDRESS}");
+
+ // 写入 true(触发)
+ await WriteSingleCoilAsync(START_WASH_BUTTON_ADDRESS, true);
+ _logger.LogInfo($"[Modbus] M{START_WASH_BUTTON_ADDRESS} = true");
+
+ // 延迟 100ms
+ await Task.Delay(100);
+
+ // 写入 false(复位)
+ await WriteSingleCoilAsync(START_WASH_BUTTON_ADDRESS, false);
+ _logger.LogInfo($"[Modbus] M{START_WASH_BUTTON_ADDRESS} = false");
+
+ // 延迟 100ms 确保 PLC 处理完成
+ await Task.Delay(100);
+
+ _logger.LogInfo($"[Modbus] M{START_WASH_BUTTON_ADDRESS} 脉冲信号发送完成");
+ }
+ else
+ {
+ throw new InvalidOperationException("Modbus 未连接");
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError($"触发关闭门并开始洗护失败: {ex.Message}", ex);
+ throw;
+ }
+ }
+
+ ///
+ /// 触发紧急停止按钮 M83(复归型)
+ /// M83 是复归型按钮,需要写入脉冲信号:true → 延迟 → false
+ ///
+ public async Task TriggerEmergencyStopAsync()
+ {
+ try
+ {
+ if (_modbusMaster != null && _isConnected)
+ {
+ const ushort EMERGENCY_STOP_BUTTON_ADDRESS = 83; // M83 复归型按钮
+ _logger.LogInfo($"[Modbus] 触发紧急停止按钮 M{EMERGENCY_STOP_BUTTON_ADDRESS}");
+
+ // 写入 true(触发)
+ await WriteSingleCoilAsync(EMERGENCY_STOP_BUTTON_ADDRESS, true);
+ _logger.LogInfo($"[Modbus] M{EMERGENCY_STOP_BUTTON_ADDRESS} = true");
+
+ // 延迟 100ms
+ await Task.Delay(100);
+
+ // 写入 false(复位)
+ await WriteSingleCoilAsync(EMERGENCY_STOP_BUTTON_ADDRESS, false);
+ _logger.LogInfo($"[Modbus] M{EMERGENCY_STOP_BUTTON_ADDRESS} = false");
+
+ // 延迟 100ms 确保 PLC 处理完成
+ await Task.Delay(100);
+
+ _logger.LogInfo($"[Modbus] M{EMERGENCY_STOP_BUTTON_ADDRESS} 脉冲信号发送完成");
+ }
+ else
+ {
+ throw new InvalidOperationException("Modbus 未连接");
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError($"触发紧急停止失败: {ex.Message}", ex);
+ throw;
+ }
+ }
+
+ #endregion
}
diff --git a/PetWashControl/ViewModels/MainViewModel.cs b/PetWashControl/ViewModels/MainViewModel.cs
index 8d9ff38..de96ed3 100644
--- a/PetWashControl/ViewModels/MainViewModel.cs
+++ b/PetWashControl/ViewModels/MainViewModel.cs
@@ -758,7 +758,10 @@ public partial class MainViewModel : ObservableObject
try
{
- _logger.LogInfo($"关门,订单ID: {CurrentOrder.Id}");
+ _logger.LogInfo($"关门并开始洗护,订单ID: {CurrentOrder.Id}");
+
+ // 触发 Modbus M80 复归型按钮
+ await _modbusService.TriggerStartWashAsync();
// 通过MQTT发送关门状态
await _mqttService.PublishAsync("device/status", new
@@ -794,6 +797,42 @@ public partial class MainViewModel : ObservableObject
}
}
+ [RelayCommand]
+ private async Task EmergencyStopAsync()
+ {
+ try
+ {
+ _logger.LogInfo("触发紧急停止");
+
+ // 触发 Modbus M83 复归型按钮
+ await _modbusService.TriggerEmergencyStopAsync();
+
+ // 停止洗护流程
+ IsWashing = false;
+
+ // 通过MQTT发送紧急停止状态
+ await _mqttService.PublishAsync("device/status", new
+ {
+ status = "emergency_stop",
+ orderId = CurrentOrder?.Id,
+ timestamp = DateTime.Now
+ });
+
+ StatusMessage = "紧急停止已触发";
+ _logger.LogInfo("紧急停止执行成功");
+
+ MessageBox.Show("紧急停止已触发!\n\n设备已停止运行",
+ "紧急停止", MessageBoxButton.OK, MessageBoxImage.Warning);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError("紧急停止失败", ex);
+ StatusMessage = $"紧急停止失败: {ex.Message}";
+ MessageBox.Show($"紧急停止失败\n\n{ex.Message}", "错误",
+ MessageBoxButton.OK, MessageBoxImage.Error);
+ }
+ }
+
private async Task SimulateWashingProcessAsync()
{
try
diff --git a/PetWashControl/Views/MainWindow.xaml b/PetWashControl/Views/MainWindow.xaml
index 0e968ed..7a17411 100644
--- a/PetWashControl/Views/MainWindow.xaml
+++ b/PetWashControl/Views/MainWindow.xaml
@@ -1337,7 +1337,8 @@
Foreground="White"
BorderThickness="0"
Margin="0,20,0,0"
- Cursor="Hand">
+ Cursor="Hand"
+ Command="{Binding EmergencyStopCommand}">