终端一体化运控平台
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 

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