终端一体化运控平台
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.
 
 
 

512 lines
20 KiB

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