终端一体化运控平台
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

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