EquipmentDataModel.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  1. using ScottPlot;
  2. using SWRIS.Enums;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Collections.ObjectModel;
  6. using System.ComponentModel;
  7. using System.Linq;
  8. using System.Net.Sockets;
  9. using System.Threading.Tasks;
  10. using System.Windows;
  11. namespace SWRIS.Models
  12. {
  13. public class EquipmentDataModel : INotifyPropertyChanged
  14. {
  15. private int ropeNumber;
  16. private string ropeName;
  17. private string ipAddress;
  18. private string serialNo;
  19. private bool isConnect = false;
  20. private int sensorCount = 4;
  21. private double liftHightRatio = 1;
  22. private double ropeLength = 100f; // 默认长度为100米
  23. private RunningStatus runningStatus = RunningStatus.Stopped;
  24. private DirectionState direction;
  25. private double speed;
  26. private double position;
  27. private double absolutePosition;
  28. private double liftHeight;
  29. private double maxDamageValue;
  30. private double avgDamageValue;
  31. private int damageCount;
  32. private int mildCount;
  33. private int lightCount;
  34. private int moderateCount;
  35. private int severeCount;
  36. private int criticalCount;
  37. private int extremeCount;
  38. private DetectionDataModel detectionData;
  39. private RiskLevel riskLevel = RiskLevel.Normal;
  40. private Socket clientSocket;
  41. private double samplingStep;
  42. private DebugMessageModel debugMessage = new DebugMessageModel(string.Empty);
  43. private bool isAlerting = false;
  44. private bool isFaulting = false;
  45. private bool isSpeedStable = true;
  46. private double variationThreshold = 0.25;
  47. private bool isHeartbeatReceived;
  48. private uint detectionNo;
  49. private bool disableAlarm;
  50. private int[] inUseSensor = new int[] { 1, 2, 3, 4 };
  51. /// <summary>
  52. /// 钢丝绳绳号
  53. /// </summary>
  54. public int RopeNumber
  55. {
  56. get => ropeNumber;
  57. set { ropeNumber = value; OnPropertyChanged(nameof(RopeNumber)); }
  58. }
  59. /// <summary>
  60. /// 钢丝绳名称
  61. /// </summary>
  62. public string RopeName
  63. {
  64. get => ropeName;
  65. set { ropeName = value; OnPropertyChanged(nameof(RopeName)); }
  66. }
  67. /// <summary>
  68. /// 设备Ip地址
  69. /// </summary>
  70. public string IpAddress
  71. {
  72. get => ipAddress;
  73. set { ipAddress = value; OnPropertyChanged(nameof(IpAddress)); }
  74. }
  75. /// <summary>
  76. /// 设备序列号
  77. /// </summary>
  78. public string SerialNo
  79. {
  80. get => serialNo;
  81. set { serialNo = value; OnPropertyChanged(nameof(SerialNo)); }
  82. }
  83. /// <summary>
  84. /// 连接状态
  85. /// </summary>
  86. public bool IsConnect
  87. {
  88. get => isConnect;
  89. set { isConnect = value; OnPropertyChanged(nameof(IsConnect)); }
  90. }
  91. /// <summary>
  92. /// 传感器数量
  93. /// </summary>
  94. public int SensorCount
  95. {
  96. get => sensorCount;
  97. set { sensorCount = value; OnPropertyChanged(nameof(SensorCount)); }
  98. }
  99. /// <summary>
  100. /// 钢丝绳绳长
  101. /// </summary>
  102. public double RopeLength
  103. {
  104. get => ropeLength;
  105. set { ropeLength = value; OnPropertyChanged(nameof(RopeLength)); }
  106. }
  107. public double LiftHightRatio
  108. {
  109. get => liftHightRatio;
  110. set { liftHightRatio = value; OnPropertyChanged(nameof(LiftHightRatio)); }
  111. }
  112. /// <summary>
  113. /// 采样步长
  114. /// </summary>
  115. public double SamplingStep
  116. {
  117. get => samplingStep;
  118. set { samplingStep = value; OnPropertyChanged(nameof(SamplingStep)); }
  119. }
  120. /// <summary>
  121. /// 运行状态
  122. /// </summary>
  123. public RunningStatus RunningStatus
  124. {
  125. get => runningStatus;
  126. set { runningStatus = value; OnPropertyChanged(nameof(RunningStatus)); }
  127. }
  128. /// <summary>
  129. /// 运行方向
  130. /// </summary>
  131. public DirectionState Direction
  132. {
  133. get => direction;
  134. set { direction = value; OnPropertyChanged(nameof(Direction)); }
  135. }
  136. /// <summary>
  137. /// 速度
  138. /// </summary>
  139. public double Speed
  140. {
  141. get => speed;
  142. set { speed = value; OnPropertyChanged(nameof(Speed)); }
  143. }
  144. /// <summary>
  145. /// 速度变化率阈值
  146. /// </summary>
  147. public double VariationThreshold
  148. {
  149. get => variationThreshold;
  150. set { variationThreshold = value; OnPropertyChanged(nameof(VariationThreshold)); }
  151. }
  152. /// <summary>
  153. /// 速度是否稳定
  154. /// </summary>
  155. public bool IsSpeedStable
  156. {
  157. get => isSpeedStable;
  158. set { isSpeedStable = value; OnPropertyChanged(nameof(IsSpeedStable)); }
  159. }
  160. /// <summary>
  161. /// 位置
  162. /// </summary>
  163. public double Position
  164. {
  165. get => position;
  166. set { position = value; OnPropertyChanged(nameof(Position)); }
  167. }
  168. /// <summary>
  169. /// 绝对位置
  170. /// </summary>
  171. public double AbsolutePosition
  172. {
  173. get => absolutePosition;
  174. set { absolutePosition = value; OnPropertyChanged(nameof(AbsolutePosition)); }
  175. }
  176. /// <summary>
  177. /// 起升高度
  178. /// </summary>
  179. public double LiftHeight
  180. {
  181. get => liftHeight;
  182. set { liftHeight = value; OnPropertyChanged(nameof(LiftHeight)); }
  183. }
  184. /// <summary>
  185. /// 健康程度
  186. /// </summary>
  187. public RiskLevel RiskLevel
  188. {
  189. get => riskLevel;
  190. set { riskLevel = value; OnPropertyChanged(nameof(RiskLevel)); }
  191. }
  192. /// <summary>
  193. /// 平均损伤值
  194. /// </summary>
  195. public double AvgDamageValue
  196. {
  197. get => avgDamageValue;
  198. set { avgDamageValue = value; OnPropertyChanged(nameof(AvgDamageValue)); }
  199. }
  200. /// <summary>
  201. /// 最大损伤值
  202. /// </summary>
  203. public double MaxDamageValue
  204. {
  205. get => maxDamageValue;
  206. set { maxDamageValue = value; OnPropertyChanged(nameof(MaxDamageValue)); }
  207. }
  208. /// <summary>
  209. /// 损伤报警数量
  210. /// </summary>
  211. public int DamageCount
  212. {
  213. get => damageCount;
  214. set { damageCount = value; OnPropertyChanged(nameof(DamageCount)); }
  215. }
  216. /// <summary>
  217. /// 轻微损伤数量
  218. /// </summary>
  219. public int MildCount
  220. {
  221. get => mildCount;
  222. set { mildCount = value; OnPropertyChanged(nameof(MildCount)); }
  223. }
  224. /// <summary>
  225. /// 轻度损伤数量
  226. /// </summary>
  227. public int LightCount
  228. {
  229. get => lightCount;
  230. set { lightCount = value; OnPropertyChanged(nameof(LightCount)); }
  231. }
  232. /// <summary>
  233. /// 中度损伤数量
  234. /// </summary>
  235. public int ModerateCount
  236. {
  237. get => moderateCount;
  238. set { moderateCount = value; OnPropertyChanged(nameof(ModerateCount)); }
  239. }
  240. /// <summary>
  241. /// 较重损伤数量
  242. /// </summary>
  243. public int SevereCount
  244. {
  245. get => severeCount;
  246. set { severeCount = value; OnPropertyChanged(nameof(SevereCount)); }
  247. }
  248. /// <summary>
  249. /// 严重损伤数量
  250. /// </summary>
  251. public int CriticalCount
  252. {
  253. get => criticalCount;
  254. set { criticalCount = value; OnPropertyChanged(nameof(CriticalCount)); }
  255. }
  256. /// <summary>
  257. /// 超限损伤数量
  258. /// </summary>
  259. public int ExtremeCount
  260. {
  261. get => extremeCount;
  262. set { extremeCount = value; OnPropertyChanged(nameof(ExtremeCount)); }
  263. }
  264. /// <summary>
  265. /// 最后一次的检测数据
  266. /// </summary>
  267. public DetectionDataModel DetectionData
  268. {
  269. get => detectionData;
  270. set { detectionData = value; OnPropertyChanged(nameof(DetectionData)); }
  271. }
  272. /// <summary>
  273. /// 调试信息
  274. /// </summary>
  275. public DebugMessageModel DebugMessage
  276. {
  277. get => debugMessage;
  278. set { debugMessage = value; OnPropertyChanged(nameof(DebugMessage)); }
  279. }
  280. /// <summary>
  281. /// TCP 客户端
  282. /// </summary>
  283. public Socket ClientSocket
  284. {
  285. get => clientSocket;
  286. set { clientSocket = value; OnPropertyChanged(nameof(ClientSocket)); }
  287. }
  288. /// <summary>
  289. /// 是否报警中
  290. /// </summary>
  291. public bool IsAlerting
  292. {
  293. get => isAlerting;
  294. set { isAlerting = value; OnPropertyChanged(nameof(IsAlerting)); }
  295. }
  296. /// <summary>
  297. /// 是否故障中
  298. /// </summary>
  299. public bool IsFaulting
  300. {
  301. get => isFaulting;
  302. set { isFaulting = value; OnPropertyChanged(nameof(IsFaulting)); }
  303. }
  304. public bool IsHeartbeatReceived
  305. {
  306. get => isHeartbeatReceived;
  307. set
  308. {
  309. isHeartbeatReceived = value;
  310. OnPropertyChanged(nameof(IsHeartbeatReceived));
  311. if (value)
  312. {
  313. // 延迟一段时间后重置,以便动画可以重复触发
  314. Task.Delay(600).ContinueWith(_ =>
  315. {
  316. Application.Current.Dispatcher.Invoke(() =>
  317. {
  318. IsHeartbeatReceived = false;
  319. });
  320. });
  321. }
  322. }
  323. }
  324. /// <summary>
  325. /// 检测编号
  326. /// </summary>
  327. public uint DetectionNo
  328. {
  329. get => detectionNo;
  330. set { detectionNo = value; OnPropertyChanged(nameof(DetectionNo)); }
  331. }
  332. /// <summary>
  333. /// 禁用报警
  334. /// </summary>
  335. public bool DisableAlarm
  336. {
  337. get => disableAlarm;
  338. set { disableAlarm = value; OnPropertyChanged(nameof(DisableAlarm)); }
  339. }
  340. /// <summary>
  341. /// 在用传感器
  342. /// </summary>
  343. public int[] InUseSensor
  344. {
  345. get => inUseSensor;
  346. set { inUseSensor = value; OnPropertyChanged(nameof(InUseSensor)); }
  347. }
  348. public ObservableCollection<AlarmDataModel> Alarms { get; set; } = new ObservableCollection<AlarmDataModel>();
  349. public Dictionary<FaultType, FaultDataModel> Faults { get; set; } = new Dictionary<FaultType, FaultDataModel>();
  350. public ObservableCollection<string> Messages { get; set; } = new ObservableCollection<string>();
  351. public ObservableCollection<LimitModel> Limits { get; set; } = new ObservableCollection<LimitModel>();
  352. public Coordinates[] ChartSource { get; internal set; }
  353. public Queue<double> RecentSpeeds { get; internal set; } = new Queue<double>();
  354. public void AddFault(FaultDataModel faultData)
  355. {
  356. if (Faults.ContainsKey(faultData.FaultType))
  357. {
  358. if (faultData.FaultCode == 0)
  359. {
  360. Faults.Remove(faultData.FaultType);
  361. }
  362. else
  363. {
  364. Faults[faultData.FaultType] = faultData;
  365. }
  366. }
  367. else if (faultData.FaultCode != 0)
  368. {
  369. Faults.Add(faultData.FaultType, faultData);
  370. }
  371. Application.Current.Dispatcher.Invoke(() =>
  372. {
  373. if (Messages.Any())
  374. {
  375. Messages.Clear();
  376. }
  377. foreach (var fault in Faults)
  378. {
  379. if (fault.Value != null)
  380. {
  381. Messages.Add(fault.Value.ToString());
  382. }
  383. }
  384. });
  385. if (Messages.Any())
  386. IsFaulting = true;
  387. else
  388. IsFaulting = false;
  389. }
  390. public void AddSpeedData(double speed)
  391. {
  392. // 更新数据窗口
  393. RecentSpeeds.Enqueue(speed);
  394. if (RecentSpeeds.Count > 3)
  395. RecentSpeeds.Dequeue();
  396. if (RecentSpeeds.Count < 2)
  397. return;
  398. double avgSpeed = RecentSpeeds.Average();
  399. if (avgSpeed == 0)
  400. {
  401. IsSpeedStable = true;
  402. return;
  403. }
  404. // 计算当前速度相对于平均值的偏差
  405. bool _isStable = (Math.Abs(speed - avgSpeed) / avgSpeed) <= VariationThreshold;
  406. if (IsSpeedStable != _isStable)
  407. {
  408. IsSpeedStable = _isStable;
  409. }
  410. }
  411. public void AddAlarm(AlarmDataModel alarm)
  412. {
  413. DamageCount++;
  414. MaxDamageValue = alarm.DamageValue > MaxDamageValue ? alarm.DamageValue : MaxDamageValue;
  415. AvgDamageValue = (AvgDamageValue * (DamageCount - 1) + alarm.DamageValue) / DamageCount;
  416. switch (alarm.DamageLevel)
  417. {
  418. case DamageLevel.Mild:
  419. MildCount++;
  420. break;
  421. case DamageLevel.Light:
  422. LightCount++;
  423. break;
  424. case DamageLevel.Moderate:
  425. ModerateCount++;
  426. break;
  427. case DamageLevel.Severe:
  428. SevereCount++;
  429. break;
  430. case DamageLevel.Critical:
  431. CriticalCount++;
  432. break;
  433. case DamageLevel.ExceededLimit:
  434. ExtremeCount++;
  435. break;
  436. }
  437. Alarms.Add(alarm);
  438. RiskLevel = Alarms.Any() ? (RiskLevel)Alarms.Max(c => (int)c.DamageLevel) : RiskLevel.Normal;
  439. IsAlerting = true;
  440. Task.Run(() =>
  441. {
  442. Task.Delay(3000).Wait();
  443. IsAlerting = false;
  444. });
  445. }
  446. public void ClearData()
  447. {
  448. Speed = 0;
  449. MaxDamageValue = 0;
  450. AvgDamageValue = 0;
  451. DamageCount = 0;
  452. MildCount = 0;
  453. LightCount = 0;
  454. ModerateCount = 0;
  455. SevereCount = 0;
  456. CriticalCount = 0;
  457. ExtremeCount = 0;
  458. ChartSource = null;
  459. RiskLevel = RiskLevel.Normal;
  460. DetectionNo += 1;
  461. Application.Current.Dispatcher.Invoke(() => Alarms.Clear());
  462. Task.Run(async () =>
  463. {
  464. // 持续监控直到条件满足
  465. while (DetectionData?.RawDataReceiving == true)
  466. {
  467. await Task.Delay(100); // 避免CPU占用过高
  468. }
  469. // 条件满足时执行
  470. DetectionData = null;
  471. });
  472. }
  473. public event PropertyChangedEventHandler PropertyChanged;
  474. protected internal virtual void OnPropertyChanged(string propertyName)
  475. {
  476. PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
  477. }
  478. }
  479. }