EquipmentDataModel.cs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620
  1. using SWRIS.Controls;
  2. using SWRIS.Dtos;
  3. using SWRIS.Enums;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Collections.ObjectModel;
  7. using System.ComponentModel;
  8. using System.Linq;
  9. using System.Net.Sockets;
  10. using System.Threading.Tasks;
  11. using System.Windows;
  12. namespace SWRIS.Models
  13. {
  14. public class EquipmentDataModel : INotifyPropertyChanged
  15. {
  16. private int ropeNumber;
  17. private string ropeName;
  18. private int trolleyId;
  19. private string ipAddress;
  20. private string serialNo;
  21. private bool isConnect = false;
  22. private int sensorCount = 4;
  23. private double liftHightRatio = 1;
  24. private double ropeLength = 100f; // 默认长度为100米
  25. private RunningStatus runningStatus = RunningStatus.Stopped;
  26. private DirectionState direction;
  27. private FaultType? faultType;
  28. private double speed;
  29. private double position;
  30. private double absolutePosition;
  31. private double liftHeight;
  32. private double maxDamageValue;
  33. private double avgDamageValue;
  34. private int damageCount;
  35. private int mildCount;
  36. private int lightCount;
  37. private int moderateCount;
  38. private int severeCount;
  39. private int criticalCount;
  40. private int extremeCount;
  41. private DetectionDataModel detectionData;
  42. private RiskLevel riskLevel = RiskLevel.Normal;
  43. private Socket clientSocket;
  44. private double samplingStep;
  45. private DebugMessageModel debugMessage = new DebugMessageModel(string.Empty);
  46. private bool isAlerting = false;
  47. private bool isSpeedStable = true;
  48. private double variationThreshold = 0.25;
  49. private bool isHeartbeatReceived;
  50. private uint detectionNo;
  51. private bool disableAlarm;
  52. private int[] inUseSensor = new int[] { 1, 2, 3, 4 };
  53. private RealTimeLineChart chart;
  54. /// <summary>
  55. /// 钢丝绳绳号
  56. /// </summary>
  57. public int RopeNumber
  58. {
  59. get => ropeNumber;
  60. set { ropeNumber = value; OnPropertyChanged(nameof(RopeNumber)); }
  61. }
  62. /// <summary>
  63. /// 钢丝绳名称
  64. /// </summary>
  65. public string RopeName
  66. {
  67. get => ropeName;
  68. set { ropeName = value; OnPropertyChanged(nameof(RopeName)); }
  69. }
  70. /// <summary>
  71. /// 小车Id
  72. /// </summary>
  73. public int TrolleyId
  74. {
  75. get => trolleyId;
  76. set { trolleyId = value; OnPropertyChanged(nameof(TrolleyId)); }
  77. }
  78. /// <summary>
  79. /// 设备Ip地址
  80. /// </summary>
  81. public string IpAddress
  82. {
  83. get => ipAddress;
  84. set { ipAddress = value; OnPropertyChanged(nameof(IpAddress)); }
  85. }
  86. /// <summary>
  87. /// 设备序列号
  88. /// </summary>
  89. public string SerialNo
  90. {
  91. get => serialNo;
  92. set { serialNo = value; OnPropertyChanged(nameof(SerialNo)); }
  93. }
  94. /// <summary>
  95. /// 连接状态
  96. /// </summary>
  97. public bool IsConnect
  98. {
  99. get => isConnect;
  100. set { isConnect = value; OnPropertyChanged(nameof(IsConnect)); }
  101. }
  102. /// <summary>
  103. /// 传感器数量
  104. /// </summary>
  105. public int SensorCount
  106. {
  107. get => sensorCount;
  108. set { sensorCount = value; OnPropertyChanged(nameof(SensorCount)); }
  109. }
  110. /// <summary>
  111. /// 钢丝绳绳长
  112. /// </summary>
  113. public double RopeLength
  114. {
  115. get => ropeLength;
  116. set { ropeLength = value; OnPropertyChanged(nameof(RopeLength)); }
  117. }
  118. public double LiftHightRatio
  119. {
  120. get => liftHightRatio;
  121. set { liftHightRatio = value; OnPropertyChanged(nameof(LiftHightRatio)); }
  122. }
  123. /// <summary>
  124. /// 采样步长
  125. /// </summary>
  126. public double SamplingStep
  127. {
  128. get => samplingStep;
  129. set { samplingStep = value; OnPropertyChanged(nameof(SamplingStep)); }
  130. }
  131. /// <summary>
  132. /// 运行状态
  133. /// </summary>
  134. public RunningStatus RunningStatus
  135. {
  136. get => runningStatus;
  137. set { runningStatus = value; OnPropertyChanged(nameof(RunningStatus)); }
  138. }
  139. /// <summary>
  140. /// 运行方向
  141. /// </summary>
  142. public DirectionState Direction
  143. {
  144. get => direction;
  145. set { direction = value; OnPropertyChanged(nameof(Direction)); }
  146. }
  147. /// <summary>
  148. /// 故障类型
  149. /// </summary>
  150. public FaultType? FaultType
  151. {
  152. get => faultType;
  153. set { faultType = value; OnPropertyChanged(nameof(FaultType)); }
  154. }
  155. /// <summary>
  156. /// 速度
  157. /// </summary>
  158. public double Speed
  159. {
  160. get => speed;
  161. set { speed = value; OnPropertyChanged(nameof(Speed)); }
  162. }
  163. /// <summary>
  164. /// 速度变化率阈值
  165. /// </summary>
  166. public double VariationThreshold
  167. {
  168. get => variationThreshold;
  169. set { variationThreshold = value; OnPropertyChanged(nameof(VariationThreshold)); }
  170. }
  171. /// <summary>
  172. /// 速度是否稳定
  173. /// </summary>
  174. public bool IsSpeedStable
  175. {
  176. get => isSpeedStable;
  177. set { isSpeedStable = value; OnPropertyChanged(nameof(IsSpeedStable)); }
  178. }
  179. /// <summary>
  180. /// 位置
  181. /// </summary>
  182. public double Position
  183. {
  184. get => position;
  185. set { position = value; OnPropertyChanged(nameof(Position)); }
  186. }
  187. /// <summary>
  188. /// 绝对位置
  189. /// </summary>
  190. public double AbsolutePosition
  191. {
  192. get => absolutePosition;
  193. set { absolutePosition = value; OnPropertyChanged(nameof(AbsolutePosition)); }
  194. }
  195. /// <summary>
  196. /// 起升高度
  197. /// </summary>
  198. public double LiftHeight
  199. {
  200. get => liftHeight;
  201. set { liftHeight = value; OnPropertyChanged(nameof(LiftHeight)); }
  202. }
  203. /// <summary>
  204. /// 健康程度
  205. /// </summary>
  206. public RiskLevel RiskLevel
  207. {
  208. get => riskLevel;
  209. set { riskLevel = value; OnPropertyChanged(nameof(RiskLevel)); }
  210. }
  211. /// <summary>
  212. /// 平均损伤值
  213. /// </summary>
  214. public double AvgDamageValue
  215. {
  216. get => avgDamageValue;
  217. set { avgDamageValue = value; OnPropertyChanged(nameof(AvgDamageValue)); }
  218. }
  219. /// <summary>
  220. /// 最大损伤值
  221. /// </summary>
  222. public double MaxDamageValue
  223. {
  224. get => maxDamageValue;
  225. set { maxDamageValue = value; OnPropertyChanged(nameof(MaxDamageValue)); }
  226. }
  227. /// <summary>
  228. /// 损伤报警数量
  229. /// </summary>
  230. public int DamageCount
  231. {
  232. get => damageCount;
  233. set { damageCount = value; OnPropertyChanged(nameof(DamageCount)); }
  234. }
  235. /// <summary>
  236. /// 轻微损伤数量
  237. /// </summary>
  238. public int MildCount
  239. {
  240. get => mildCount;
  241. set { mildCount = value; OnPropertyChanged(nameof(MildCount)); }
  242. }
  243. /// <summary>
  244. /// 轻度损伤数量
  245. /// </summary>
  246. public int LightCount
  247. {
  248. get => lightCount;
  249. set { lightCount = value; OnPropertyChanged(nameof(LightCount)); }
  250. }
  251. /// <summary>
  252. /// 中度损伤数量
  253. /// </summary>
  254. public int ModerateCount
  255. {
  256. get => moderateCount;
  257. set { moderateCount = value; OnPropertyChanged(nameof(ModerateCount)); }
  258. }
  259. /// <summary>
  260. /// 较重损伤数量
  261. /// </summary>
  262. public int SevereCount
  263. {
  264. get => severeCount;
  265. set { severeCount = value; OnPropertyChanged(nameof(SevereCount)); }
  266. }
  267. /// <summary>
  268. /// 严重损伤数量
  269. /// </summary>
  270. public int CriticalCount
  271. {
  272. get => criticalCount;
  273. set { criticalCount = value; OnPropertyChanged(nameof(CriticalCount)); }
  274. }
  275. /// <summary>
  276. /// 超限损伤数量
  277. /// </summary>
  278. public int ExtremeCount
  279. {
  280. get => extremeCount;
  281. set { extremeCount = value; OnPropertyChanged(nameof(ExtremeCount)); }
  282. }
  283. /// <summary>
  284. /// 最后一次的检测数据
  285. /// </summary>
  286. public DetectionDataModel DetectionData
  287. {
  288. get => detectionData;
  289. set { detectionData = value; OnPropertyChanged(nameof(DetectionData)); }
  290. }
  291. /// <summary>
  292. /// 调试信息
  293. /// </summary>
  294. public DebugMessageModel DebugMessage
  295. {
  296. get => debugMessage;
  297. set { debugMessage = value; OnPropertyChanged(nameof(DebugMessage)); }
  298. }
  299. /// <summary>
  300. /// TCP 客户端
  301. /// </summary>
  302. public Socket ClientSocket
  303. {
  304. get => clientSocket;
  305. set { clientSocket = value; OnPropertyChanged(nameof(ClientSocket)); }
  306. }
  307. /// <summary>
  308. /// 是否报警中
  309. /// </summary>
  310. public bool IsAlerting
  311. {
  312. get => isAlerting;
  313. set { isAlerting = value; OnPropertyChanged(nameof(IsAlerting)); }
  314. }
  315. public bool IsHeartbeatReceived
  316. {
  317. get => isHeartbeatReceived;
  318. set
  319. {
  320. isHeartbeatReceived = value;
  321. OnPropertyChanged(nameof(IsHeartbeatReceived));
  322. if (value)
  323. {
  324. // 延迟一段时间后重置,以便动画可以重复触发
  325. Task.Delay(600).ContinueWith(_ =>
  326. {
  327. Application.Current.Dispatcher.Invoke(() =>
  328. {
  329. IsHeartbeatReceived = false;
  330. });
  331. });
  332. }
  333. }
  334. }
  335. /// <summary>
  336. /// 检测编号
  337. /// </summary>
  338. public uint DetectionNo
  339. {
  340. get => detectionNo;
  341. set { detectionNo = value; OnPropertyChanged(nameof(DetectionNo)); }
  342. }
  343. /// <summary>
  344. /// 禁用报警
  345. /// </summary>
  346. public bool DisableAlarm
  347. {
  348. get => disableAlarm;
  349. set { disableAlarm = value; OnPropertyChanged(nameof(DisableAlarm)); }
  350. }
  351. /// <summary>
  352. /// 在用传感器
  353. /// </summary>
  354. public int[] InUseSensor
  355. {
  356. get => inUseSensor;
  357. set { inUseSensor = value; OnPropertyChanged(nameof(InUseSensor)); }
  358. }
  359. public RealTimeLineChart Chart
  360. {
  361. get => chart;
  362. set
  363. {
  364. chart = value;
  365. }
  366. }
  367. public ObservableCollection<FaultDataModel> Faults { get; set; } = new ObservableCollection<FaultDataModel>();
  368. public ObservableCollection<AlarmDataModel> Alarms { get; set; } = new ObservableCollection<AlarmDataModel>();
  369. public ObservableCollection<LimitModel> Limits { get; set; } = new ObservableCollection<LimitModel>();
  370. public Queue<double> RecentSpeeds { get; internal set; } = new Queue<double>();
  371. private readonly object _liveStreamLock = new object();
  372. public Queue<int[]> LiveStreams { get; internal set; } = new Queue<int[]>();
  373. public ObservableCollection<int> LiveStreamValues { get; set; } = new ObservableCollection<int>();
  374. public void AddLiveStream(LiveStreamDataModel liveStream)
  375. {
  376. if (liveStream?.Data == null || liveStream.Data.Length == 0)
  377. return;
  378. lock (_liveStreamLock)
  379. {
  380. // 新数据到来时清空之前的实时流数据
  381. LiveStreams.Clear();
  382. int sensorCount = liveStream.SensorCount;
  383. int sampleCount = liveStream.Data.Length;
  384. // 本次与上次接收的时间间隔对应的采样点数量(每50ms 1个点)
  385. int targetCount = Math.Max(1, liveStream.SampleInterval / 50);
  386. int actualCount = Math.Min(targetCount, sampleCount);
  387. // 从 sampleCount 个采样点中平均抽取 actualCount 个点
  388. for (int i = 0; i < actualCount; i++)
  389. {
  390. int sourceIndex = actualCount == 1
  391. ? 0
  392. : (int)Math.Round((double)i * (sampleCount - 1) / (actualCount - 1));
  393. var point = new int[sensorCount];
  394. for (int s = 0; s < sensorCount; s++)
  395. {
  396. point[s] = liveStream.Data[sourceIndex][s];
  397. }
  398. LiveStreams.Enqueue(point);
  399. }
  400. }
  401. }
  402. /// <summary>
  403. /// 从实时流队列取出并移除一项(取出即移出)
  404. /// </summary>
  405. public bool TryDequeueLiveStream(out int[] sample)
  406. {
  407. lock (_liveStreamLock)
  408. {
  409. if (LiveStreams.Count > 0)
  410. {
  411. sample = LiveStreams.Dequeue();
  412. return true;
  413. }
  414. }
  415. sample = null;
  416. return false;
  417. }
  418. public void AddFault(FaultDataModel fault)
  419. {
  420. if (fault == null)
  421. return;
  422. // 无故障(HasFault 为 false):取消对应的故障(含编码器故障)
  423. if (!fault.HasFault)
  424. {
  425. RemoveFault(fault.FaultType);
  426. return;
  427. }
  428. // 有故障:查找同类型的已有故障
  429. var existingFault = Faults.FirstOrDefault(c => c.FaultType == fault.FaultType);
  430. if (existingFault == null)
  431. {
  432. // 无同类型故障,直接添加
  433. Faults.Add(fault);
  434. AddFaultMessage(fault);
  435. return;
  436. }
  437. // 已有同类型故障:判断故障传感器是否一致
  438. if (!existingFault.FaultySensors.SequenceEqual(fault.FaultySensors))
  439. {
  440. // 故障传感器不一致,更新为最新的故障信息
  441. existingFault.FaultCode = fault.FaultCode;
  442. UpdateFaultMessage(fault.FaultType, fault.FaultCode);
  443. }
  444. // 传感器一致则忽略,不重复添加
  445. }
  446. /// <summary>
  447. /// 取消指定类型的故障(含编码器故障)
  448. /// </summary>
  449. private void RemoveFault(FaultType faultType)
  450. {
  451. var existing = Faults.FirstOrDefault(c => c.FaultType == faultType);
  452. if (existing != null)
  453. {
  454. Faults.Remove(existing);
  455. }
  456. var message = App.DataCenter.Messages.FirstOrDefault(m => m.RopeName == RopeName);
  457. if (message != null)
  458. {
  459. Application.Current.Dispatcher.Invoke(() =>
  460. {
  461. message.Messages.RemoveAll(c => c.FaultType == faultType);
  462. });
  463. }
  464. }
  465. /// <summary>
  466. /// 添加故障到消息中心
  467. /// </summary>
  468. private void AddFaultMessage(FaultDataModel fault)
  469. {
  470. var message = App.DataCenter.Messages.FirstOrDefault(m => m.RopeName == RopeName);
  471. if (message == null)
  472. {
  473. Application.Current.Dispatcher.Invoke(() =>
  474. {
  475. App.DataCenter.Messages.Add(new FaultsMessageDto
  476. {
  477. RopeName = RopeName,
  478. Messages = new List<FaultDataModel> { fault }
  479. });
  480. });
  481. }
  482. else
  483. {
  484. Application.Current.Dispatcher.Invoke(() =>
  485. {
  486. message.Messages.Add(fault);
  487. });
  488. }
  489. }
  490. /// <summary>
  491. /// 更新消息中心中指定类型的故障码
  492. /// </summary>
  493. private void UpdateFaultMessage(FaultType faultType, int faultCode)
  494. {
  495. var message = App.DataCenter.Messages.FirstOrDefault(m => m.RopeName == RopeName);
  496. if (message != null)
  497. {
  498. Application.Current.Dispatcher.Invoke(() =>
  499. {
  500. var msgFault = message.Messages.FirstOrDefault(c => c.FaultType == faultType);
  501. if (msgFault != null)
  502. {
  503. msgFault.FaultCode = faultCode;
  504. }
  505. });
  506. }
  507. }
  508. public void AddSpeedData(double speed)
  509. {
  510. // 更新数据窗口
  511. RecentSpeeds.Enqueue(speed);
  512. if (RecentSpeeds.Count > 3)
  513. RecentSpeeds.Dequeue();
  514. if (RecentSpeeds.Count < 2)
  515. return;
  516. double avgSpeed = RecentSpeeds.Average();
  517. if (avgSpeed == 0)
  518. {
  519. IsSpeedStable = true;
  520. return;
  521. }
  522. // 计算当前速度相对于平均值的偏差
  523. bool _isStable = (Math.Abs(speed - avgSpeed) / avgSpeed) <= VariationThreshold;
  524. if (IsSpeedStable != _isStable)
  525. {
  526. IsSpeedStable = _isStable;
  527. }
  528. }
  529. public void AddAlarm(AlarmDataModel alarm)
  530. {
  531. DamageCount++;
  532. MaxDamageValue = alarm.DamageValue > MaxDamageValue ? alarm.DamageValue : MaxDamageValue;
  533. AvgDamageValue = (AvgDamageValue * (DamageCount - 1) + alarm.DamageValue) / DamageCount;
  534. switch (alarm.DamageLevel)
  535. {
  536. case DamageLevel.Mild:
  537. MildCount++;
  538. break;
  539. case DamageLevel.Light:
  540. LightCount++;
  541. break;
  542. case DamageLevel.Moderate:
  543. ModerateCount++;
  544. break;
  545. case DamageLevel.Severe:
  546. SevereCount++;
  547. break;
  548. case DamageLevel.Critical:
  549. CriticalCount++;
  550. break;
  551. case DamageLevel.ExceededLimit:
  552. ExtremeCount++;
  553. break;
  554. }
  555. Alarms.Add(alarm);
  556. RiskLevel = Alarms.Any() ? (RiskLevel)Alarms.Max(c => (int)c.DamageLevel) : RiskLevel.Normal;
  557. IsAlerting = true;
  558. Task.Run(() =>
  559. {
  560. Task.Delay(3000).Wait();
  561. IsAlerting = false;
  562. });
  563. }
  564. public void ClearData()
  565. {
  566. Speed = 0;
  567. MaxDamageValue = 0;
  568. AvgDamageValue = 0;
  569. DamageCount = 0;
  570. MildCount = 0;
  571. LightCount = 0;
  572. ModerateCount = 0;
  573. SevereCount = 0;
  574. CriticalCount = 0;
  575. ExtremeCount = 0;
  576. RiskLevel = RiskLevel.Normal;
  577. DetectionNo += 1;
  578. Application.Current.Dispatcher.Invoke(() => Alarms.Clear());
  579. Task.Run(async () =>
  580. {
  581. // 持续监控直到条件满足
  582. while (DetectionData?.RawDataReceiving == true)
  583. {
  584. await Task.Delay(100); // 避免CPU占用过高
  585. }
  586. // 条件满足时执行
  587. DetectionData = null;
  588. });
  589. }
  590. public event PropertyChangedEventHandler PropertyChanged;
  591. protected internal virtual void OnPropertyChanged(string propertyName)
  592. {
  593. PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
  594. }
  595. }
  596. }