LeadOpcUaClientHelper.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. using System;
  2. using System.Collections.Concurrent;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7. using NX_CommonClassLibrary;
  8. using NX_LogClassLibrary;
  9. using NX_ModelClassLibrary.BaseModel;
  10. using NX_ModelClassLibrary.CustomEnum;
  11. using NX_ModelClassLibrary.CustomEvent;
  12. using NX_ModelClassLibrary.OpcModel;
  13. using NX_WcsDal.CommonBusiness;
  14. using Opc.Ua;
  15. using Opc.Ua.Client;
  16. using Opc.Ua.Configuration;
  17. using OpcUaHelper;
  18. namespace NX_OpcUaClientLibrary
  19. {
  20. /// <summary>
  21. /// OpcUa客户端帮助类
  22. /// 基于OPC基金会开源的.net版本OPCUA客户端项目的二次封装
  23. /// Copyright20210125 (C) sunyalong
  24. /// 允许修改、添加满足自己项目的需要。
  25. /// 添加、修改后请详细注释。违者会强制删除不予采用。
  26. /// </summary>
  27. public class LeadOpcUaClientHelper
  28. {
  29. #region 单例模式
  30. /// <summary>
  31. /// 单例模式对象
  32. /// </summary>
  33. private static LeadOpcUaClientHelper _instance = null;
  34. private static readonly object lockObj = new object();
  35. /// <summary>
  36. /// 单例模式方法
  37. /// </summary>
  38. public static LeadOpcUaClientHelper Instance
  39. {
  40. get
  41. {
  42. if (_instance == null)
  43. {
  44. lock (lockObj)
  45. {
  46. if (_instance == null)
  47. {
  48. _instance = new LeadOpcUaClientHelper();
  49. }
  50. }
  51. }
  52. return _instance;
  53. }
  54. }
  55. #endregion
  56. #region 全局变量
  57. /// <summary>
  58. /// 日志显示帮助类对象
  59. /// </summary>
  60. public ShowLogToFrmHelper showLogToFrm = new ShowLogToFrmHelper();
  61. /// <summary>
  62. /// 日志头部
  63. /// </summary>
  64. private readonly string LogHeadText = "OpcUa客户端帮助类 ==>> ";
  65. /// <summary>
  66. /// OPCUA客户端列表
  67. /// </summary>
  68. private ConcurrentDictionary<BasWcsPlcMd, OpcUaClient> opcUaClientLst = new ConcurrentDictionary<BasWcsPlcMd, OpcUaClient>();
  69. /// <summary>
  70. /// 所有设备OPCItem变量信息列表
  71. /// </summary>
  72. public List<WcsOpcItemMd> allOpcItemList;
  73. #region 2021 0602 孙亚龙注释掉旧版代码
  74. ///// <summary>
  75. ///// 堆垛机OpcUa客户端
  76. ///// </summary>
  77. //private OpcUaClient crn_OpcUaClient;
  78. ///// <summary>
  79. ///// 输送线OpcUa客户端
  80. ///// </summary>
  81. //private OpcUaClient tran_OpcUaClient;
  82. ///// <summary>
  83. ///// 堆垛机OPC UA服务器地址
  84. ///// </summary>
  85. //private readonly string CrnOpcUaServerIpAddress = AppConfigHelper.Get("CrnOpcUaServerIpAddress");
  86. ///// <summary>
  87. ///// 输送线OPC UA服务器地址
  88. ///// </summary>
  89. //private readonly string TranOpcUaServerIpAddress = AppConfigHelper.Get("TranOpcUaServerIpAddress");
  90. ///// <summary>
  91. ///// 堆垛机OPC UA服务器连接状态
  92. ///// </summary>
  93. //private bool CrnOpcUaServerConnStatus = false;
  94. ///// <summary>
  95. ///// 输送线OPC UA服务器连接状态
  96. ///// </summary>
  97. //private bool TranOpcUaServerConnStatus = false;
  98. #endregion 2021 0602 孙亚龙注释掉旧版代码
  99. #endregion
  100. /// <summary>
  101. /// 连接所有PLC的OPCUa服务器,并设置PLC的OPCItem变量为订阅模式。
  102. /// </summary>
  103. /// <param name="basWcsPlcMdList">WCS涉及的所有PLC信息列表</param>
  104. /// <returns></returns>
  105. public bool ConnAllOpcUaServer(List<BasWcsPlcMd> basWcsPlcMdList)
  106. {
  107. try
  108. {
  109. foreach (BasWcsPlcMd item in basWcsPlcMdList)
  110. {
  111. if (opcUaClientLst.TryAdd(item, new OpcUaClient { UserIdentity = new UserIdentity("Administrator", "123456") }))
  112. {
  113. opcUaClientLst[item].ConnectServer(item.IpAddr);
  114. ShowLogToForm($"OpcUa客户端连接OpcUa服务器成功!IP地址:【{item.IpAddr}】", true, LogTypeEnum.Run);
  115. }
  116. }
  117. foreach (var item in opcUaClientLst)
  118. {
  119. string[] MonitorNodeTagArr = allOpcItemList.FindAll(x => x.PlcCode == item.Key.PlcCode).Select(x => x.OpcItemPos).ToArray();
  120. item.Value.AddSubscription(item.Key.PlcCode, MonitorNodeTagArr, SubCallback);
  121. ShowLogToForm($"OpcUa客户端设置OpcItem订阅模式成功!IP地址:【{item.Key.IpAddr}】", true, LogTypeEnum.Run);
  122. }
  123. return true;
  124. }
  125. catch (Exception ex)
  126. {
  127. ShowLogToForm($"OpcUa客户端连接OpcUa服务器发生异常:【{ex.Message}】!", true, LogTypeEnum.Err);
  128. return false;
  129. }
  130. }
  131. #region 2021 0602 孙亚龙注释掉旧版代码
  132. //public async Task<bool> ConnCrnOpcUaServer()
  133. //{
  134. // try
  135. // {
  136. // crn_OpcUaClient = new OpcUaClient
  137. // {
  138. // UserIdentity = new UserIdentity("Administrator", "123456")
  139. // };
  140. // await crn_OpcUaClient.ConnectServer(CrnOpcUaServerIpAddress);
  141. // ShowLogToForm($"堆垛机OpcUa客户端连接Opc服务器成功!IP地址:【{CrnOpcUaServerIpAddress}】", true, LogTypeEnum.Run);
  142. // CrnOpcUaServerConnStatus = true;
  143. // return true;
  144. // }
  145. // catch (Exception ex)
  146. // {
  147. // ShowLogToForm($"堆垛机OpcUa客户端连接Opc服务器发生异常:【{ex.Message}】!IP地址:【{CrnOpcUaServerIpAddress}】", true, LogTypeEnum.Err);
  148. // CrnOpcUaServerConnStatus = false;
  149. // return false;
  150. // }
  151. //}
  152. //public async Task<bool> ConnTranOpcUaServer()
  153. //{
  154. // try
  155. // {
  156. // tran_OpcUaClient = new OpcUaClient
  157. // {
  158. // UserIdentity = new UserIdentity("Administrator", "123456")
  159. // };
  160. // await tran_OpcUaClient.ConnectServer(TranOpcUaServerIpAddress);
  161. // ShowLogToForm($"输送线OpcUa客户端连接Opc服务器成功!IP地址:【{TranOpcUaServerIpAddress}】", true, LogTypeEnum.Run);
  162. // TranOpcUaServerConnStatus = true;
  163. // return true;
  164. // }
  165. // catch (Exception ex)
  166. // {
  167. // ShowLogToForm($"输送线OpcUa客户端连接Opc服务器发生异常:【{ex.Message}】!IP地址:【{TranOpcUaServerIpAddress}】", true, LogTypeEnum.Err);
  168. // TranOpcUaServerConnStatus = false;
  169. // return false;
  170. // }
  171. //}
  172. //public bool SetOpcItemSubscription()
  173. //{
  174. // try
  175. // {
  176. // List<string> MonitorNodeTags_Crn = new List<string>();
  177. // List<string> MonitorNodeTags_Tran = new List<string>();
  178. // foreach (WcsOpcItemMd item in allOpcItemList)
  179. // {
  180. // if (item.PlcCode == "CrnPlc001")
  181. // {
  182. // MonitorNodeTags_Crn.Add(item.OpcItemPos);
  183. // }
  184. // if (item.PlcCode == "TranPlc001")
  185. // {
  186. // MonitorNodeTags_Tran.Add(item.OpcItemPos);
  187. // }
  188. // }
  189. // crn_OpcUaClient.AddSubscription("Crn", MonitorNodeTags_Crn.ToArray(), SubCallback);
  190. // ShowLogToForm($"堆垛机设置OpcItem订阅模式成功!", true, LogTypeEnum.Run);
  191. // tran_OpcUaClient.AddSubscription("Tran", MonitorNodeTags_Tran.ToArray(), SubCallback);
  192. // ShowLogToForm($"输送线设置OpcItem订阅模式成功!", true, LogTypeEnum.Run);
  193. // return true;
  194. // }
  195. // catch (Exception ex)
  196. // {
  197. // ShowLogToForm($"堆垛机设置OpcItem订阅模式发生异常:【{ex.Message}】!", true, LogTypeEnum.Err);
  198. // ShowLogToForm($"输送线设置OpcItem订阅模式发生异常:【{ex.Message}】!", true, LogTypeEnum.Err);
  199. // return false;
  200. // }
  201. //}
  202. #endregion 2021 0602 孙亚龙注释掉旧版代码
  203. private void SubCallback(string key, MonitoredItem monitoredItem, MonitoredItemNotificationEventArgs args)
  204. {
  205. MonitoredItemNotification notification = args.NotificationValue as MonitoredItemNotification;
  206. WcsOpcItemMd tmpMonitoredOpcItem = allOpcItemList.FirstOrDefault(x => x.OpcItemPos == monitoredItem.StartNodeId.ToString() && x.PlcCode == key);
  207. if (tmpMonitoredOpcItem != null)
  208. {
  209. tmpMonitoredOpcItem.OpcItemValue = notification.Value.WrappedValue.Value.ToString();
  210. Task.Run(() => {
  211. BasCommon_Dal.Instance.UpdateOpcItemMonitorToDataBase(tmpMonitoredOpcItem);
  212. });
  213. }
  214. #region 2021 0602 孙亚龙注释掉旧版代码
  215. //if (key == "Crn")
  216. //{
  217. // MonitoredItemNotification notification = args.NotificationValue as MonitoredItemNotification;
  218. // WcsOpcItemMd tmpMonitoredOpcItem = allOpcItemList.FirstOrDefault(x => x.OpcItemPos == monitoredItem.StartNodeId.ToString() && x.PlcCode == "CrnPlc001");
  219. // if (tmpMonitoredOpcItem != null)
  220. // {
  221. // tmpMonitoredOpcItem.OpcItemValue = notification.Value.WrappedValue.Value.ToString();
  222. // Task.Run(() =>
  223. // {
  224. // BasCommon_Dal.Instance.UpdateOpcItemMonitorToDataBase(tmpMonitoredOpcItem);
  225. // });
  226. // }
  227. //}
  228. //else if (key == "Tran")
  229. //{
  230. // MonitoredItemNotification notification = args.NotificationValue as MonitoredItemNotification;
  231. // WcsOpcItemMd tmpMonitoredOpcItem = allOpcItemList.FirstOrDefault(x => x.OpcItemPos == monitoredItem.StartNodeId.ToString() && x.PlcCode == "TranPlc001");
  232. // if (tmpMonitoredOpcItem != null)
  233. // {
  234. // tmpMonitoredOpcItem.OpcItemValue = notification.Value.WrappedValue.Value.ToString();
  235. // Task.Run(() =>
  236. // {
  237. // BasCommon_Dal.Instance.UpdateOpcItemMonitorToDataBase(tmpMonitoredOpcItem);
  238. // });
  239. // }
  240. //}
  241. #endregion 2021 0602 孙亚龙注释掉旧版代码
  242. }
  243. /// <summary>
  244. /// 写入OPC变量值
  245. /// </summary>
  246. /// <param name="wcsOpcItemMd">opc变量对象</param>
  247. /// <param name="value">写入值</param>
  248. /// <returns></returns>
  249. public bool WriteOpcItemValue(WcsOpcItemMd wcsOpcItemMd, object value)
  250. {
  251. try
  252. {
  253. OpcUaClient tmpOpcUaClient = opcUaClientLst.Where(x => x.Key.PlcCode == wcsOpcItemMd.PlcCode).FirstOrDefault().Value;
  254. switch (wcsOpcItemMd.PlcItemDataType)
  255. {
  256. case 1:
  257. return tmpOpcUaClient.WriteNode(wcsOpcItemMd.OpcItemPos, Convert.ToInt32(value));
  258. case 2:
  259. return tmpOpcUaClient.WriteNode(wcsOpcItemMd.OpcItemPos, value.ToString());
  260. case 3:
  261. return tmpOpcUaClient.WriteNode(wcsOpcItemMd.OpcItemPos, Convert.ToBoolean(value));
  262. case 4:
  263. return tmpOpcUaClient.WriteNode(wcsOpcItemMd.OpcItemPos, Convert.ToDouble(value));
  264. case 5:
  265. return tmpOpcUaClient.WriteNode(wcsOpcItemMd.OpcItemPos, Convert.ToInt16(value));
  266. case 6:
  267. return tmpOpcUaClient.WriteNode(wcsOpcItemMd.OpcItemPos, Convert.ToByte(value));
  268. default:
  269. return tmpOpcUaClient.WriteNode(wcsOpcItemMd.OpcItemPos, value);
  270. }
  271. #region 孙亚龙 20210602 注释旧版代码
  272. //if (wcsOpcItemMd.PlcCode == "CrnPlc001")
  273. //{
  274. // switch (wcsOpcItemMd.PlcItemDataType)
  275. // {
  276. // case 1:
  277. // return crn_OpcUaClient.WriteNode(wcsOpcItemMd.OpcItemPos, Convert.ToInt32(value));
  278. // case 2:
  279. // return crn_OpcUaClient.WriteNode(wcsOpcItemMd.OpcItemPos, value.ToString());
  280. // case 3:
  281. // return crn_OpcUaClient.WriteNode(wcsOpcItemMd.OpcItemPos, Convert.ToBoolean(value));
  282. // case 4:
  283. // return crn_OpcUaClient.WriteNode(wcsOpcItemMd.OpcItemPos, Convert.ToDouble(value));
  284. // case 5:
  285. // return crn_OpcUaClient.WriteNode(wcsOpcItemMd.OpcItemPos, Convert.ToInt16(value));
  286. // case 6:
  287. // return crn_OpcUaClient.WriteNode(wcsOpcItemMd.OpcItemPos, Convert.ToByte(value));
  288. // default:
  289. // return crn_OpcUaClient.WriteNode(wcsOpcItemMd.OpcItemPos, value);
  290. // }
  291. //}
  292. //if (wcsOpcItemMd.PlcCode == "TranPlc001")
  293. //{
  294. // switch (wcsOpcItemMd.PlcItemDataType)
  295. // {
  296. // case 1:
  297. // return tran_OpcUaClient.WriteNode(wcsOpcItemMd.OpcItemPos, Convert.ToInt32(value));
  298. // case 2:
  299. // return tran_OpcUaClient.WriteNode(wcsOpcItemMd.OpcItemPos, value.ToString());
  300. // case 3:
  301. // return tran_OpcUaClient.WriteNode(wcsOpcItemMd.OpcItemPos, Convert.ToBoolean(value));
  302. // case 4:
  303. // return tran_OpcUaClient.WriteNode(wcsOpcItemMd.OpcItemPos, Convert.ToDouble(value));
  304. // case 5:
  305. // return tran_OpcUaClient.WriteNode(wcsOpcItemMd.OpcItemPos, Convert.ToInt16(value));
  306. // case 6:
  307. // return tran_OpcUaClient.WriteNode(wcsOpcItemMd.OpcItemPos, Convert.ToByte(value));
  308. // default:
  309. // return tran_OpcUaClient.WriteNode(wcsOpcItemMd.OpcItemPos, value);
  310. // }
  311. //}
  312. #endregion
  313. }
  314. catch(Exception ex)
  315. {
  316. ShowLogToForm($"OpcItem变量写入发生异常:【{ex.Message}】!设备名称:【{wcsOpcItemMd.DevName}】PLC:【{wcsOpcItemMd.PlcName}】OPC变量:【{wcsOpcItemMd.OpcItemCode}】变量OPC地址:【{wcsOpcItemMd.OpcItemPos}】写入值:【{value}】", true, LogTypeEnum.Err);
  317. return false;
  318. }
  319. }
  320. public void CloseConnect()
  321. {
  322. foreach (var item in opcUaClientLst)
  323. {
  324. item.Value.Disconnect();
  325. }
  326. #region 孙亚龙 20210602 注释旧版代码
  327. //if (CrnOpcUaServerConnStatus)
  328. //{
  329. // crn_OpcUaClient.Disconnect();
  330. //}
  331. //if (TranOpcUaServerConnStatus)
  332. //{
  333. // tran_OpcUaClient.Disconnect();
  334. //}
  335. #endregion
  336. }
  337. #region 桌面显示Log、记录log到文本
  338. /// <summary>
  339. /// 桌面显示Log、记录log到文本
  340. /// </summary>
  341. /// <param name="msg">log内容</param>
  342. /// <param name="isShowFormFlag">是否输出到桌面日志端。true:输出桌面;false:只记录文本</param>
  343. /// <param name="logTypeEnum">日志类型枚举</param>
  344. private void ShowLogToForm(string msg, bool isShowFormFlag, LogTypeEnum logTypeEnum)
  345. {
  346. if (isShowFormFlag)
  347. {
  348. showLogToFrm.ShowLog(new ShowLogToFrmEventArgs(LogHeadText + msg));
  349. }
  350. LogHelper.WriteLog(LogHeadText + msg, logTypeEnum);
  351. }
  352. #endregion
  353. }
  354. }