|
|
@@ -0,0 +1,416 @@
|
|
|
+using CommunityToolkit.Mvvm.ComponentModel;
|
|
|
+using CommunityToolkit.Mvvm.Input;
|
|
|
+using Serilog;
|
|
|
+using YZWater.Core.Models;
|
|
|
+using YZWater.Core.Services;
|
|
|
+
|
|
|
+namespace YZWater.Core.ViewModels;
|
|
|
+
|
|
|
+/// <summary>
|
|
|
+/// 涓诲伐鑹鸿鍥 ViewModel
|
|
|
+/// </summary>
|
|
|
+public partial class ViewAViewModel : ObservableObject
|
|
|
+{
|
|
|
+ // 娑蹭綅鏁版嵁
|
|
|
+ [ObservableProperty]
|
|
|
+ private float _tank1Level = 50f;
|
|
|
+
|
|
|
+ [ObservableProperty]
|
|
|
+ private float _tank2Level = 60f;
|
|
|
+
|
|
|
+ [ObservableProperty]
|
|
|
+ private float _tank3Level = 70f;
|
|
|
+
|
|
|
+ [ObservableProperty]
|
|
|
+ private float _tank4Level = 45f;
|
|
|
+
|
|
|
+ // 娴侀噺鏁版嵁
|
|
|
+ [ObservableProperty]
|
|
|
+ private float _inflowRate = 25.5f;
|
|
|
+
|
|
|
+ [ObservableProperty]
|
|
|
+ private float _outflowRate = 22.3f;
|
|
|
+
|
|
|
+ // 娉电姸鎬
|
|
|
+ [ObservableProperty]
|
|
|
+ private bool _pump1Running;
|
|
|
+
|
|
|
+ [ObservableProperty]
|
|
|
+ private bool _pump2Running;
|
|
|
+
|
|
|
+ [ObservableProperty]
|
|
|
+ private bool _pump3Running;
|
|
|
+
|
|
|
+ [ObservableProperty]
|
|
|
+ private bool _pump4Running;
|
|
|
+
|
|
|
+ [ObservableProperty]
|
|
|
+ private bool _pump5Running;
|
|
|
+
|
|
|
+ // 椋庢墖鐘舵
|
|
|
+ [ObservableProperty]
|
|
|
+ private bool _fan1Running;
|
|
|
+
|
|
|
+ [ObservableProperty]
|
|
|
+ private bool _fan2Running;
|
|
|
+
|
|
|
+ // 闃闂ㄧ姸鎬
|
|
|
+ [ObservableProperty]
|
|
|
+ private ValveStatus _valve1Status = ValveStatus.Middle;
|
|
|
+
|
|
|
+ [ObservableProperty]
|
|
|
+ private ValveStatus _valve2Status = ValveStatus.Middle;
|
|
|
+
|
|
|
+ [ObservableProperty]
|
|
|
+ private ValveStatus _valve3Status = ValveStatus.Middle;
|
|
|
+
|
|
|
+ [ObservableProperty]
|
|
|
+ private ValveStatus _valve4Status = ValveStatus.Middle;
|
|
|
+
|
|
|
+ [ObservableProperty]
|
|
|
+ private ValveStatus _valve5Status = ValveStatus.Middle;
|
|
|
+
|
|
|
+ // 妯″紡鐘舵
|
|
|
+ [ObservableProperty]
|
|
|
+ private ValveStatus _modeStatus = ValveStatus.Middle;
|
|
|
+
|
|
|
+ // 娴佸姩鐘舵
|
|
|
+ [ObservableProperty]
|
|
|
+ private bool _isInflowRunning = true;
|
|
|
+
|
|
|
+ [ObservableProperty]
|
|
|
+ private bool _isOutflowRunning = true;
|
|
|
+
|
|
|
+ // 璁惧鐘舵侀鑹
|
|
|
+ [ObservableProperty]
|
|
|
+ private string _pump1StatusColor = "#4CAF50";
|
|
|
+
|
|
|
+ [ObservableProperty]
|
|
|
+ private string _pump2StatusColor = "#4CAF50";
|
|
|
+
|
|
|
+ [ObservableProperty]
|
|
|
+ private string _pump3StatusColor = "#4CAF50";
|
|
|
+
|
|
|
+ [ObservableProperty]
|
|
|
+ private string _pump4StatusColor = "#4CAF50";
|
|
|
+
|
|
|
+ [ObservableProperty]
|
|
|
+ private string _pump5StatusColor = "#4CAF50";
|
|
|
+
|
|
|
+ [ObservableProperty]
|
|
|
+ private string _fan1StatusColor = "#4CAF50";
|
|
|
+
|
|
|
+ [ObservableProperty]
|
|
|
+ private string _fan2StatusColor = "#4CAF50";
|
|
|
+
|
|
|
+ // 鎶ヨ鐘舵
|
|
|
+ [ObservableProperty]
|
|
|
+ private bool _hasAlarm;
|
|
|
+
|
|
|
+ [ObservableProperty]
|
|
|
+ private string _alarmMessage = string.Empty;
|
|
|
+
|
|
|
+ // 杩炴帴鐘舵
|
|
|
+ [ObservableProperty]
|
|
|
+ private bool _isPlcConnected;
|
|
|
+
|
|
|
+ public ViewAViewModel()
|
|
|
+ {
|
|
|
+ StartDataRefresh();
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 鍚姩鏁版嵁鍒锋柊
|
|
|
+ /// </summary>
|
|
|
+ private void StartDataRefresh()
|
|
|
+ {
|
|
|
+ var timer = new System.Timers.Timer(1000);
|
|
|
+ timer.Elapsed += async (s, e) =>
|
|
|
+ {
|
|
|
+ await RefreshDataAsync();
|
|
|
+ };
|
|
|
+ timer.Start();
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 鍒锋柊 PLC 鏁版嵁
|
|
|
+ /// </summary>
|
|
|
+ [RelayCommand]
|
|
|
+ private async Task RefreshDataAsync()
|
|
|
+ {
|
|
|
+ if (!PlcService.IsConnected) return;
|
|
|
+
|
|
|
+ try
|
|
|
+ {
|
|
|
+ // 璇诲彇娑蹭綅鏁版嵁
|
|
|
+ Tank1Level = await PlcService.ReadFloatAsync("VD100");
|
|
|
+ Tank2Level = await PlcService.ReadFloatAsync("VD104");
|
|
|
+ Tank3Level = await PlcService.ReadFloatAsync("VD108");
|
|
|
+ Tank4Level = await PlcService.ReadFloatAsync("VD112");
|
|
|
+
|
|
|
+ // 璇诲彇娴侀噺鏁版嵁
|
|
|
+ InflowRate = await PlcService.ReadFloatAsync("VD200");
|
|
|
+ OutflowRate = await PlcService.ReadFloatAsync("VD204");
|
|
|
+
|
|
|
+ // 璇诲彇娉电姸鎬
|
|
|
+ Pump1Running = await PlcService.ReadBoolAsync("Q0.0");
|
|
|
+ Pump2Running = await PlcService.ReadBoolAsync("Q0.1");
|
|
|
+ Pump3Running = await PlcService.ReadBoolAsync("Q0.2");
|
|
|
+ Pump4Running = await PlcService.ReadBoolAsync("Q0.3");
|
|
|
+ Pump5Running = await PlcService.ReadBoolAsync("Q0.4");
|
|
|
+
|
|
|
+ // 璇诲彇椋庢墖鐘舵
|
|
|
+ Fan1Running = await PlcService.ReadBoolAsync("Q0.5");
|
|
|
+ Fan2Running = await PlcService.ReadBoolAsync("Q0.6");
|
|
|
+
|
|
|
+ // 鏇存柊璁惧鐘舵侀鑹
|
|
|
+ UpdateDeviceStatusColors();
|
|
|
+
|
|
|
+ // 妫鏌ユ姤璀
|
|
|
+ CheckAlarms();
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ Log.Error(ex, "鍒锋柊 PLC 鏁版嵁澶辫触");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 鏇存柊璁惧鐘舵侀鑹
|
|
|
+ /// </summary>
|
|
|
+ private void UpdateDeviceStatusColors()
|
|
|
+ {
|
|
|
+ Pump1StatusColor = Pump1Running ? "#4CAF50" : "#F44336";
|
|
|
+ Pump2StatusColor = Pump2Running ? "#4CAF50" : "#F44336";
|
|
|
+ Pump3StatusColor = Pump3Running ? "#4CAF50" : "#F44336";
|
|
|
+ Pump4StatusColor = Pump4Running ? "#4CAF50" : "#F44336";
|
|
|
+ Pump5StatusColor = Pump5Running ? "#4CAF50" : "#F44336";
|
|
|
+ Fan1StatusColor = Fan1Running ? "#4CAF50" : "#F44336";
|
|
|
+ Fan2StatusColor = Fan2Running ? "#4CAF50" : "#F44336";
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 妫鏌ユ姤璀︽潯浠
|
|
|
+ /// </summary>
|
|
|
+ private void CheckAlarms()
|
|
|
+ {
|
|
|
+ var config = ConfigService.GetConfig();
|
|
|
+ if (config == null) return;
|
|
|
+
|
|
|
+ HasAlarm = false;
|
|
|
+ AlarmMessage = string.Empty;
|
|
|
+
|
|
|
+ if (Tank1Level > config.LevelHighAlarm)
|
|
|
+ {
|
|
|
+ HasAlarm = true;
|
|
|
+ AlarmMessage = "1鍙锋按姹犳恫浣嶈繃楂";
|
|
|
+ }
|
|
|
+ else if (Tank1Level < config.LevelLowAlarm)
|
|
|
+ {
|
|
|
+ HasAlarm = true;
|
|
|
+ AlarmMessage = "1鍙锋按姹犳恫浣嶈繃浣";
|
|
|
+ }
|
|
|
+
|
|
|
+ if (InflowRate > config.FlowHighAlarm)
|
|
|
+ {
|
|
|
+ HasAlarm = true;
|
|
|
+ AlarmMessage = "杩涙按娴侀噺杩囬珮";
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 杩炴帴 PLC
|
|
|
+ /// </summary>
|
|
|
+ [RelayCommand]
|
|
|
+ private async Task ConnectPlcAsync()
|
|
|
+ {
|
|
|
+ IsPlcConnected = await PlcService.ConnectAsync();
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 鏂紑 PLC
|
|
|
+ /// </summary>
|
|
|
+ [RelayCommand]
|
|
|
+ private void DisconnectPlc()
|
|
|
+ {
|
|
|
+ PlcService.Disconnect();
|
|
|
+ IsPlcConnected = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 鎺у埗娉
|
|
|
+ /// </summary>
|
|
|
+ [RelayCommand]
|
|
|
+ private async Task TogglePumpAsync(string pumpId)
|
|
|
+ {
|
|
|
+ if (!PlcService.IsConnected)
|
|
|
+ {
|
|
|
+ Log.Warning("PLC 鏈繛鎺ワ紝鏃犳硶鎺у埗娉");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ var address = pumpId switch
|
|
|
+ {
|
|
|
+ "P001" => "Q0.0",
|
|
|
+ "P002" => "Q0.1",
|
|
|
+ "P003" => "Q0.2",
|
|
|
+ "P004" => "Q0.3",
|
|
|
+ "P005" => "Q0.4",
|
|
|
+ _ => throw new ArgumentException($"鏈煡鐨勬车 ID: {pumpId}")
|
|
|
+ };
|
|
|
+
|
|
|
+ var currentState = pumpId switch
|
|
|
+ {
|
|
|
+ "P001" => Pump1Running,
|
|
|
+ "P002" => Pump2Running,
|
|
|
+ "P003" => Pump3Running,
|
|
|
+ "P004" => Pump4Running,
|
|
|
+ "P005" => Pump5Running,
|
|
|
+ _ => false
|
|
|
+ };
|
|
|
+
|
|
|
+ var success = await PlcService.WriteBoolAsync(address, !currentState);
|
|
|
+ if (success)
|
|
|
+ {
|
|
|
+ Log.Information("娉 {PumpId} 鐘舵佸凡鍒囨崲", pumpId);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 鎺у埗椋庢墖
|
|
|
+ /// </summary>
|
|
|
+ [RelayCommand]
|
|
|
+ private async Task ToggleFanAsync(string fanId)
|
|
|
+ {
|
|
|
+ if (!PlcService.IsConnected)
|
|
|
+ {
|
|
|
+ Log.Warning("PLC 鏈繛鎺ワ紝鏃犳硶鎺у埗椋庢墖");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ var address = fanId switch
|
|
|
+ {
|
|
|
+ "F001" => "Q0.5",
|
|
|
+ "F002" => "Q0.6",
|
|
|
+ _ => throw new ArgumentException($"鏈煡鐨勯鎵 ID: {fanId}")
|
|
|
+ };
|
|
|
+
|
|
|
+ var currentState = fanId switch
|
|
|
+ {
|
|
|
+ "F001" => Fan1Running,
|
|
|
+ "F002" => Fan2Running,
|
|
|
+ _ => false
|
|
|
+ };
|
|
|
+
|
|
|
+ var success = await PlcService.WriteBoolAsync(address, !currentState);
|
|
|
+ if (success)
|
|
|
+ {
|
|
|
+ Log.Information("椋庢墖 {FanId} 鐘舵佸凡鍒囨崲", fanId);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 鎺у埗闃闂
|
|
|
+ /// </summary>
|
|
|
+ [RelayCommand]
|
|
|
+ private async Task ToggleValveAsync(string valveId)
|
|
|
+ {
|
|
|
+ if (!PlcService.IsConnected)
|
|
|
+ {
|
|
|
+ Log.Warning("PLC 鏈繛鎺ワ紝鏃犳硶鎺у埗闃闂");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ var address = valveId switch
|
|
|
+ {
|
|
|
+ "V001" => "Q1.0",
|
|
|
+ "V002" => "Q1.1",
|
|
|
+ "V003" => "Q1.2",
|
|
|
+ "V004" => "Q1.3",
|
|
|
+ "V005" => "Q1.4",
|
|
|
+ _ => throw new ArgumentException($"鏈煡鐨勯榾闂 ID: {valveId}")
|
|
|
+ };
|
|
|
+
|
|
|
+ var currentStatus = valveId switch
|
|
|
+ {
|
|
|
+ "V001" => Valve1Status,
|
|
|
+ "V002" => Valve2Status,
|
|
|
+ "V003" => Valve3Status,
|
|
|
+ "V004" => Valve4Status,
|
|
|
+ "V005" => Valve5Status,
|
|
|
+ _ => ValveStatus.Middle
|
|
|
+ };
|
|
|
+
|
|
|
+ // 寰幆鍒囨崲鐘舵: 鍏抽棴 -> 涓棿 -> 鎵撳紑 -> 鍏抽棴
|
|
|
+ var newStatus = currentStatus switch
|
|
|
+ {
|
|
|
+ ValveStatus.Closed => ValveStatus.Middle,
|
|
|
+ ValveStatus.Middle => ValveStatus.Open,
|
|
|
+ ValveStatus.Open => ValveStatus.Closed,
|
|
|
+ _ => ValveStatus.Middle
|
|
|
+ };
|
|
|
+
|
|
|
+ var success = await PlcService.WriteBoolAsync(address, newStatus == ValveStatus.Open);
|
|
|
+ if (success)
|
|
|
+ {
|
|
|
+ switch (valveId)
|
|
|
+ {
|
|
|
+ case "V001": Valve1Status = newStatus; break;
|
|
|
+ case "V002": Valve2Status = newStatus; break;
|
|
|
+ case "V003": Valve3Status = newStatus; break;
|
|
|
+ case "V004": Valve4Status = newStatus; break;
|
|
|
+ case "V005": Valve5Status = newStatus; break;
|
|
|
+ }
|
|
|
+ Log.Information("闃闂 {ValveId} 鐘舵佸凡鍒囨崲涓 {Status}", valveId, newStatus);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 鍒囨崲妯″紡
|
|
|
+ /// </summary>
|
|
|
+ [RelayCommand]
|
|
|
+ private async Task ToggleModeAsync()
|
|
|
+ {
|
|
|
+ if (!PlcService.IsConnected)
|
|
|
+ {
|
|
|
+ Log.Warning("PLC 鏈繛鎺ワ紝鏃犳硶鍒囨崲妯″紡");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ var newStatus = ModeStatus switch
|
|
|
+ {
|
|
|
+ ValveStatus.Closed => ValveStatus.Middle,
|
|
|
+ ValveStatus.Middle => ValveStatus.Open,
|
|
|
+ ValveStatus.Open => ValveStatus.Closed,
|
|
|
+ _ => ValveStatus.Middle
|
|
|
+ };
|
|
|
+
|
|
|
+ var success = await PlcService.WriteBoolAsync("M0.0", newStatus == ValveStatus.Open);
|
|
|
+ if (success)
|
|
|
+ {
|
|
|
+ ModeStatus = newStatus;
|
|
|
+ Log.Information("妯″紡宸插垏鎹负: {Status}", newStatus);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/// <summary>
|
|
|
+/// 闃闂ㄧ姸鎬佹灇涓
|
|
|
+/// </summary>
|
|
|
+public enum ValveStatus
|
|
|
+{
|
|
|
+ /// <summary>
|
|
|
+ /// 鍏抽棴
|
|
|
+ /// </summary>
|
|
|
+ Closed,
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 涓棿浣嶇疆
|
|
|
+ /// </summary>
|
|
|
+ Middle,
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 鎵撳紑
|
|
|
+ /// </summary>
|
|
|
+ Open
|
|
|
+}
|