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

515 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.Add(new { Time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), Type = "流程", Text = info });
  95. MessageLog.GetInstance.DeviceProcessLogShow(DeviceId.ToString(), info);
  96. }
  97. public void Initliaze()
  98. {
  99. }
  100. public void Initliaze(List<IPeripheral> peripherals)
  101. {
  102. peripherals.ForEach(p =>
  103. {
  104. p.DeviceId = this.DeviceId;
  105. p.Init();
  106. });
  107. this.peripherals = peripherals;
  108. }
  109. public virtual void StartMain()
  110. {
  111. #region 测试添加几个日志与告警
  112. Error.Add(new { Time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), Type = "落碗", Text = "落碗异常" });
  113. Error.Add(new { Time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), Type = "煮面机", Text = "煮面机温度异常" });
  114. Log.Add(new { Time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), Type = "初始化", Text = "初始化已完成" });
  115. Log.Add(new { Time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), Type = "启动中", Text = "已完成外设启动" });
  116. #endregion
  117. ThreadManage.GetInstance().StartLong(new Action(() =>
  118. {
  119. foreach (var peripheral in peripherals)
  120. {
  121. string TypeName = peripheral.GetType().FullName.Replace("BPASmartClient.", "");
  122. Status.Update($"{TypeName}.IsConnected", peripheral.IsConnected);
  123. Status.Update($"{TypeName}.IsWork", peripheral.IsWork);
  124. foreach (var key in peripheral.GetAllStatus().Keys)
  125. {
  126. peripheralStatus[key] = peripheral.GetAllStatus()[key];
  127. if (TypeName != "PLC.MorksMachine")
  128. {
  129. Status.Update($"{TypeName}.{key}", peripheral.GetAllStatus()[key]);
  130. }
  131. }
  132. }
  133. if (AddErrorAction != null && DeleteErrorAction != null)
  134. {
  135. foreach (var item in Status.GetStatusT())
  136. {
  137. if (item.Name == "Warning" || item.Name == "Fault")
  138. {
  139. if (item.Status != "无故障" && item.Status != "无警告" && item.Status != "未发生故障")
  140. {
  141. var res = Error?.FirstOrDefault(p => p.GetType().GetProperty("Text").GetValue(p).ToString() == item.Ms);
  142. if (res == null)
  143. {
  144. object obj = new
  145. {
  146. Time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
  147. Type = item.Name == "Warning" ? "警告" : "故障",
  148. Text = item.Ms
  149. };
  150. Error.Add(obj);
  151. AddErrorAction?.Invoke(DeviceId,obj);
  152. }
  153. }
  154. else
  155. {
  156. var res = Error?.FirstOrDefault(p => p.GetType().GetProperty("Text").GetValue(p).ToString().Contains(item.id));
  157. if (res != null)
  158. {
  159. Error.Remove(res);
  160. DeleteErrorAction?.Invoke(DeviceId,res);
  161. }
  162. }
  163. }
  164. }
  165. }
  166. Thread.Sleep(100);
  167. }), $"GetAllStatus:{DeviceId}");
  168. DoMain();
  169. GetGvlStatus();
  170. InitResetTask();
  171. InitTask();
  172. }
  173. private void GetGvlStatus()
  174. {
  175. this.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).ToList().ForEach(item =>
  176. {
  177. var res = item.FieldType.GetInterfaces();
  178. if (res != null)
  179. {
  180. foreach (var faces in res)
  181. {
  182. if (faces.Name == "IStatus")
  183. {
  184. IStatus status = item.GetValue(this) as IStatus;
  185. GetMonitorData(status);
  186. ThreadManage.GetInstance().StopTask($"{item.Name}:{DeviceId}", new Action(() =>
  187. {
  188. ThreadManage.GetInstance().StartLong(new Action(() =>
  189. {
  190. UpdateValue(status);
  191. Thread.Sleep(1000);
  192. }), $"{item.Name}:{DeviceId}");
  193. }));
  194. }
  195. else if (faces.Name == "IAlarm")
  196. {
  197. IAlarm alarm = item.GetValue(this) as IAlarm;
  198. AlarmHelper alarmHelper = new AlarmHelper();
  199. alarmHelper.AddAction = new Action<string>((s) =>
  200. {
  201. var res = alarmHelper.Alarms.FirstOrDefault(p => p.Info == s);
  202. if (res != null)
  203. {
  204. object obj = new
  205. {
  206. Time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
  207. Type = res.Grade,
  208. Text = res.Info
  209. };
  210. Error.Add(obj);
  211. AddErrorAction?.Invoke(DeviceId, obj);
  212. }
  213. });
  214. alarmHelper.RemoveAction = new Action<string>((s) =>
  215. {
  216. var res = Error.FirstOrDefault(p => p.GetType().GetProperty("Text").GetValue(p).ToString() == s);
  217. if (res != null && Error.Contains(res))
  218. {
  219. Error.Remove(res);
  220. DeleteErrorAction?.Invoke(DeviceId, res);
  221. }
  222. });
  223. ThreadManage.GetInstance().StartLong(new Action(() =>
  224. {
  225. AlarmMonitoring(alarm, alarmHelper);
  226. Thread.Sleep(500);
  227. }), $"报警检测监控:{DeviceId}");
  228. }
  229. }
  230. }
  231. });
  232. }
  233. /// <summary>
  234. /// 报警监控
  235. /// </summary>
  236. /// <param name="alarm"></param>
  237. /// <param name="alarmHelper"></param>
  238. private void AlarmMonitoring(IAlarm alarm, AlarmHelper alarmHelper)
  239. {
  240. if (alarm == null) return;
  241. foreach (var item in alarm.GetType().GetProperties())
  242. {
  243. var res = item.GetValue(alarm);
  244. if (res != null && res is bool blen)
  245. {
  246. if (item.CustomAttributes.Count() > 0 && item.CustomAttributes.ElementAt(0)?.ConstructorArguments.Count() > 0)
  247. {
  248. var info = item.CustomAttributes.ElementAt(0)?.ConstructorArguments.ElementAt(0).Value;
  249. if (info != null) alarmHelper.EdgeAlarm(blen, info.ToString());
  250. }
  251. }
  252. }
  253. }
  254. private void InitResetTask()
  255. {
  256. #region 复位程序
  257. ThreadManage.GetInstance().StartLong(new Action(() =>
  258. {
  259. if (RTrig.GetInstance($"ResetProgram:{DeviceId}").Start(Initing))
  260. {
  261. ThreadManage.GetInstance().StopTask($"MainTask:{DeviceId}", new Action(() =>
  262. {
  263. ThreadManage.GetInstance().StopTask($"ReadData:{DeviceId}", new Action(() =>
  264. {
  265. ResetProgram();
  266. InitTask();
  267. }));
  268. }));
  269. }
  270. Thread.Sleep(10);
  271. }), $"ResetProgram:{DeviceId}");
  272. #endregion
  273. }
  274. private void InitTask()
  275. {
  276. #region 数据读取
  277. ThreadManage.GetInstance().StartLong(new Action(() =>
  278. {
  279. ReadData();
  280. Thread.Sleep(10);
  281. }), $"ReadData:{DeviceId}");
  282. #endregion
  283. #region 任务流程
  284. ThreadManage.GetInstance().StartLong(new Action(() =>
  285. {
  286. MainTask();
  287. Thread.Sleep(10);
  288. }), $"MainTask:{DeviceId}");
  289. #endregion
  290. }
  291. /// <summary>
  292. /// 获取流程信息
  293. /// </summary>
  294. private void GetMonitorData(IStatus status)
  295. {
  296. if (status == null) return;
  297. foreach (var item in status.GetType().GetProperties())
  298. {
  299. if (item.CustomAttributes.Count() > 0)
  300. {
  301. var attributeName = item.CustomAttributes.FirstOrDefault(p => p.AttributeType.Name == "VariableMonitorAttribute");
  302. if (attributeName == null) return;
  303. var plcadd = item.GetCustomAttribute<VariableMonitorAttribute>()?.PLCAddress;
  304. var modadd = item.GetCustomAttribute<VariableMonitorAttribute>()?.ModbusTcpAddress;
  305. var notes = item.GetCustomAttribute<VariableMonitorAttribute>()?.Notes;
  306. if (item.PropertyType?.BaseType?.Name == "Array")
  307. {
  308. if (plcadd?.Length > 0)
  309. {
  310. var arrayRes = item.GetValue(status, null);
  311. if (arrayRes != null && arrayRes is Array arr)
  312. {
  313. for (int i = 0; i < arr.Length; i++)
  314. {
  315. var res = variableMonitors.FirstOrDefault(p => p.VarName == $"{item.Name}_{i + 1}");
  316. if (res == null)
  317. {
  318. string[] plc = plcadd?.Substring(1).Split('.');
  319. string TempPlcAddress = string.Empty;
  320. if (plc?.Length == 2)
  321. {
  322. int add = int.Parse(plc[1]);
  323. int firstAdd = int.Parse(plc[0]);
  324. if (add >= 0 && add < 7)
  325. {
  326. add += i;
  327. }
  328. else if (add >= 7)
  329. {
  330. add = 0;
  331. firstAdd++;
  332. }
  333. plc[0] = firstAdd.ToString();
  334. plc[1] = add.ToString();
  335. TempPlcAddress = $"M{plc[0]}.{plc[1]}";
  336. }
  337. variableMonitors.Add(new VariableMonitor()
  338. {
  339. Id = variableMonitors.Count,
  340. VarName = $"{item.Name}_{i + 1}",
  341. Notes = $"{notes}_{i + 1}",
  342. ModbusTcpAddress = $"{int.Parse(modadd) + i}",
  343. PLCAddress = TempPlcAddress,
  344. });
  345. }
  346. }
  347. }
  348. }
  349. else
  350. {
  351. var arrayRes = item.GetValue(status, null);
  352. if (arrayRes != null && arrayRes is Array arr)
  353. {
  354. for (int i = 0; i < arr.Length; i++)
  355. {
  356. var res = variableMonitors.FirstOrDefault(p => p.VarName == $"{item.Name}_{i + 1}");
  357. if (res == null)
  358. {
  359. variableMonitors.Add(new VariableMonitor()
  360. {
  361. Id = variableMonitors.Count,
  362. VarName = $"{item.Name}_{i + 1}",
  363. Notes = $"{notes}_{i + 1}",
  364. });
  365. }
  366. }
  367. }
  368. }
  369. }
  370. else
  371. {
  372. var res = variableMonitors.FirstOrDefault(p => p.VarName == item.Name);
  373. if (res == null)
  374. {
  375. variableMonitors.Add(new VariableMonitor()
  376. {
  377. Id = variableMonitors.Count,
  378. VarName = item.Name,
  379. Notes = notes,
  380. ModbusTcpAddress = modadd,
  381. PLCAddress = plcadd,
  382. });
  383. }
  384. }
  385. }
  386. }
  387. }
  388. /// <summary>
  389. /// 更新数据
  390. /// </summary>
  391. /// <param name="status"></param>
  392. public void UpdateValue(IStatus status)
  393. {
  394. if (status == null) return;
  395. foreach (var item in status.GetType().GetProperties())
  396. {
  397. if (item.CustomAttributes.Count() > 0)
  398. {
  399. if (item.PropertyType?.BaseType?.Name == "Array")
  400. {
  401. var arrayRes = item.GetValue(status);
  402. if (arrayRes != null && arrayRes is Array arr)
  403. {
  404. for (int i = 0; i < arr.Length; i++)
  405. {
  406. int index = Array.FindIndex(variableMonitors.ToArray(), p => p.VarName == $"{item.Name}_{i + 1}");
  407. if (index >= 0 && index < variableMonitors.Count)
  408. {
  409. variableMonitors.ElementAt(index).CurrentValue = arr.GetValue(i)?.ToString();
  410. }
  411. }
  412. }
  413. }
  414. else
  415. {
  416. int index = Array.FindIndex(variableMonitors.ToArray(), p => p.VarName == item.Name);
  417. if (index >= 0 && index < variableMonitors.Count)
  418. {
  419. variableMonitors.ElementAt(index).CurrentValue = item.GetValue(status)?.ToString();
  420. }
  421. }
  422. }
  423. }
  424. }
  425. public abstract void DoMain();
  426. public abstract void Stop();
  427. /// <summary>
  428. /// 数据读取
  429. /// </summary>
  430. public abstract void ReadData();
  431. /// <summary>
  432. /// 主流程控制
  433. /// </summary>
  434. public abstract void MainTask();
  435. /// <summary>
  436. /// 复位程序
  437. /// </summary>
  438. public abstract void ResetProgram();
  439. public object GetError()
  440. {
  441. return new { data = Error };
  442. }
  443. public object GetLog()
  444. {
  445. return new { data = Log };
  446. }
  447. public object GetVariableMonitor()
  448. {
  449. return new { data = variableMonitors };
  450. }
  451. /// <summary>
  452. /// 获取某个对象中的属性值
  453. /// </summary>
  454. /// <param name="info"></param>
  455. /// <param name="field"></param>
  456. /// <returns></returns>
  457. public object GetPropertyValue(object info, string field)
  458. {
  459. if (info == null) return null;
  460. Type t = info.GetType();
  461. IEnumerable<System.Reflection.PropertyInfo> property = from pi in t.GetProperties() where pi.Name.ToLower() == field.ToLower() select pi;
  462. return property.First().GetValue(info, null);
  463. }
  464. }
  465. }