终端一体化运控平台
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 

555 строки
21 KiB

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