using SWRIS.Controls; using SWRIS.Dtos; using SWRIS.Enums; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Linq; using System.Net.Sockets; using System.Threading.Tasks; using System.Windows; namespace SWRIS.Models { public class EquipmentDataModel : INotifyPropertyChanged { private int ropeNumber; private string ropeName; private int trolleyId; private string ipAddress; private string serialNo; private bool isConnect = false; private int sensorCount = 4; private double liftHightRatio = 1; private double ropeLength = 100f; // 默认长度为100米 private RunningStatus runningStatus = RunningStatus.Stopped; private DirectionState direction; private FaultType? faultType; private double speed; private double position; private double absolutePosition; private double liftHeight; private double maxDamageValue; private double avgDamageValue; private int damageCount; private int mildCount; private int lightCount; private int moderateCount; private int severeCount; private int criticalCount; private int extremeCount; private DetectionDataModel detectionData; private RiskLevel riskLevel = RiskLevel.Normal; private Socket clientSocket; private double samplingStep; private DebugMessageModel debugMessage = new DebugMessageModel(string.Empty); private bool isAlerting = false; private bool isSpeedStable = true; private double variationThreshold = 0.25; private bool isHeartbeatReceived; private uint detectionNo; private bool disableAlarm; private int[] inUseSensor = new int[] { 1, 2, 3, 4 }; private RealTimeLineChart chart; /// /// 钢丝绳绳号 /// public int RopeNumber { get => ropeNumber; set { ropeNumber = value; OnPropertyChanged(nameof(RopeNumber)); } } /// /// 钢丝绳名称 /// public string RopeName { get => ropeName; set { ropeName = value; OnPropertyChanged(nameof(RopeName)); } } /// /// 小车Id /// public int TrolleyId { get => trolleyId; set { trolleyId = value; OnPropertyChanged(nameof(TrolleyId)); } } /// /// 设备Ip地址 /// public string IpAddress { get => ipAddress; set { ipAddress = value; OnPropertyChanged(nameof(IpAddress)); } } /// /// 设备序列号 /// public string SerialNo { get => serialNo; set { serialNo = value; OnPropertyChanged(nameof(SerialNo)); } } /// /// 连接状态 /// public bool IsConnect { get => isConnect; set { isConnect = value; OnPropertyChanged(nameof(IsConnect)); } } /// /// 传感器数量 /// public int SensorCount { get => sensorCount; set { sensorCount = value; OnPropertyChanged(nameof(SensorCount)); } } /// /// 钢丝绳绳长 /// public double RopeLength { get => ropeLength; set { ropeLength = value; OnPropertyChanged(nameof(RopeLength)); } } public double LiftHightRatio { get => liftHightRatio; set { liftHightRatio = value; OnPropertyChanged(nameof(LiftHightRatio)); } } /// /// 采样步长 /// public double SamplingStep { get => samplingStep; set { samplingStep = value; OnPropertyChanged(nameof(SamplingStep)); } } /// /// 运行状态 /// public RunningStatus RunningStatus { get => runningStatus; set { runningStatus = value; OnPropertyChanged(nameof(RunningStatus)); } } /// /// 预状态挂起时间戳(UtcNow.Ticks),0 表示无挂起的预状态 /// public long PreStatusTimestamp { get; set; } /// /// 预运行请求的检测模式(TemporalNormal=时域,SpatialNormal=空域),用于 0x06 应答确认时恢复正确模式 /// public RunningStatus PreStatusRunningMode { get; set; } /// /// 标记预状态位并记录挂起时间戳(本地先行、等待设备确认) /// public void MarkPreStatus(RunningStatus flag) { RunningStatus |= flag; PreStatusTimestamp = DateTime.UtcNow.Ticks; } /// /// 标记预运行状态并记录本次请求的检测模式(时域/空域),清除旧模式位避免切换时残留 /// public void MarkPreRunning(RunningStatus mode) { RunningStatus = (RunningStatus & ~(RunningStatus.SpatialNormal | RunningStatus.TemporalNormal)) | mode | RunningStatus.PreRunning; PreStatusRunningMode = mode; PreStatusTimestamp = DateTime.UtcNow.Ticks; } /// /// 设备已确认命令:按位清除对应预状态位并合并实际状态,保留报警/故障等其他状态位 /// public void ConfirmPreStatus(RunningStatus preFlag, RunningStatus actualStatus) { RunningStatus = (RunningStatus & ~preFlag) | actualStatus; if (preFlag == RunningStatus.PreRunning) { PreStatusRunningMode = 0; } // 仅当没有其他挂起的预状态位时才清零挂起时间戳,避免影响其他预状态的超时判断 if ((RunningStatus & (RunningStatus.PreStop | RunningStatus.PreRunning | RunningStatus.PreCalibration)) == 0) { PreStatusTimestamp = 0; } } /// /// 清除所有挂起的预状态位(用于断线、超时等场景) /// public void ClearAllPreStatus() { RunningStatus &= ~(RunningStatus.PreStop | RunningStatus.PreRunning | RunningStatus.PreCalibration); PreStatusRunningMode = 0; PreStatusTimestamp = 0; } /// /// 运行方向 /// public DirectionState Direction { get => direction; set { direction = value; OnPropertyChanged(nameof(Direction)); } } /// /// 故障类型 /// public FaultType? FaultType { get => faultType; set { faultType = value; OnPropertyChanged(nameof(FaultType)); } } /// /// 速度 /// public double Speed { get => speed; set { speed = value; OnPropertyChanged(nameof(Speed)); } } /// /// 速度变化率阈值 /// public double VariationThreshold { get => variationThreshold; set { variationThreshold = value; OnPropertyChanged(nameof(VariationThreshold)); } } /// /// 速度是否稳定 /// public bool IsSpeedStable { get => isSpeedStable; set { isSpeedStable = value; OnPropertyChanged(nameof(IsSpeedStable)); } } /// /// 位置 /// public double Position { get => position; set { position = value; OnPropertyChanged(nameof(Position)); } } /// /// 绝对位置 /// public double AbsolutePosition { get => absolutePosition; set { absolutePosition = value; OnPropertyChanged(nameof(AbsolutePosition)); } } /// /// 起升高度 /// public double LiftHeight { get => liftHeight; set { liftHeight = value; OnPropertyChanged(nameof(LiftHeight)); } } /// /// 健康程度 /// public RiskLevel RiskLevel { get => riskLevel; set { riskLevel = value; OnPropertyChanged(nameof(RiskLevel)); } } /// /// 平均损伤值 /// public double AvgDamageValue { get => avgDamageValue; set { avgDamageValue = value; OnPropertyChanged(nameof(AvgDamageValue)); } } /// /// 最大损伤值 /// public double MaxDamageValue { get => maxDamageValue; set { maxDamageValue = value; OnPropertyChanged(nameof(MaxDamageValue)); } } /// /// 损伤报警数量 /// public int DamageCount { get => damageCount; set { damageCount = value; OnPropertyChanged(nameof(DamageCount)); } } /// /// 轻微损伤数量 /// public int MildCount { get => mildCount; set { mildCount = value; OnPropertyChanged(nameof(MildCount)); } } /// /// 轻度损伤数量 /// public int LightCount { get => lightCount; set { lightCount = value; OnPropertyChanged(nameof(LightCount)); } } /// /// 中度损伤数量 /// public int ModerateCount { get => moderateCount; set { moderateCount = value; OnPropertyChanged(nameof(ModerateCount)); } } /// /// 较重损伤数量 /// public int SevereCount { get => severeCount; set { severeCount = value; OnPropertyChanged(nameof(SevereCount)); } } /// /// 严重损伤数量 /// public int CriticalCount { get => criticalCount; set { criticalCount = value; OnPropertyChanged(nameof(CriticalCount)); } } /// /// 超限损伤数量 /// public int ExtremeCount { get => extremeCount; set { extremeCount = value; OnPropertyChanged(nameof(ExtremeCount)); } } /// /// 最后一次的检测数据 /// public DetectionDataModel DetectionData { get => detectionData; set { detectionData = value; OnPropertyChanged(nameof(DetectionData)); } } /// /// 调试信息 /// public DebugMessageModel DebugMessage { get => debugMessage; set { debugMessage = value; OnPropertyChanged(nameof(DebugMessage)); } } /// /// TCP 客户端 /// public Socket ClientSocket { get => clientSocket; set { clientSocket = value; OnPropertyChanged(nameof(ClientSocket)); } } /// /// 是否报警中 /// public bool IsAlerting { get => isAlerting; set { isAlerting = value; OnPropertyChanged(nameof(IsAlerting)); } } public bool IsHeartbeatReceived { get => isHeartbeatReceived; set { isHeartbeatReceived = value; OnPropertyChanged(nameof(IsHeartbeatReceived)); if (value) { // 延迟一段时间后重置,以便动画可以重复触发 Task.Delay(600).ContinueWith(_ => { Application.Current.Dispatcher.Invoke(() => { IsHeartbeatReceived = false; }); }); } } } /// /// 检测编号 /// public uint DetectionNo { get => detectionNo; set { detectionNo = value; OnPropertyChanged(nameof(DetectionNo)); } } /// /// 禁用报警 /// public bool DisableAlarm { get => disableAlarm; set { disableAlarm = value; OnPropertyChanged(nameof(DisableAlarm)); } } /// /// 在用传感器 /// public int[] InUseSensor { get => inUseSensor; set { inUseSensor = value; OnPropertyChanged(nameof(InUseSensor)); } } public RealTimeLineChart Chart { get => chart; set { chart = value; } } public ObservableCollection Faults { get; set; } = new ObservableCollection(); public ObservableCollection Alarms { get; set; } = new ObservableCollection(); public ObservableCollection Limits { get; set; } = new ObservableCollection(); public Queue RecentSpeeds { get; internal set; } = new Queue(); private readonly object _liveStreamLock = new object(); public Queue LiveStreams { get; internal set; } = new Queue(); public ObservableCollection LiveStreamValues { get; set; } = new ObservableCollection(); public void AddLiveStream(LiveStreamDataModel liveStream) { if (liveStream?.Data == null || liveStream.Data.Length == 0) return; lock (_liveStreamLock) { // 新数据到来时清空之前的实时流数据 LiveStreams.Clear(); int sensorCount = liveStream.SensorCount; int sampleCount = liveStream.Data.Length; // 本次与上次接收的时间间隔对应的采样点数量(每50ms 1个点) int targetCount = Math.Max(1, liveStream.SampleInterval / 50); int actualCount = Math.Min(targetCount, sampleCount); // 从 sampleCount 个采样点中平均抽取 actualCount 个点 for (int i = 0; i < actualCount; i++) { int sourceIndex = actualCount == 1 ? 0 : (int)Math.Round((double)i * (sampleCount - 1) / (actualCount - 1)); var point = new int[sensorCount]; for (int s = 0; s < sensorCount; s++) { point[s] = liveStream.Data[sourceIndex][s]; } LiveStreams.Enqueue(point); } } } /// /// 从实时流队列取出并移除一项(取出即移出) /// public bool TryDequeueLiveStream(out int[] sample) { lock (_liveStreamLock) { if (LiveStreams.Count > 0) { sample = LiveStreams.Dequeue(); return true; } } sample = null; return false; } public void AddFault(FaultDataModel fault) { if (fault == null) return; // 无故障(HasFault 为 false):取消对应的故障(含编码器故障) if (!fault.HasFault) { RemoveFault(fault.FaultType); return; } // 有故障:查找同类型的已有故障 var existingFault = Faults.FirstOrDefault(c => c.FaultType == fault.FaultType); if (existingFault == null) { // 无同类型故障,直接添加 Faults.Add(fault); AddFaultMessage(fault); return; } // 已有同类型故障:判断故障传感器是否一致 if (!existingFault.FaultySensors.SequenceEqual(fault.FaultySensors)) { // 故障传感器不一致,更新为最新的故障信息 existingFault.FaultCode = fault.FaultCode; UpdateFaultMessage(fault.FaultType, fault.FaultCode); } // 传感器一致则忽略,不重复添加 } /// /// 取消指定类型的故障(含编码器故障) /// private void RemoveFault(FaultType faultType) { var existing = Faults.FirstOrDefault(c => c.FaultType == faultType); if (existing != null) { Faults.Remove(existing); } var message = App.DataCenter.Messages.FirstOrDefault(m => m.RopeName == RopeName); if (message != null) { Application.Current.Dispatcher.Invoke(() => { message.Messages.RemoveAll(c => c.FaultType == faultType); }); } } /// /// 添加故障到消息中心 /// private void AddFaultMessage(FaultDataModel fault) { var message = App.DataCenter.Messages.FirstOrDefault(m => m.RopeName == RopeName); if (message == null) { Application.Current.Dispatcher.Invoke(() => { App.DataCenter.Messages.Add(new FaultsMessageDto { RopeName = RopeName, Messages = new List { fault } }); }); } else { Application.Current.Dispatcher.Invoke(() => { message.Messages.Add(fault); }); } } /// /// 更新消息中心中指定类型的故障码 /// private void UpdateFaultMessage(FaultType faultType, int faultCode) { var message = App.DataCenter.Messages.FirstOrDefault(m => m.RopeName == RopeName); if (message != null) { Application.Current.Dispatcher.Invoke(() => { var msgFault = message.Messages.FirstOrDefault(c => c.FaultType == faultType); if (msgFault != null) { msgFault.FaultCode = faultCode; } }); } } public void AddSpeedData(double speed) { // 更新数据窗口 RecentSpeeds.Enqueue(speed); if (RecentSpeeds.Count > 3) RecentSpeeds.Dequeue(); if (RecentSpeeds.Count < 2) return; double avgSpeed = RecentSpeeds.Average(); if (avgSpeed == 0) { IsSpeedStable = true; return; } // 计算当前速度相对于平均值的偏差 bool _isStable = (Math.Abs(speed - avgSpeed) / avgSpeed) <= VariationThreshold; if (IsSpeedStable != _isStable) { IsSpeedStable = _isStable; } } public void AddAlarm(AlarmDataModel alarm) { DamageCount++; MaxDamageValue = alarm.DamageValue > MaxDamageValue ? alarm.DamageValue : MaxDamageValue; AvgDamageValue = (AvgDamageValue * (DamageCount - 1) + alarm.DamageValue) / DamageCount; switch (alarm.DamageLevel) { case DamageLevel.Mild: MildCount++; break; case DamageLevel.Light: LightCount++; break; case DamageLevel.Moderate: ModerateCount++; break; case DamageLevel.Severe: SevereCount++; break; case DamageLevel.Critical: CriticalCount++; break; case DamageLevel.ExceededLimit: ExtremeCount++; break; } Alarms.Add(alarm); RiskLevel = Alarms.Any() ? (RiskLevel)Alarms.Max(c => (int)c.DamageLevel) : RiskLevel.Normal; IsAlerting = true; Task.Run(() => { Task.Delay(3000).Wait(); IsAlerting = false; }); } public void ClearData() { Speed = 0; MaxDamageValue = 0; AvgDamageValue = 0; DamageCount = 0; MildCount = 0; LightCount = 0; ModerateCount = 0; SevereCount = 0; CriticalCount = 0; ExtremeCount = 0; RiskLevel = RiskLevel.Normal; DetectionNo += 1; Application.Current.Dispatcher.Invoke(() => Alarms.Clear()); Task.Run(async () => { // 持续监控直到条件满足 while (DetectionData?.RawDataReceiving == true) { await Task.Delay(100); // 避免CPU占用过高 } // 条件满足时执行 DetectionData = null; }); } public event PropertyChangedEventHandler PropertyChanged; protected internal virtual void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } }