OPCuaClientPLC.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. using Opc.Ua;
  2. using Opc.Ua.Client;
  3. using OpcUaHelper;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Threading.Tasks;
  9. using TeamAAS_VP.Enums;
  10. using TeamAAS_VP.Interfaces;
  11. using TeamAAS_VP.Models;
  12. namespace TeamAAS_VP.Core.PLCs
  13. {
  14. public class OpcUaClientPLC : IPlc
  15. {
  16. public Guid Id{ get; private set; }
  17. public CommunicationType CommunicationType { get; private set; }
  18. public string EndpointUrl { get; private set; }
  19. public int Index { get; set; }
  20. public string Name { get; private set; }
  21. public OpcUaClient OpcUaClient { get; private set; }
  22. public bool IsConnected { get { return OpcUaClient.Connected; } }
  23. /// <summary>
  24. /// 节点头
  25. /// </summary>
  26. public string NodeHeader { get; private set; }
  27. public event Action<object, bool> ConnectChangedEvent;
  28. public OpcUaClientPLC(Guid id,int index, string name, string endpointUrl,string nodeHeader, CommunicationType communicationType)
  29. {
  30. Id = id;
  31. Index = index;
  32. Name = name;
  33. EndpointUrl = endpointUrl;
  34. NodeHeader = nodeHeader;
  35. CommunicationType = communicationType;
  36. OpcUaClient = new OpcUaClient();
  37. // 初始化PLC连接
  38. OpcUaClient.UserIdentity = new UserIdentity(new AnonymousIdentityToken());
  39. // connect to server, this is a sample
  40. try
  41. {
  42. OpcUaClient.ConnectComplete += OpcUaClient_ConnectComplete;
  43. OpcUaClient.ReconnectStarting += OpcUaClient_ReconnectStarting;
  44. OpcUaClient.ReconnectComplete += OpcUaClient_ReconnectComplete;
  45. OpcUaClient.OpcStatusChange += OpcUaClient_OpcStatusChange;
  46. }
  47. catch (Exception)
  48. {
  49. return;
  50. }
  51. }
  52. public OpcUaClientPLC(PlcInfo plcInfo)
  53. {
  54. Id = plcInfo.Id;
  55. Index=plcInfo.Index;
  56. Name = plcInfo.Name;
  57. NodeHeader=plcInfo.NodeHeader;
  58. EndpointUrl = plcInfo.EndpointUrl;
  59. CommunicationType = plcInfo.CommunicationType;
  60. OpcUaClient = new OpcUaClient();
  61. // 初始化PLC连接
  62. OpcUaClient.UserIdentity = new UserIdentity(new AnonymousIdentityToken());
  63. // connect to server, this is a sample
  64. try
  65. {
  66. OpcUaClient.ConnectComplete += OpcUaClient_ConnectComplete;
  67. OpcUaClient.ReconnectStarting += OpcUaClient_ReconnectStarting;
  68. OpcUaClient.ReconnectComplete += OpcUaClient_ReconnectComplete;
  69. OpcUaClient.OpcStatusChange += OpcUaClient_OpcStatusChange;
  70. }
  71. catch (Exception)
  72. {
  73. return;
  74. }
  75. }
  76. public void Connect()
  77. {
  78. OpcUaClient.ConnectServer(EndpointUrl);
  79. }
  80. public Task ConnectAsync()
  81. {
  82. return OpcUaClient.ConnectServer(EndpointUrl);
  83. }
  84. public void Disconnect()
  85. {
  86. OpcUaClient.Disconnect();
  87. }
  88. public void Dispose()
  89. {
  90. OpcUaClient.Disconnect();
  91. OpcUaClient.ConnectComplete -= OpcUaClient_ConnectComplete;
  92. OpcUaClient.ReconnectStarting -= OpcUaClient_ReconnectStarting;
  93. OpcUaClient.ReconnectComplete -= OpcUaClient_ReconnectComplete;
  94. OpcUaClient.OpcStatusChange -= OpcUaClient_OpcStatusChange;
  95. }
  96. /// <summary>
  97. /// 读取多个节点的值
  98. /// </summary>
  99. /// <param name="nodeIds"></param>
  100. /// <returns></returns>
  101. public Dictionary<string, object> ReadNodes(string[] nodeIds)
  102. {
  103. var result = new Dictionary<string, object>();
  104. var readNodeIds = nodeIds.Select(s =>
  105. {
  106. if (s.StartsWith(NodeHeader))
  107. {
  108. return s;
  109. }
  110. else
  111. {
  112. return NodeHeader + s;
  113. }
  114. }).ToArray();
  115. List<NodeId> readNodeIdList = new List<NodeId>();
  116. foreach (var readNodeId in readNodeIds)
  117. {
  118. readNodeIdList.Add(new NodeId(readNodeId));
  119. }
  120. var values = OpcUaClient.ReadNodes(readNodeIdList.ToArray());
  121. for (int i = 0; i < nodeIds.Length; i++)
  122. {
  123. result[nodeIds[i]] = values[i].Value;
  124. }
  125. return result;
  126. }
  127. /// <summary>
  128. /// 异步读取多个节点的值
  129. /// </summary>
  130. /// <param name="nodeIds"></param>
  131. /// <returns></returns>
  132. public async Task<Dictionary<string, object>> ReadNodesAsync(string[] nodeIds)
  133. {
  134. var result = new Dictionary<string, object>();
  135. var readNodeIds = nodeIds.Select(s =>
  136. {
  137. if (s.StartsWith(NodeHeader))
  138. {
  139. return s;
  140. }
  141. else
  142. {
  143. return NodeHeader + s;
  144. }
  145. }).ToArray();
  146. List<NodeId> readNodeIdList = new List<NodeId>();
  147. foreach (var readNodeId in readNodeIds)
  148. {
  149. readNodeIdList.Add(new NodeId(readNodeId));
  150. }
  151. var values = await OpcUaClient.ReadNodesAsync(readNodeIdList.ToArray());
  152. for (int i = 0; i < nodeIds.Length; i++)
  153. {
  154. result[nodeIds[i]] = values[i].Value;
  155. }
  156. return result;
  157. }
  158. /// <summary>
  159. /// 读取单个节点的值
  160. /// </summary>
  161. /// <param name="nodeId"></param>
  162. /// <returns></returns>
  163. public object ReadNode(string nodeId)
  164. {
  165. string readNodeId = nodeId;
  166. if (!nodeId.StartsWith(NodeHeader))
  167. {
  168. readNodeId = NodeHeader + nodeId;
  169. }
  170. var value = OpcUaClient.ReadNode(new NodeId(readNodeId));
  171. return value.Value;
  172. }
  173. /// <summary>
  174. /// 异步读取单个节点的值
  175. /// </summary>
  176. /// <param name="nodeId"></param>
  177. /// <returns></returns>
  178. public Task<object> ReadNodeAsync(string nodeId)
  179. {
  180. return Task.Run(() =>
  181. {
  182. return ReadNode(nodeId);
  183. });
  184. }
  185. /// <summary>
  186. /// 读取单个节点的值
  187. /// </summary>
  188. /// <typeparam name="T"></typeparam>
  189. /// <param name="nodeId"></param>
  190. /// <returns></returns>
  191. public T ReadNode<T>(string nodeId)
  192. {
  193. string readNodeId = nodeId;
  194. if (!nodeId.StartsWith(NodeHeader))
  195. {
  196. readNodeId = NodeHeader + nodeId;
  197. }
  198. return OpcUaClient.ReadNode<T>(readNodeId);
  199. }
  200. /// <summary>
  201. /// 异步读取单个节点的值
  202. /// </summary>
  203. /// <typeparam name="T"></typeparam>
  204. /// <param name="nodeId"></param>
  205. /// <returns></returns>
  206. public async Task<T> ReadNodeAsync<T>(string nodeId)
  207. {
  208. string readNodeId = nodeId;
  209. if (!nodeId.StartsWith(NodeHeader))
  210. {
  211. readNodeId = NodeHeader + nodeId;
  212. }
  213. return await OpcUaClient.ReadNodeAsync<T>(readNodeId);
  214. }
  215. /// <summary>
  216. /// 写入单个节点的值
  217. /// </summary>
  218. /// <typeparam name="T"></typeparam>
  219. /// <param name="nodeId"></param>
  220. /// <param name="value"></param>
  221. /// <returns></returns>
  222. public bool WriteNode<T>(string nodeId, T value)
  223. {
  224. string writeNodeId = nodeId;
  225. if (!nodeId.StartsWith(NodeHeader))
  226. {
  227. writeNodeId = NodeHeader + nodeId;
  228. }
  229. return OpcUaClient.WriteNode<T>(writeNodeId, value);
  230. }
  231. /// <summary>
  232. /// 异步写入单个节点的值
  233. /// </summary>
  234. /// <typeparam name="T"></typeparam>
  235. /// <param name="nodeId"></param>
  236. /// <param name="value"></param>
  237. /// <returns></returns>
  238. public async Task<bool> WriteNodeAsync<T>(string nodeId, T value)
  239. {
  240. string writeNodeId = nodeId;
  241. if (!nodeId.StartsWith(NodeHeader))
  242. {
  243. writeNodeId = NodeHeader + nodeId;
  244. }
  245. return await OpcUaClient.WriteNodeAsync<T>(writeNodeId, value);
  246. }
  247. /// <summary>
  248. /// 写入多个节点
  249. /// </summary>
  250. /// <param name="nodeValues"></param>
  251. /// <returns></returns>
  252. public bool WriteNodes(Dictionary<string, object> nodeValues)
  253. {
  254. var writeNodeValues = new Dictionary<string, object>();
  255. foreach (var kvp in nodeValues)
  256. {
  257. string writeNodeId = kvp.Key;
  258. if (!kvp.Key.StartsWith(NodeHeader))
  259. {
  260. writeNodeId = NodeHeader + kvp.Key;
  261. }
  262. writeNodeValues[writeNodeId] = kvp.Value;
  263. }
  264. return OpcUaClient.WriteNodes(writeNodeValues.Keys.ToArray(), writeNodeValues.Values.ToArray());
  265. }
  266. /// <summary>
  267. /// 写入多个节点异步
  268. /// </summary>
  269. /// <param name="nodeValues"></param>
  270. /// <returns></returns>
  271. public Task<bool> WriteNodesAsync(Dictionary<string, object> nodeValues)
  272. {
  273. return Task.Run(() =>
  274. {
  275. return WriteNodes(nodeValues);
  276. });
  277. }
  278. /// <summary>
  279. /// 订阅多个节点
  280. /// </summary>
  281. /// <param name="key"></param>
  282. /// <param name="nodeIds"></param>
  283. /// <param name="dataChangeHandler"></param>
  284. public void SubscribeNodes(string key, List<string> nodeIds, Action<(string key,string nodeId,object value)> dataChangeHandler)
  285. {
  286. OpcUaClient.AddSubscription(key, nodeIds.Select(s =>
  287. {
  288. if (s.StartsWith(NodeHeader))
  289. {
  290. return s;
  291. }
  292. else
  293. {
  294. return NodeHeader + s;
  295. }
  296. }).ToArray(), (key1, monitoredItem, args) =>
  297. {
  298. MonitoredItemNotification notification = args.NotificationValue as MonitoredItemNotification;
  299. if (notification == null)
  300. {
  301. return;
  302. }
  303. string nodeId = monitoredItem.StartNodeId.ToString();
  304. if (nodeId.StartsWith(NodeHeader))
  305. {
  306. nodeId= nodeId.Substring(NodeHeader.Length);
  307. }
  308. // 触发数据变化事件
  309. dataChangeHandler?.Invoke((key1, nodeId, notification.Value.WrappedValue.Value));
  310. });
  311. }
  312. #region OPC事件
  313. private void OpcUaClient_OpcStatusChange(object sender, OpcUaStatusEventArgs e)
  314. {
  315. //LogHelper.WriteLogInfo($"OPC状态发生改变:Error:{e.Error},Time:{e.Time},Text:{e.Text}");
  316. }
  317. private void OpcUaClient_ReconnectComplete(object sender, EventArgs e)
  318. {
  319. ConnectChangedEvent?.Invoke(this, OpcUaClient.Connected);
  320. }
  321. private void OpcUaClient_ReconnectStarting(object sender, EventArgs e)
  322. {
  323. ConnectChangedEvent?.Invoke(this, OpcUaClient.Connected);
  324. }
  325. private void OpcUaClient_ConnectComplete(object sender, EventArgs e)
  326. {
  327. ConnectChangedEvent?.Invoke(this, OpcUaClient.Connected);
  328. }
  329. #endregion
  330. }
  331. }