Эх сурвалжийг харах

feat: 新增报警来源配置,防止上位机与PLC重复报警

- AlarmThresholds 新增 AlarmSource 字段(PLC/Host/Both,默认PLC)
- AlarmService.CheckAlarmsFromProfile 按 AlarmSource 分支检查
- 杨杰项目配置 alarmSource: PLC,只走DI报警
- PLC通信中断检测不受影响,始终由上位机判断
DESKTOP-74CLTRG\Leol 1 сар өмнө
parent
commit
9254b0e53a

+ 1 - 0
projects/yangjie2.json

@@ -140,6 +140,7 @@
     }
   ],
   "alarmThresholds": {
+    "alarmSource": "PLC",
     "pressureHigh": 1.2,
     "pressureLow": 0.1
   }

+ 9 - 0
src/YZWater.Core/Models/ProjectProfile.cs

@@ -260,6 +260,15 @@ public class DigitalOutputConfig
 /// </summary>
 public class AlarmThresholds
 {
+    /// <summary>
+    /// 报警来源:PLC / Host / Both
+    /// PLC = 只信任 PLC 的 DI 开关量报警,上位机不做模拟量阈值判断
+    /// Host = 只走上位机的模拟量阈值判断,忽略 PLC 的 DI 报警
+    /// Both = 两套都检查(可能产生重复报警)
+    /// 默认 PLC
+    /// </summary>
+    public string AlarmSource { get; set; } = "PLC";
+
     public float? LevelHigh { get; set; }
     public float? LevelLow { get; set; }
     public float? FlowHigh { get; set; }

+ 45 - 31
src/YZWater.Core/Services/AlarmService.cs

@@ -190,49 +190,63 @@ public partial class AlarmService : ObservableObject, IDisposable
     }
 
     /// <summary>
-    /// 从项目档案检查报警
+    /// 从项目档案检查报警(根据 AlarmSource 配置决定检查来源)
     /// </summary>
     private void CheckAlarmsFromProfile(ProjectProfile profile, PlcDataModel data, DateTime now)
     {
         var thresholds = profile.AlarmThresholds;
+        var source = thresholds?.AlarmSource ?? "PLC";
 
-        // 液位报警(从动态寄存器读取)
-        foreach (var tank in profile.Tanks)
-        {
-            var level = data.GetAnalogRegister($"{tank.Name}.Level");
-            CheckLevelAlarm(tank.Name, level, now);
-        }
+        // PLC 模式:只信任 PLC 的 DI 开关量报警
+        // Host 模式:只走上位机模拟量阈值判断
+        // Both 模式:两套都检查(向后兼容)
+        bool checkAnalog = source == "Host" || source == "Both";
+        bool checkDI = source == "PLC" || source == "Both";
 
-        // 仪表报警(压力/流量等)
-        foreach (var gauge in profile.Gauges)
+        // ① 模拟量阈值检查(液位 + 仪表)— Host/Both 模式
+        if (checkAnalog)
         {
-            var value = data.GetAnalogRegister($"{gauge.Name}.Value");
-            if (thresholds?.PressureHigh.HasValue == true && value > thresholds.PressureHigh.Value)
-                CheckCondition($"Pressure_{gauge.Name}_High", $"{gauge.Name}过高: {value:F2} {gauge.Unit}", 2, now);
-            else
-                ClearCondition($"Pressure_{gauge.Name}_High");
+            // 液位报警(从动态寄存器读取)
+            foreach (var tank in profile.Tanks)
+            {
+                var level = data.GetAnalogRegister($"{tank.Name}.Level");
+                CheckLevelAlarm(tank.Name, level, now);
+            }
 
-            if (thresholds?.PressureLow.HasValue == true && value < thresholds.PressureLow.Value)
-                CheckCondition($"Pressure_{gauge.Name}_Low", $"{gauge.Name}过低: {value:F2} {gauge.Unit}", 2, now);
-            else
-                ClearCondition($"Pressure_{gauge.Name}_Low");
-        }
+            // 仪表报警(压力/流量等)
+            foreach (var gauge in profile.Gauges)
+            {
+                var value = data.GetAnalogRegister($"{gauge.Name}.Value");
+                if (thresholds?.PressureHigh.HasValue == true && value > thresholds.PressureHigh.Value)
+                    CheckCondition($"Pressure_{gauge.Name}_High", $"{gauge.Name}过高: {value:F2} {gauge.Unit}", 2, now);
+                else
+                    ClearCondition($"Pressure_{gauge.Name}_High");
+
+                if (thresholds?.PressureLow.HasValue == true && value < thresholds.PressureLow.Value)
+                    CheckCondition($"Pressure_{gauge.Name}_Low", $"{gauge.Name}过低: {value:F2} {gauge.Unit}", 2, now);
+                else
+                    ClearCondition($"Pressure_{gauge.Name}_Low");
+            }
 
-        // 泵故障报警
-        foreach (var pump in profile.Pumps)
-        {
-            var fault = data.GetDigitalRegister($"{pump.Name}.Fault");
-            CheckPumpFault(pump.Name, fault, now);
+            // 泵故障报警(寄存器读取)
+            foreach (var pump in profile.Pumps)
+            {
+                var fault = data.GetDigitalRegister($"{pump.Name}.Fault");
+                CheckPumpFault(pump.Name, fault, now);
+            }
         }
 
-        // 通用 DI 报警(变频器故障等)
-        foreach (var di in profile.DigitalInputs)
+        // ② PLC DI 报警 — PLC/Both 模式
+        if (checkDI)
         {
-            var isActive = data.GetDigitalRegister($"DI.{di.Name}");
-            if (isActive)
-                CheckCondition($"DI_{di.Name}", $"{di.Name} 触发", 2, now);
-            else
-                ClearCondition($"DI_{di.Name}");
+            foreach (var di in profile.DigitalInputs)
+            {
+                var isActive = data.GetDigitalRegister($"DI.{di.Name}");
+                if (isActive)
+                    CheckCondition($"DI_{di.Name}", $"{di.Name} 触发", 2, now);
+                else
+                    ClearCondition($"DI_{di.Name}");
+            }
         }
     }