终端一体化运控平台
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

BaseDevice.cs 20 KiB

2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
2 anos atrás
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529
  1. using BPA.Message;
  2. using BPA.Message.Enum;
  3. using BPASmartClient.Helper;
  4. using BPASmartClient.Message;
  5. using BPASmartClient.Model;
  6. using BPASmartClient.Peripheral;
  7. using System;
  8. using System.Collections.Concurrent;
  9. using System.Collections.Generic;
  10. using System.Linq;
  11. using System.Reflection;
  12. using System.Text;
  13. using System.Threading;
  14. using System.Threading.Tasks;
  15. using System.Collections.ObjectModel;
  16. namespace BPASmartClient.Device
  17. {
  18. /// <summary>
  19. /// 设备基类
  20. /// </summary>
  21. public abstract class BaseDevice : IDevice
  22. {
  23. public BaseDevice()
  24. {
  25. }
  26. #region 属性
  27. /// <summary>
  28. /// 订单物料信息
  29. /// </summary>
  30. public OrderMaterialDelivery orderMaterialDelivery { get; set; } = new OrderMaterialDelivery();
  31. /// <summary>
  32. /// 配方数据信息
  33. /// </summary>
  34. public RecipeBoms recipeBoms { get; set; } = new RecipeBoms();
  35. /// <summary>
  36. /// 设备ID
  37. /// </summary>
  38. public int DeviceId { get; set; }
  39. /// <summary>
  40. /// 设备所有状态
  41. /// </summary>
  42. public DeviceStatus Status { get; set; } = new DeviceStatus();
  43. /// <summary>
  44. /// 设备名称
  45. /// </summary>
  46. public string Name { get; set; }
  47. /// <summary>
  48. /// 当前订单数量
  49. /// </summary>
  50. protected int OrderCount { get; set; }
  51. /// <summary>
  52. /// 设备初始化中
  53. /// </summary>
  54. protected bool Initing { get; set; }
  55. /// <summary>
  56. /// 设备类型
  57. /// </summary>
  58. public abstract DeviceClientType DeviceType { get; }
  59. /// <summary>
  60. /// 是否忙碌
  61. /// </summary>
  62. public bool IsBusy { get; protected set; }
  63. /// <summary>
  64. /// 是否健康
  65. /// </summary>
  66. public bool IsHealth { get; protected set; }
  67. /// <summary>
  68. /// 设备运行日志
  69. /// </summary>
  70. public List<object> Log { get; set; } = new List<object>();
  71. /// <summary>
  72. /// 设备运行告警与错误
  73. /// </summary>
  74. public List<object> Error { get; set; } = new List<object>();
  75. /// <summary>
  76. /// 设备变量监控
  77. /// </summary>
  78. public ObservableCollection<VariableMonitor> variableMonitors { get; set; } = new ObservableCollection<VariableMonitor>();
  79. /// <summary>
  80. /// 外设状态,硬件设备数据
  81. /// </summary>
  82. protected ConcurrentDictionary<string, object> peripheralStatus = new ConcurrentDictionary<string, object>();
  83. /// <summary>
  84. /// 外设设备集合
  85. /// </summary>
  86. private List<IPeripheral> peripherals;
  87. public Action<int, object> AddErrorAction { get; set; }
  88. public Action<int, object> DeleteErrorAction { get; set; }
  89. public List<Alarm> alarms { get; set; } = new List<Alarm>();
  90. public IAlarm InterfaceAlarm { get; set; }
  91. public AlarmHelper alarmHelper { get; set; } = new AlarmHelper();
  92. public IStatus InterfaceStatus { get; set; }
  93. #endregion
  94. /// <summary>
  95. /// 设备过程日志显示
  96. /// </summary>
  97. /// <param name="info"></param>
  98. public void DeviceProcessLogShow(string info)
  99. {
  100. Log.Insert(0, new { Time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), Type = "流程", Text = info });
  101. MessageLog.GetInstance.DeviceProcessLogShow(DeviceId.ToString(), info);
  102. if (Log.Count > 100) { Log.RemoveAt(Log.Count - 1); }
  103. }
  104. public void Initliaze()
  105. {
  106. }
  107. public void Initliaze(List<IPeripheral> peripherals)
  108. {
  109. peripherals.ForEach(p =>
  110. {
  111. p.DeviceId = this.DeviceId;
  112. p.Init();
  113. });
  114. this.peripherals = peripherals;
  115. }
  116. public virtual void StartMain()
  117. {
  118. ThreadManage.GetInstance().StartLong(new Action(() =>
  119. {
  120. foreach (var peripheral in peripherals)
  121. {
  122. string TypeName = peripheral.GetType().FullName.Replace("BPASmartClient.", "");
  123. Status.Update($"{TypeName}.IsConnected", peripheral.IsConnected);
  124. Status.Update($"{TypeName}.IsWork", peripheral.IsWork);
  125. foreach (var key in peripheral.GetAllStatus().Keys)
  126. {
  127. peripheralStatus[key] = peripheral.GetAllStatus()[key];
  128. if (TypeName != "PLC.PLCMachine")
  129. {
  130. Status.Update($"{TypeName}.{key}", peripheral.GetAllStatus()[key]);
  131. }
  132. }
  133. }
  134. if (AddErrorAction != null && DeleteErrorAction != null)
  135. {
  136. foreach (var item in Status.GetStatusT())
  137. {
  138. if (item.Name == "Warning" || item.Name == "Fault")
  139. {
  140. if (item.Status != "无故障" && item.Status != "无警告" && item.Status != "未发生故障")
  141. {
  142. var res = Error?.FirstOrDefault(p => p.GetType().GetProperty("Text").GetValue(p).ToString() == item.Ms);
  143. if (res == null)
  144. {
  145. object obj = new
  146. {
  147. Time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
  148. Type = item.Name == "Warning" ? "警告" : "故障",
  149. Text = item.Ms
  150. };
  151. Error.Add(obj);
  152. AddErrorAction?.Invoke(DeviceId, obj);
  153. }
  154. }
  155. else
  156. {
  157. var res = Error?.FirstOrDefault(p => p.GetType().GetProperty("Text").GetValue(p).ToString().Contains(item.id));
  158. if (res != null)
  159. {
  160. Error.Remove(res);
  161. DeleteErrorAction?.Invoke(DeviceId, res);
  162. }
  163. }
  164. }
  165. }
  166. }
  167. Thread.Sleep(100);
  168. }), $"GetAllStatus:{DeviceId}");
  169. DoMain();
  170. GetGvlStatus();
  171. InitResetTask();
  172. InitTask();
  173. }
  174. private void ResetStatus()
  175. {
  176. this.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).ToList().ForEach(item =>
  177. {
  178. var res = item.FieldType.GetInterfaces();
  179. if (res != null)
  180. {
  181. foreach (var faces in res)
  182. {
  183. if (faces.Name == "IStatus") InterfaceStatus = item.GetValue(this) as IStatus;
  184. }
  185. }
  186. });
  187. }
  188. private void GetGvlStatus()
  189. {
  190. this.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).ToList().ForEach(item =>
  191. {
  192. var res = item.FieldType.GetInterfaces();
  193. if (res != null)
  194. {
  195. foreach (var faces in res)
  196. {
  197. if (faces.Name == "IStatus")
  198. {
  199. InterfaceStatus = item.GetValue(this) as IStatus;
  200. GetMonitorData(InterfaceStatus);
  201. }
  202. else if (faces.Name == "IAlarm")
  203. {
  204. InterfaceAlarm = item.GetValue(this) as IAlarm;
  205. alarmHelper.AddAction += new Action<string>((s) =>
  206. {
  207. var res = alarmHelper.Alarms.FirstOrDefault(p => p.Info == s);
  208. if (res != null)
  209. {
  210. object obj = new
  211. {
  212. Time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
  213. Type = res.Grade,
  214. Text = res.Info
  215. };
  216. Error.Insert(0, obj);
  217. AddErrorAction?.Invoke(DeviceId, obj);
  218. }
  219. });
  220. alarmHelper.RemoveAction += new Action<string>((s) =>
  221. {
  222. var res = Error.FirstOrDefault(p => p.GetType().GetProperty("Text").GetValue(p).ToString() == s);
  223. if (res != null && Error.Contains(res))
  224. {
  225. Error.Remove(res);
  226. DeleteErrorAction?.Invoke(DeviceId, res);
  227. }
  228. });
  229. ThreadManage.GetInstance().StartLong(new Action(() =>
  230. {
  231. AlarmMonitoring();
  232. Thread.Sleep(500);
  233. }), $"报警检测监控:{DeviceId}");
  234. }
  235. }
  236. }
  237. });
  238. }
  239. /// <summary>
  240. /// 报警监控
  241. /// </summary>
  242. /// <param name="alarm"></param>
  243. /// <param name="alarmHelper"></param>
  244. private void AlarmMonitoring()
  245. {
  246. if (InterfaceAlarm == null) return;
  247. foreach (var item in InterfaceAlarm.GetType().GetProperties())
  248. {
  249. var res = item.GetValue(InterfaceAlarm);
  250. if (res != null && res is bool blen)
  251. {
  252. if (item.CustomAttributes.Count() > 0 && item.CustomAttributes.ElementAt(0)?.ConstructorArguments.Count() > 0)
  253. {
  254. var info = item.GetCustomAttribute<AlarmAttribute>().AlarmInfo;
  255. if (info != null) alarmHelper.EdgeAlarm(blen, $"{info.ToString()}-{DeviceId}");
  256. }
  257. }
  258. }
  259. }
  260. private void InitResetTask()
  261. {
  262. #region 复位程序
  263. ThreadManage.GetInstance().StartLong(new Action(() =>
  264. {
  265. if (RTrig.GetInstance($"ResetProgram:{DeviceId}").Start(Initing))
  266. {
  267. ThreadManage.GetInstance().StopTask($"MainTask:{DeviceId}", new Action(() =>
  268. {
  269. ThreadManage.GetInstance().StopTask($"ReadData:{DeviceId}", new Action(() =>
  270. {
  271. ThreadManage.GetInstance().StopTask($"GvlStatusMonitor:{DeviceId}", new Action(() =>
  272. {
  273. ResetProgram();
  274. ResetStatus();
  275. InitTask();
  276. }));
  277. }));
  278. }));
  279. }
  280. Thread.Sleep(10);
  281. }), $"ResetProgram:{DeviceId}");
  282. #endregion
  283. }
  284. private void InitTask()
  285. {
  286. #region 数据读取
  287. ThreadManage.GetInstance().StartLong(new Action(() =>
  288. {
  289. ReadData();
  290. Thread.Sleep(10);
  291. }), $"ReadData:{DeviceId}");
  292. #endregion
  293. #region 任务流程
  294. ThreadManage.GetInstance().StartLong(new Action(() =>
  295. {
  296. MainTask();
  297. Thread.Sleep(10);
  298. }), $"MainTask:{DeviceId}");
  299. #endregion
  300. #region 设备状态监控
  301. ThreadManage.GetInstance().StartLong(new Action(() =>
  302. {
  303. UpdateValue(InterfaceStatus);
  304. Thread.Sleep(1000);
  305. }), $"GvlStatusMonitor:{DeviceId}");
  306. #endregion
  307. }
  308. /// <summary>
  309. /// 获取监控信息
  310. /// </summary>
  311. private void GetMonitorData(IStatus status)
  312. {
  313. if (status == null) return;
  314. foreach (var item in status.GetType().GetProperties())
  315. {
  316. if (item.CustomAttributes.Count() > 0)
  317. {
  318. var attributeName = item.CustomAttributes.FirstOrDefault(p => p.AttributeType.Name == "VariableMonitorAttribute");
  319. if (attributeName == null) return;
  320. var plcadd = item.GetCustomAttribute<VariableMonitorAttribute>()?.PLCAddress;
  321. var modadd = item.GetCustomAttribute<VariableMonitorAttribute>()?.ModbusTcpAddress;
  322. var notes = item.GetCustomAttribute<VariableMonitorAttribute>()?.Notes;
  323. if (item.PropertyType?.BaseType?.Name == "Array")
  324. {
  325. if (plcadd?.Length > 0)
  326. {
  327. var arrayRes = item.GetValue(status, null);
  328. if (arrayRes != null && arrayRes is Array arr)
  329. {
  330. for (int i = 0; i < arr.Length; i++)
  331. {
  332. var res = variableMonitors.FirstOrDefault(p => p.VarName == $"{item.Name}_{i + 1}");
  333. if (res == null)
  334. {
  335. string[] plc = plcadd?.Substring(1).Split('.');
  336. string TempPlcAddress = string.Empty;
  337. if (plc?.Length == 2)
  338. {
  339. int add = int.Parse(plc[1]);
  340. int firstAdd = int.Parse(plc[0]);
  341. if (add >= 0 && add < 7)
  342. {
  343. add += i;
  344. }
  345. else if (add >= 7)
  346. {
  347. add = 0;
  348. firstAdd++;
  349. }
  350. plc[0] = firstAdd.ToString();
  351. plc[1] = add.ToString();
  352. TempPlcAddress = $"M{plc[0]}.{plc[1]}";
  353. }
  354. variableMonitors.Add(new VariableMonitor()
  355. {
  356. Id = variableMonitors.Count,
  357. VarName = $"{item.Name}_{i + 1}",
  358. Notes = $"{notes}_{i + 1}",
  359. ModbusTcpAddress = $"{int.Parse(modadd) + i}",
  360. PLCAddress = TempPlcAddress,
  361. });
  362. }
  363. }
  364. }
  365. }
  366. else
  367. {
  368. var arrayRes = item.GetValue(status, null);
  369. if (arrayRes != null && arrayRes is Array arr)
  370. {
  371. for (int i = 0; i < arr.Length; i++)
  372. {
  373. var res = variableMonitors.FirstOrDefault(p => p.VarName == $"{item.Name}_{i + 1}");
  374. if (res == null)
  375. {
  376. variableMonitors.Add(new VariableMonitor()
  377. {
  378. Id = variableMonitors.Count,
  379. VarName = $"{item.Name}_{i + 1}",
  380. Notes = $"{notes}_{i + 1}",
  381. });
  382. }
  383. }
  384. }
  385. }
  386. }
  387. else
  388. {
  389. var res = variableMonitors.FirstOrDefault(p => p.VarName == item.Name);
  390. if (res == null)
  391. {
  392. variableMonitors.Add(new VariableMonitor()
  393. {
  394. Id = variableMonitors.Count,
  395. VarName = item.Name,
  396. Notes = notes,
  397. ModbusTcpAddress = modadd,
  398. PLCAddress = plcadd,
  399. });
  400. }
  401. }
  402. }
  403. }
  404. }
  405. /// <summary>
  406. /// 更新数据
  407. /// </summary>
  408. /// <param name="status"></param>
  409. public void UpdateValue(IStatus status)
  410. {
  411. if (status == null) return;
  412. foreach (var item in status.GetType().GetProperties())
  413. {
  414. if (item.CustomAttributes.Count() > 0)
  415. {
  416. if (item.PropertyType?.BaseType?.Name == "Array")
  417. {
  418. var arrayRes = item.GetValue(status);
  419. if (arrayRes != null && arrayRes is Array arr)
  420. {
  421. for (int i = 0; i < arr.Length; i++)
  422. {
  423. int index = Array.FindIndex(variableMonitors.ToArray(), p => p.VarName == $"{item.Name}_{i + 1}");
  424. if (index >= 0 && index < variableMonitors.Count)
  425. {
  426. variableMonitors.ElementAt(index).CurrentValue = arr.GetValue(i)?.ToString();
  427. }
  428. }
  429. }
  430. }
  431. else
  432. {
  433. int index = Array.FindIndex(variableMonitors.ToArray(), p => p.VarName == item.Name);
  434. if (index >= 0 && index < variableMonitors.Count)
  435. {
  436. variableMonitors.ElementAt(index).CurrentValue = item.GetValue(status)?.ToString();
  437. }
  438. }
  439. }
  440. }
  441. }
  442. public abstract void DoMain();
  443. public abstract void Stop();
  444. /// <summary>
  445. /// 数据读取
  446. /// </summary>
  447. public abstract void ReadData();
  448. /// <summary>
  449. /// 主流程控制
  450. /// </summary>
  451. public abstract void MainTask();
  452. /// <summary>
  453. /// 复位程序
  454. /// </summary>
  455. public abstract void ResetProgram();
  456. public object GetError()
  457. {
  458. return new { data = Error };
  459. }
  460. public object GetLog()
  461. {
  462. return new { data = Log };
  463. }
  464. public object GetVariableMonitor()
  465. {
  466. return new { data = variableMonitors };
  467. }
  468. /// <summary>
  469. /// 获取某个对象中的属性值
  470. /// </summary>
  471. /// <param name="info"></param>
  472. /// <param name="field"></param>
  473. /// <returns></returns>
  474. public object GetPropertyValue(object info, string field)
  475. {
  476. if (info == null) return null;
  477. Type t = info.GetType();
  478. IEnumerable<System.Reflection.PropertyInfo> property = from pi in t.GetProperties() where pi.Name.ToLower() == field.ToLower() select pi;
  479. return property.First().GetValue(info, null);
  480. }
  481. }
  482. }