程序员最近都爱上了这个网站  程序员们快来瞅瞅吧!  it98k网:it98k.com

本站消息

站长简介/公众号

  出租广告位,需要合作请联系站长

+关注
已关注

分类  

暂无分类

标签  

暂无标签

日期归档  

2023-05(1)

C#使用OpcUaHelper开源库开发客户端实现读取、订阅OPC UA服务器节点信息

发布于2021-05-30 20:07     阅读(1304)     评论(0)     点赞(10)     收藏(3)


目录

一、内容准备

1.1、搭建OPC UA服务器环境

1.2、项目安装OPCUaHelper开源库

1.3、OpcUaHelper开源库

二、实现操作

2.1、连接OPC UA服务器,浏览所有节点信息

2.2、OpcUaHelper帮助类的常用方法

2.2.1、连接OPC UA服务器方法

2.2.2、读取OPC UA服务器的节点数据

2.2.3、读取OPC UA服务器中节点信息

三、运行测试

3.1、自己写的核心类

3.2、运行项目测试


一、内容准备

1.1、搭建OPC UA服务器环境

搭建OPC UA服务器环境图文教程

②注意:OPC UA服务器环境可以使用虚拟机搭建,如果从本机访问OPC UA服务器连接不上或超时,请先关闭OPC UA服务器的防火墙,或者在防火墙打开对应的端口即可。

1.2、项目安装OPCUaHelper开源库

1.3、OpcUaHelper开源库

OpcUaHelper开源库项目

二、实现操作

2.1、连接OPC UA服务器,浏览所有节点信息

①打开OPC UA服务器连接面板代码如下:

  1. using (FormBrowseServer form = new FormBrowseServer())
  2. {
  3. form.ShowDialog();
  4. }

②执行该代码后即可弹窗输入OPC UA服务器URL,连接服务器

③查看服务器的节点

2.2、OpcUaHelper帮助类的常用方法

2.2.1、连接OPC UA服务器方法

  1. //实例化操作
  2. OpcUaClient m_OpcUaClient = new OpcUaClient();
  3. //设置匿名连接
  4. m_OpcUaClient.UserIdentity = new UserIdentity( new AnonymousIdentityToken( ) );
  5. //设置用户名连接
  6. m_OpcUaClient.UserIdentity = new UserIdentity( "user", "password" );
  7. //使用证书连接
  8. X509Certificate2 certificate = new X509Certificate2( "[证书的路径]", "[密钥]", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.Exportable );
  9. m_OpcUaClient.UserIdentity = new UserIdentity( certificate );
  1. //设置完连接的权限之后,就可以真正的启动连接操作了,连接的操作必须要放到try...catch...之前,必须使用async标记方法
  2. private async void button1_Click( object sender, EventArgs e )
  3. {
  4. // 这是一个连接服务器的示例
  5. try
  6. {
  7. await m_OpcUaClient.ConnectServer( "opc.tcp://192.168.146.137:49321/Kepware.KEPServerEX.V6" );
  8. }
  9. catch (Exception ex)
  10. {
  11. ClientUtils.HandleException( "连接失败!!!", ex );
  12. }
  13. }

2.2.2、读取OPC UA服务器的节点数据

①如果我们想要读取上图节点浏览器的温度数据,节点字符串为:

ns=2;s=数据类型示例.16 位设备.R 寄存器.Long4

②同步方式读取节点信息【1-单节点数据读取 ;2-多节点批量读取】

  1. //1-同步单节点数据读取,类型为Int32, 所以我们使用下面的方法读取
  2. try
  3. {
  4. Int32 value = m_OpcUaClient.ReadNode<Int32>( "ns=2;s=数据类型示例.16 位设备.R 寄存器.Long4" );
  5. }
  6. catch(Exception ex)
  7. {
  8. ClientUtils.HandleException( “读取失败!!!”, ex );
  9. }
  10. //2-同步批量节点数据读取的操作,分为类型不一致和类型一致两种操作,下面都做个示例
  11. try
  12. {
  13. // 添加所有的读取的节点,此处的示例是类型不一致的情况
  14. List<NodeId> nodeIds = new List<NodeId>( );
  15. nodeIds.Add( new NodeId( "ns=2;s=数据类型示例.16 位设备.R 寄存器.DWord1" ) );
  16. nodeIds.Add( new NodeId( "ns=2;s=数据类型示例.16 位设备.R 寄存器.Float1" ) );
  17. nodeIds.Add( new NodeId( "ns=2;s=数据类型示例.16 位设备.R 寄存器.LLong4" ) );
  18. );
  19. // dataValues按顺序定义的值,每个值里面需要重新判断类型
  20. List<DataValue> dataValues = m_OpcUaClient.ReadNodes( nodeIds.ToArray() );
  21. // 如果你批量读取的值的类型都是一样的,比如float,那么有简便的方式
  22. List<string> tags = new List<string>( );
  23. tags.Add( "ns=2;s=数据类型示例.16 位设备.R 寄存器.Float1" );
  24. tags.Add( "ns=2;s=数据类型示例.16 位设备.R 寄存器.Float2" );
  25. tags.Add( "ns=2;s=数据类型示例.16 位设备.R 寄存器.Float3" );
  26. // 按照顺序定义的值
  27. List<float> values = m_OpcUaClient.ReadNodes<float>( tags.ToArray() );
  28. }
  29. catch (Exception ex)
  30. {
  31. ClientUtils.HandleException( this.Text, ex );
  32. }

③异步方式读取节点信息【1-单节点数据读取 ;2-多节点批量读取】

  1. //1-异步单节点数据读取,类型为Int32, 所以我们使用下面的方法读取
  2. try
  3. {
  4. Int32 value =await m_OpcUaClient.ReadNodeAsync<Int32>( "ns=2;s=数据类型示例.16 位设备.R 寄存器.Long4" );
  5. }
  6. catch(Exception ex)
  7. {
  8. ClientUtils.HandleException( “读取失败!!!”, ex );
  9. }
  10. //2-异步批量节点数据读取的操作,分为类型不一致和类型一致两种操作,下面都做个示例
  11. try
  12. {
  13. // 添加所有的读取的节点,此处的示例是类型不一致的情况
  14. List<NodeId> nodeIds = new List<NodeId>( );
  15. nodeIds.Add( new NodeId( "ns=2;s=数据类型示例.16 位设备.R 寄存器.DWord1" ) );
  16. nodeIds.Add( new NodeId( "ns=2;s=数据类型示例.16 位设备.R 寄存器.Float1" ) );
  17. nodeIds.Add( new NodeId( "ns=2;s=数据类型示例.16 位设备.R 寄存器.LLong4" ) );
  18. );
  19. // dataValues按顺序定义的值,每个值里面需要重新判断类型
  20. List<DataValue> dataValues =await m_OpcUaClient.ReadNodesAsync( nodeIds.ToArray() );
  21. }
  22. catch (Exception ex)
  23. {
  24. ClientUtils.HandleException( this.Text, ex );
  25. }

④订阅方式读取节点信息【1、单节点数据读取;2-多节点批量读取】

  1. //1-单节点数据订阅
  2. m_OpcUaClient.AddSubscription( "A", "ns=2;s=数据类型示例.16 位设备.R 寄存器.Long4", SubCallback );
  3. //1-单节点数据订阅的回调函数
  4. private void SubCallback(string key, MonitoredItem monitoredItem, MonitoredItemNotificationEventArgs args )
  5. {
  6. if (InvokeRequired)
  7. {
  8. Invoke( new Action<string, MonitoredItem, MonitoredItemNotificationEventArgs>( SubCallback ), key, monitoredItem, args );
  9. return;
  10. }
  11. if (key == "A")
  12. {
  13. // 如果有多个的订阅值都关联了当前的方法,可以通过key和monitoredItem来区分
  14. MonitoredItemNotification notification = args.NotificationValue as MonitoredItemNotification;
  15. if (notification != null)
  16. {
  17. textBox3.Text = notification.Value.WrappedValue.Value.ToString( );
  18. }
  19. }
  20. }
  21. //1-取消单节点数据订阅
  22. m_OpcUaClient.RemoveSubscription( "A" );
  23. //2-多节点批量数据订阅
  24. private string[] MonitorNodeTags = null;
  25. private void button5_Click( object sender, EventArgs e )
  26. {
  27. // 多个节点的订阅
  28. MonitorNodeTags = new string[]
  29. {
  30. "ns=2;s=数据类型示例.16 位设备.R 寄存器.DWord1",
  31. "ns=2;s=数据类型示例.16 位设备.R 寄存器.LLong4",
  32. "ns=2;s=数据类型示例.16 位设备.R 寄存器.Long4",
  33. };
  34. m_OpcUaClient.AddSubscription( "B", MonitorNodeTags, SubCallback );
  35. }
  36. //2-多节点批量数据订阅回调函数
  37. private void SubCallback(string key, MonitoredItem monitoredItem, MonitoredItemNotificationEventArgs args )
  38. {
  39. if (InvokeRequired)
  40. {
  41. Invoke( new Action<string, MonitoredItem, MonitoredItemNotificationEventArgs>( SubCallback ), key, monitoredItem, args );
  42. return;
  43. }
  44. if (key == "A")
  45. {
  46. // 如果有多个的订阅值都关联了当前的方法,可以通过key和monitoredItem来区分
  47. MonitoredItemNotification notification = args.NotificationValue as MonitoredItemNotification;
  48. if (notification != null)
  49. {
  50. textBox3.Text = notification.Value.WrappedValue.Value.ToString( );
  51. }
  52. }
  53. else if(key == "B")
  54. {
  55. // 需要区分出来每个不同的节点信息
  56. MonitoredItemNotification notification = args.NotificationValue as MonitoredItemNotification;
  57. if (monitoredItem.StartNodeId.ToString( ) == MonitorNodeTags[0])
  58. {
  59. "ns=2;s=数据类型示例.16 位设备.R 寄存器.DWord1" = notification.Value.WrappedValue.Value.ToString( );
  60. }
  61. else if (monitoredItem.StartNodeId.ToString( ) == MonitorNodeTags[1])
  62. {
  63. "ns=2;s=数据类型示例.16 位设备.R 寄存器.LLong4" = notification.Value.WrappedValue.Value.ToString( );
  64. }
  65. else if (monitoredItem.StartNodeId.ToString( ) == MonitorNodeTags[2])
  66. {
  67. "ns=2;s=数据类型示例.16 位设备.R 寄存器.Long4" = notification.Value.WrappedValue.Value.ToString( );
  68. }
  69. }
  70. }
  71. //2-取消所有节点订阅
  72. m_OpcUaClient.RemoveAllSubscription();

⑤读取单节点的历史数据

  1. try
  2. {
  3. // 此处演示读取历史数据的操作,读取8月18日12点到13点的数据,如果想要读取成功,该节点是支持历史记录的
  4. List<float> values = m_OpcUaClient.ReadHistoryRawDataValues<float>( "ns=2;s=数据类型示例.16 位设备.R 寄存器.Long4",
  5. new DateTime( 2021, 5, 1, 12, 0, 0 ), new DateTime( 2021, 2, 25, 13, 0, 0 ) ).ToList( );
  6. // 列表数据可用于显示曲线之类的操作
  7. }
  8. catch (Exception ex)
  9. {
  10. ClientUtils.HandleException( this.Text, ex );
  11. }

 

2.2.3、读取OPC UA服务器中节点信息

①读取一个节点的关联节点,包含了几个简单的基本信息

  1. try
  2. {
  3. ReferenceDescription[] references = m_OpcUaClient.BrowseNodeReference( "ns=2;s=数据类型示例.16 位设备.R 寄存器" );
  4. foreach (var item in references)
  5. {
  6. str = string.Format("节点:{0},节点类型:{1},节点名称:{2},节点显示名称:{3}",
  7. item.NodeId, item.NodeClass, item.BrowseName, item.DisplayName);
  8. }
  9. ;
  10. }
  11. catch (Exception ex)
  12. {
  13. ClientUtils.HandleException( this.Text, ex );
  14. }
  15. //执行结果
  16. 节点:ns=2;s=数据类型示例.16 位设备.R 寄存器.Boolean1,节点类型:Variable,节点名称:2:Boolean1,节点显示名称:Boolean1节点:ns=2;s=数据类型示例.16 位设备.R 寄存器.Boolean2,节点类型:Variable,节点名称:2:Boolean2,节点显示名称:Boolean2节点:ns=2;s=数据类型示例.16 位设备.R 寄存器.Boolean3,节点类型:Variable,节点名称:2:Boolean3,节点显示名称:Boolean3节点:ns=2;s=数据类型示例.16 位设备.R 寄存器.Boolean4,节点类型:Variable,节点名称:2:Boolean4,节点显示名称:Boolean4节点:ns=2;s=数据类型示例.16 位设备.R 寄存器.Double1,节点类型:Variable,节点名称:2:Double1,节点显示名称:Double1节点:ns=2;s=数据类型示例.16 位设备.R 寄存器.Double2,节点类型:Variable,节点名称:2:Double2,节点显示名称:Double2节点:ns=2;s=数据类型示例.16 位设备.R 寄存器.Double3,节点类型:Variable,节点名称:2:Double3,节点显示名称:Double3节点:ns=2;s=数据类型示例.16 位设备.R 寄存器.Double4,节点类型:Variable,节点名称:2:Double4,节点显示名称:Double4节点:ns=2;s=数据类型示例.16 位设备.R 寄存器.DoubleArray,节点类型:Variable,节点名称:2:DoubleArray,节点显示名称:DoubleArray节点:ns=2;s=数据类型示例.16 位设备.R 寄存器.DWord1,节点类型:Variable,节点名称:2:DWord1,节点显示名称:DWord1节点:ns=2;s=数据类型示例.16 位设备.R 寄存器.DWord2,节点类型:Variable,节点名称:2:DWord2,节点显示名称:DWord2节点:ns=2;s=数据类型示例.16 位设备.R 寄存器.DWord3,节点类型:Variable,节点名称:2:DWord3,节点显示名称:DWord3节点:ns=2;s=数据类型示例.16 位设备.R 寄存器.DWord4,节点类型:Variable,节点名称:2:DWord4,节点显示名称:DWord4节点:ns=2;s=数据类型示例.16 位设备.R 寄存器.DWordArray,节点类型:Variable,节点名称:2:DWordArray,节点显示名称:DWordArray节点:ns=2;s=数据类型示例.16 位设备.R 寄存器.Float1,节点类型:Variable,节点名称:2:Float1,节点显示名称:Float1节点:ns=2;s=数据类型示例.16 位设备.R 寄存器.Float2,节点类型:Variable,节点名称:2:Float2,节点显示名称:Float2节点:ns=2;s=数据类型示例.16 位设备.R 寄存器.Float3,节点类型:Variable,节点名称:2:Float3,节点显示名称:Float3节点:ns=2;s=数据类型示例.16 位设备.R 寄存器.Float4,节点类型:Variable,节点名称:2:Float4,节点显示名称:Float4节点:ns=2;s=数据类型示例.16 位设备.R 寄存器.FloatArray,节点类型:Variable,节点名称:2:FloatArray,节点显示名称:FloatArray节点:ns=2;s=数据类型示例.16 位设备.R 寄存器.LLong1,节点类型:Variable,节点名称:2:LLong1,节点显示名称:LLong1节点:ns=2;s=数据类型示例.16 位设备.R 寄存器.LLong2,节点类型:Variable,节点名称:2:LLong2,节点显示名称:LLong2节点:ns=2;s=数据类型示例.16 位设备.R 寄存器.LLong3,节点类型:Variable,节点名称:2:LLong3,节点显示名称:LLong3节点:ns=2;s=数据类型示例.16 位设备.R 寄存器.LLong4,节点类型:Variable,节点名称:2:LLong4,节点显示名称:LLong4节点:ns=2;s=数据类型示例.16 位设备.R 寄存器.LLongArray,节点类型:Variable,节点名称:2:LLongArray,节点显示名称:LLongArray节点:ns=2;s=数据类型示例.16 位设备.R 寄存器.Long1,节点类型:Variable,节点名称:2:Long1,节点显示名称:Long1节点:ns=2;s=数据类型示例.16 位设备.R 寄存器.Long2,节点类型:Variable,节点名称:2:Long2,节点显示名称:Long2节点:ns=2;s=数据类型示例.16 位设备.R 寄存器.Long3,节点类型:Variable,节点名称:2:Long3,节点显示名称:Long3节点:ns=2;s=数据类型示例.16 位设备.R 寄存器.Long4,节点类型:Variable,节点名称:2:Long4,节点显示名称:Long4节点:ns=2;s=数据类型示例.16 位设备.R 寄存器.LongArray,节点类型:Variable,节点名称:2:LongArray,节点显示名称:LongArray节点:ns=2;s=数据类型示例.16 位设备.R 寄存器.QWord1,节点类型:Variable,节点名称:2:QWord1,节点显示名称:QWord1节点:ns=2;s=数据类型示例.16 位设备.R 寄存器.QWord2,节点类型:Variable,节点名称:2:QWord2,节点显示名称:QWord2节点:ns=2;s=数据类型示例.16 位设备.R 寄存器.QWord3,节点类型:Variable,节点名称:2:QWord3,节点显示名称:QWord3节点:ns=2;s=数据类型示例.16 位设备.R 寄存器.QWord4,节点类型:Variable,节点名称:2:QWord4,节点显示名称:QWord4节点:ns=2;s=数据类型示例.16 位设备.R 寄存器.QWordArray,节点类型:Variable,节点名称:2:QWordArray,节点显示名称:QWordArray节点:ns=2;s=数据类型示例.16 位设备.R 寄存器.Short1,节点类型:Variable,节点名称:2:Short1,节点显示名称:Short1节点:ns=2;s=数据类型示例.16 位设备.R 寄存器.Short2,节点类型:Variable,节点名称:2:Short2,节点显示名称:Short2节点:ns=2;s=数据类型示例.16 位设备.R 寄存器.Short3,节点类型:Variable,节点名称:2:Short3,节点显示名称:Short3节点:ns=2;s=数据类型示例.16 位设备.R 寄存器.Short4,节点类型:Variable,节点名称:2:Short4,节点显示名称:Short4节点:ns=2;s=数据类型示例.16 位设备.R 寄存器.ShortArray,节点类型:Variable,节点名称:2:ShortArray,节点显示名称:ShortArray节点:ns=2;s=数据类型示例.16 位设备.R 寄存器.Word1,节点类型:Variable,节点名称:2:Word1,节点显示名称:Word1节点:ns=2;s=数据类型示例.16 位设备.R 寄存器.Word2,节点类型:Variable,节点名称:2:Word2,节点显示名称:Word2节点:ns=2;s=数据类型示例.16 位设备.R 寄存器.Word3,节点类型:Variable,节点名称:2:Word3,节点显示名称:Word3节点:ns=2;s=数据类型示例.16 位设备.R 寄存器.Word4,节点类型:Variable,节点名称:2:Word4,节点显示名称:Word4节点:ns=2;s=数据类型示例.16 位设备.R 寄存器.WordArray,节点类型:Variable,节点名称:2:WordArray,节点显示名称:WordArray

②读取一个节点的相关的所有的属性,主要包含了值,描述,名称,权限等级,等等操作

  1. string str=null;
  2. try
  3. {
  4. OpcNodeAttribute[] nodeAttributes = m_OpcUaClient.ReadNoteAttributes( "ns=2;s=数据类型示例.16 位设备.R 寄存器.Long4" );
  5. foreach (var item in nodeAttributes)
  6. {
  7. str += string.Format("属性名称:{0},属性类型:{1},属性状态:{2},属性值:{3}",
  8. item.Name, item.Type, item.StatusCode, item.Value);
  9. }
  10. }
  11. catch (Exception ex)
  12. {
  13. ClientUtils.HandleException( this.Text, ex );
  14. }
  15. //执行结果
  16. 属性名称:NodeClass,属性类型:Int32,属性状态:Good,属性值:2属性名称:BrowseName,属性类型:QualifiedName,属性状态:Good,属性值:2:Long4属性名称:DisplayName,属性类型:LocalizedText,属性状态:Good,属性值:Long4属性名称:Description,属性类型:LocalizedText,属性状态:Good,属性值:属性名称:WriteMask,属性类型:UInt32,属性状态:Good,属性值:0属性名称:UserWriteMask,属性类型:UInt32,属性状态:Good,属性值:0属性名称:Value,属性类型:Int32,属性状态:Good,属性值:85747属性名称:DataType,属性类型:NodeId,属性状态:Good,属性值:i=6属性名称:ValueRank,属性类型:Int32,属性状态:Good,属性值:-1属性名称:AccessLevel,属性类型:Byte,属性状态:Good,属性值:3属性名称:UserAccessLevel,属性类型:Byte,属性状态:Good,属性值:3属性名称:MinimumSamplingInterval,属性类型:UInt32,属性状态:Good,属性值:10属性名称:Historizing,属性类型:Boolean,属性状态:Good,属性值:False

三、运行测试

3.1、自己写的核心类

  1. /***
  2. * Title:"数据采集" 项目
  3. * 主题:OPCUA与kepserver通讯帮助类
  4. * Description:
  5. * 功能:
  6. * 1、打开连接【匿名方式】、【账号方式】、【证书方式】
  7. * 2、关闭连接
  8. * 3、获取到当前节点的值【同步读取】
  9. * 4、获取到当前节点数据【同步读取】
  10. * 5、获取到批量节点数据【同步读取】
  11. * 6、获取到当前节点的值【异步读取】
  12. * 7、获取到批量节点数据【异步读取】
  13. * 8、获取到当前节点的关联节点
  14. * 9、获取到当前节点的所有属性
  15. * 10、写入单个节点【同步方式】
  16. * 11、批量写入节点【同步方式】
  17. * 12、写入单个节点【异步方式】
  18. * 13、读取单个节点的历史数据记录
  19. * 14、读取单个节点的历史数据记录
  20. * 15、单节点数据订阅
  21. * 16、取消单节点数据订阅
  22. * 17、批量节点数据订阅
  23. * 18、取消所有节点的数据订阅
  24. *
  25. * Date:2021
  26. * Version:0.1版本
  27. * Author:Coffee
  28. * Modify Recoder:
  29. */
  30. using Opc.Ua;
  31. using Opc.Ua.Client;
  32. using OpcUaHelper;
  33. using System;
  34. using System.Collections.Generic;
  35. using System.Linq;
  36. using System.Security.Cryptography.X509Certificates;
  37. using System.Threading.Tasks;
  38. namespace Utils
  39. {
  40. public class OPCUAHelper
  41. {
  42. #region 基础参数
  43. //OPCUA客户端
  44. private OpcUaClient opcUaClient;
  45. #endregion
  46. /// <summary>
  47. /// 构造函数
  48. /// </summary>
  49. public OPCUAHelper()
  50. {
  51. opcUaClient = new OpcUaClient();
  52. }
  53. /// <summary>
  54. /// 连接状态
  55. /// </summary>
  56. public bool ConnectStatus
  57. {
  58. get { return opcUaClient.Connected; }
  59. }
  60. #region 公有方法
  61. /// <summary>
  62. /// 打开连接【匿名方式】
  63. /// </summary>
  64. /// <param name="serverUrl">服务器URL【格式:opc.tcp://服务器IP地址/服务名称】</param>
  65. public async void OpenConnectOfAnonymous(string serverUrl)
  66. {
  67. if (!string.IsNullOrEmpty(serverUrl))
  68. {
  69. try
  70. {
  71. opcUaClient.UserIdentity = new UserIdentity(new AnonymousIdentityToken());
  72. await opcUaClient.ConnectServer(serverUrl);
  73. }
  74. catch (Exception ex)
  75. {
  76. ClientUtils.HandleException("连接失败!!!", ex);
  77. }
  78. }
  79. }
  80. /// <summary>
  81. /// 打开连接【账号方式】
  82. /// </summary>
  83. /// <param name="serverUrl">服务器URL【格式:opc.tcp://服务器IP地址/服务名称】</param>
  84. /// <param name="userName">用户名称</param>
  85. /// <param name="userPwd">用户密码</param>
  86. public async void OpenConnectOfAccount(string serverUrl,string userName,string userPwd)
  87. {
  88. if (!string.IsNullOrEmpty(serverUrl) &&
  89. !string.IsNullOrEmpty(userName) && !string.IsNullOrEmpty(userPwd))
  90. {
  91. try
  92. {
  93. opcUaClient.UserIdentity = new UserIdentity(userName,userPwd);
  94. await opcUaClient.ConnectServer(serverUrl);
  95. }
  96. catch (Exception ex)
  97. {
  98. ClientUtils.HandleException("连接失败!!!", ex);
  99. }
  100. }
  101. }
  102. /// <summary>
  103. /// 打开连接【证书方式】
  104. /// </summary>
  105. /// <param name="serverUrl">服务器URL【格式:opc.tcp://服务器IP地址/服务名称】</param>
  106. /// <param name="certificatePath">证书路径</param>
  107. /// <param name="secreKey">密钥</param>
  108. public async void OpenConnectOfCertificate(string serverUrl,string certificatePath,string secreKey)
  109. {
  110. if (!string.IsNullOrEmpty(serverUrl) &&
  111. !string.IsNullOrEmpty(certificatePath) && !string.IsNullOrEmpty(secreKey))
  112. {
  113. try
  114. {
  115. X509Certificate2 certificate = new X509Certificate2(certificatePath, secreKey, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.Exportable);
  116. opcUaClient.UserIdentity = new UserIdentity(certificate);
  117. await opcUaClient.ConnectServer(serverUrl);
  118. }
  119. catch (Exception ex)
  120. {
  121. ClientUtils.HandleException("连接失败!!!", ex);
  122. }
  123. }
  124. }
  125. /// <summary>
  126. /// 关闭连接
  127. /// </summary>
  128. public void CloseConnect()
  129. {
  130. if (opcUaClient!=null)
  131. {
  132. try
  133. {
  134. opcUaClient.Disconnect();
  135. }
  136. catch (Exception ex)
  137. {
  138. ClientUtils.HandleException("关闭连接失败!!!", ex);
  139. }
  140. }
  141. }
  142. /// <summary>
  143. /// 获取到当前节点的值【同步读取】
  144. /// </summary>
  145. /// <typeparam name="T">节点对应的数据类型</typeparam>
  146. /// <param name="nodeId">节点</param>
  147. /// <returns>返回当前节点的值</returns>
  148. public T GetCurrentNodeValue<T>(string nodeId)
  149. {
  150. T value = default(T);
  151. if (!string.IsNullOrEmpty(nodeId) && ConnectStatus)
  152. {
  153. try
  154. {
  155. value = opcUaClient.ReadNode<T>(nodeId);
  156. }
  157. catch (Exception ex)
  158. {
  159. ClientUtils.HandleException("读取失败!!!",ex);
  160. }
  161. }
  162. return value;
  163. }
  164. /// <summary>
  165. /// 获取到当前节点数据【同步读取】
  166. /// </summary>
  167. /// <typeparam name="T">节点对应的数据类型</typeparam>
  168. /// <param name="nodeId">节点</param>
  169. /// <returns>返回当前节点的值</returns>
  170. public DataValue GetCurrentNodeValue(string nodeId)
  171. {
  172. DataValue dataValue = null;
  173. if (!string.IsNullOrEmpty(nodeId) && ConnectStatus)
  174. {
  175. try
  176. {
  177. dataValue = opcUaClient.ReadNode(nodeId);
  178. }
  179. catch (Exception ex)
  180. {
  181. ClientUtils.HandleException("读取失败!!!", ex);
  182. }
  183. }
  184. return dataValue;
  185. }
  186. /// <summary>
  187. /// 获取到批量节点数据【同步读取】
  188. /// </summary>
  189. /// <param name="nodeIds">节点列表</param>
  190. /// <returns>返回节点数据字典</returns>
  191. public Dictionary<string,DataValue> GetBatchNodeDatasOfSync(List<NodeId> nodeIdList)
  192. {
  193. Dictionary<string, DataValue> dicNodeInfo = new Dictionary<string, DataValue>();
  194. if (nodeIdList != null && nodeIdList.Count>0 && ConnectStatus)
  195. {
  196. try
  197. {
  198. List<DataValue> dataValues = opcUaClient.ReadNodes(nodeIdList.ToArray());
  199. int count = nodeIdList.Count;
  200. for (int i = 0; i < count; i++)
  201. {
  202. AddInfoToDic(dicNodeInfo, nodeIdList[i].ToString(),dataValues[i]);
  203. }
  204. }
  205. catch (Exception ex)
  206. {
  207. ClientUtils.HandleException("读取失败!!!", ex);
  208. }
  209. }
  210. return dicNodeInfo;
  211. }
  212. /// <summary>
  213. /// 获取到当前节点的值【异步读取】
  214. /// </summary>
  215. /// <typeparam name="T">节点对应的数据类型</typeparam>
  216. /// <param name="nodeId">节点</param>
  217. /// <returns>返回当前节点的值</returns>
  218. public async Task<T> GetCurrentNodeValueOfAsync<T>(string nodeId)
  219. {
  220. T value = default(T);
  221. if (!string.IsNullOrEmpty(nodeId) && ConnectStatus)
  222. {
  223. try
  224. {
  225. value =await opcUaClient.ReadNodeAsync<T>(nodeId);
  226. }
  227. catch (Exception ex)
  228. {
  229. ClientUtils.HandleException("读取失败!!!", ex);
  230. }
  231. }
  232. return value;
  233. }
  234. /// <summary>
  235. /// 获取到批量节点数据【异步读取】
  236. /// </summary>
  237. /// <param name="nodeIds">节点列表</param>
  238. /// <returns>返回节点数据字典</returns>
  239. public async Task<Dictionary<string, DataValue>> GetBatchNodeDatasOfAsync(List<NodeId> nodeIdList)
  240. {
  241. Dictionary<string, DataValue> dicNodeInfo = new Dictionary<string, DataValue>();
  242. if (nodeIdList != null && nodeIdList.Count > 0 && ConnectStatus)
  243. {
  244. try
  245. {
  246. List<DataValue> dataValues = await opcUaClient.ReadNodesAsync(nodeIdList.ToArray());
  247. int count = nodeIdList.Count;
  248. for (int i = 0; i < count; i++)
  249. {
  250. AddInfoToDic(dicNodeInfo, nodeIdList[i].ToString(), dataValues[i]);
  251. }
  252. }
  253. catch (Exception ex)
  254. {
  255. ClientUtils.HandleException("读取失败!!!", ex);
  256. }
  257. }
  258. return dicNodeInfo;
  259. }
  260. /// <summary>
  261. /// 获取到当前节点的关联节点
  262. /// </summary>
  263. /// <param name="nodeId">当前节点</param>
  264. /// <returns>返回当前节点的关联节点</returns>
  265. public ReferenceDescription[] GetAllRelationNodeOfNodeId(string nodeId)
  266. {
  267. ReferenceDescription[] referenceDescriptions = null;
  268. if (!string.IsNullOrEmpty(nodeId) && ConnectStatus)
  269. {
  270. try
  271. {
  272. referenceDescriptions = opcUaClient.BrowseNodeReference(nodeId);
  273. }
  274. catch (Exception ex)
  275. {
  276. string str = "获取当前: "+nodeId+" 节点的相关节点失败!!!";
  277. ClientUtils.HandleException(str, ex);
  278. }
  279. }
  280. return referenceDescriptions;
  281. }
  282. /// <summary>
  283. /// 获取到当前节点的所有属性
  284. /// </summary>
  285. /// <param name="nodeId">当前节点</param>
  286. /// <returns>返回当前节点对应的所有属性</returns>
  287. public OpcNodeAttribute[] GetCurrentNodeAttributes(string nodeId)
  288. {
  289. OpcNodeAttribute[] opcNodeAttributes=null;
  290. if (!string.IsNullOrEmpty(nodeId) && ConnectStatus)
  291. {
  292. try
  293. {
  294. opcNodeAttributes = opcUaClient.ReadNoteAttributes(nodeId);
  295. }
  296. catch (Exception ex)
  297. {
  298. string str = "读取节点;" + nodeId + " 的所有属性失败!!!";
  299. ClientUtils.HandleException(str, ex);
  300. }
  301. }
  302. return opcNodeAttributes;
  303. }
  304. /// <summary>
  305. /// 写入单个节点【同步方式】
  306. /// </summary>
  307. /// <typeparam name="T">写入节点值得数据类型</typeparam>
  308. /// <param name="nodeId">节点</param>
  309. /// <param name="value">节点对应的数据值(比如:(short)123))</param>
  310. /// <returns>返回写入结果(true:表示写入成功)</returns>
  311. public bool WriteSingleNodeIdOfSync<T>(string nodeId,T value)
  312. {
  313. bool success = false;
  314. if (opcUaClient!=null && ConnectStatus)
  315. {
  316. if (!string.IsNullOrEmpty(nodeId))
  317. {
  318. try
  319. {
  320. success = opcUaClient.WriteNode(nodeId, value);
  321. }
  322. catch (Exception ex)
  323. {
  324. string str = "当前节点:" + nodeId + " 写入失败";
  325. ClientUtils.HandleException(str, ex);
  326. }
  327. }
  328. }
  329. return success;
  330. }
  331. /// <summary>
  332. /// 批量写入节点
  333. /// </summary>
  334. /// <param name="nodeIdArray">节点数组</param>
  335. /// <param name="nodeIdValueArray">节点对应数据数组</param>
  336. /// <returns>返回写入结果(true:表示写入成功)</returns>
  337. public bool BatchWriteNodeIds(string[] nodeIdArray, object[] nodeIdValueArray)
  338. {
  339. bool success = false;
  340. if (nodeIdArray != null && nodeIdArray.Length > 0 &&
  341. nodeIdValueArray != null && nodeIdValueArray.Length > 0)
  342. {
  343. try
  344. {
  345. success = opcUaClient.WriteNodes(nodeIdArray, nodeIdValueArray);
  346. }
  347. catch (Exception ex)
  348. {
  349. ClientUtils.HandleException("批量写入节点失败!!!", ex);
  350. }
  351. }
  352. return success;
  353. }
  354. /// <summary>
  355. /// 写入单个节点【异步方式】
  356. /// </summary>
  357. /// <typeparam name="T">写入节点值得数据类型</typeparam>
  358. /// <param name="nodeId">节点</param>
  359. /// <param name="value">节点对应的数据值</param>
  360. /// <returns>返回写入结果(true:表示写入成功)</returns>
  361. public async Task<bool> WriteSingleNodeIdOfAsync<T>(string nodeId, T value)
  362. {
  363. bool success = false;
  364. if (opcUaClient != null && ConnectStatus)
  365. {
  366. if (!string.IsNullOrEmpty(nodeId))
  367. {
  368. try
  369. {
  370. success = await opcUaClient.WriteNodeAsync(nodeId, value);
  371. }
  372. catch (Exception ex)
  373. {
  374. string str = "当前节点:"+nodeId+" 写入失败";
  375. ClientUtils.HandleException(str, ex);
  376. }
  377. }
  378. }
  379. return success;
  380. }
  381. /// <summary>
  382. /// 读取单个节点的历史数据记录
  383. /// </summary>
  384. /// <typeparam name="T">节点的数据类型</typeparam>
  385. /// <param name="nodeId">节点</param>
  386. /// <param name="startTime">开始时间</param>
  387. /// <param name="endTime">结束时间</param>
  388. /// <returns>返回该节点对应的历史数据记录</returns>
  389. public List<T> ReadSingleNodeIdHistoryDatas<T>(string nodeId, DateTime startTime, DateTime endTime)
  390. {
  391. List<T> nodeIdDatas = null;
  392. if (!string.IsNullOrEmpty(nodeId) && startTime!=null && endTime!=null && endTime>startTime)
  393. {
  394. try
  395. {
  396. nodeIdDatas = opcUaClient.ReadHistoryRawDataValues<T>(nodeId, startTime, endTime).ToList();
  397. }
  398. catch (Exception ex)
  399. {
  400. ClientUtils.HandleException("读取失败", ex);
  401. }
  402. }
  403. return nodeIdDatas;
  404. }
  405. /// <summary>
  406. /// 读取单个节点的历史数据记录
  407. /// </summary>
  408. /// <typeparam name="T">节点的数据类型</typeparam>
  409. /// <param name="nodeId">节点</param>
  410. /// <param name="startTime">开始时间</param>
  411. /// <param name="endTime">结束时间</param>
  412. /// <returns>返回该节点对应的历史数据记录</returns>
  413. public List<DataValue> ReadSingleNodeIdHistoryDatas(string nodeId, DateTime startTime, DateTime endTime)
  414. {
  415. List<DataValue> nodeIdDatas = null;
  416. if (!string.IsNullOrEmpty(nodeId) && startTime != null && endTime != null && endTime > startTime)
  417. {
  418. if (ConnectStatus)
  419. {
  420. try
  421. {
  422. nodeIdDatas = opcUaClient.ReadHistoryRawDataValues(nodeId, startTime, endTime).ToList();
  423. }
  424. catch (Exception ex)
  425. {
  426. ClientUtils.HandleException("读取失败", ex);
  427. }
  428. }
  429. }
  430. return nodeIdDatas;
  431. }
  432. /// <summary>
  433. /// 单节点数据订阅
  434. /// </summary>
  435. /// <param name="key">订阅的关键字(必须唯一)</param>
  436. /// <param name="nodeId">节点</param>
  437. /// <param name="callback">数据订阅的回调方法</param>
  438. public void SingleNodeIdDatasSubscription(string key, string nodeId, Action<string, MonitoredItem, MonitoredItemNotificationEventArgs> callback)
  439. {
  440. if (ConnectStatus)
  441. {
  442. try
  443. {
  444. opcUaClient.AddSubscription(key,nodeId,callback);
  445. }
  446. catch (Exception ex)
  447. {
  448. string str = "订阅节点:" + nodeId + " 数据失败!!!";
  449. ClientUtils.HandleException(str, ex);
  450. }
  451. }
  452. }
  453. /// <summary>
  454. /// 取消单节点数据订阅
  455. /// </summary>
  456. /// <param name="key">订阅的关键字</param>
  457. public bool CancelSingleNodeIdDatasSubscription(string key)
  458. {
  459. bool success = false;
  460. if (!string.IsNullOrEmpty(key))
  461. {
  462. if (ConnectStatus)
  463. {
  464. try
  465. {
  466. opcUaClient.RemoveSubscription(key);
  467. success = true;
  468. }
  469. catch (Exception ex)
  470. {
  471. string str = "取消 " +key+ " 的订阅失败";
  472. ClientUtils.HandleException(str, ex);
  473. }
  474. }
  475. }
  476. return success;
  477. }
  478. /// <summary>
  479. /// 批量节点数据订阅
  480. /// </summary>
  481. /// <param name="key">订阅的关键字(必须唯一)</param>
  482. /// <param name="nodeIds">节点数组</param>
  483. /// <param name="callback">数据订阅的回调方法</param>
  484. public void BatchNodeIdDatasSubscription(string key, string[] nodeIds, Action<string, MonitoredItem, MonitoredItemNotificationEventArgs> callback)
  485. {
  486. if (!string.IsNullOrEmpty(key) && nodeIds!=null && nodeIds.Length>0)
  487. {
  488. if (ConnectStatus)
  489. {
  490. try
  491. {
  492. opcUaClient.AddSubscription(key, nodeIds, callback);
  493. }
  494. catch (Exception ex)
  495. {
  496. string str = "批量订阅节点数据失败!!!";
  497. ClientUtils.HandleException(str, ex);
  498. }
  499. }
  500. }
  501. }
  502. /// <summary>
  503. /// 取消所有节点的数据订阅
  504. /// </summary>
  505. /// <returns></returns>
  506. public bool CancelAllNodeIdDatasSubscription()
  507. {
  508. bool success = false;
  509. if (ConnectStatus)
  510. {
  511. try
  512. {
  513. opcUaClient.RemoveAllSubscription();
  514. success = true;
  515. }
  516. catch (Exception ex)
  517. {
  518. ClientUtils.HandleException("取消所有的节点数据订阅失败!!!", ex);
  519. }
  520. }
  521. return success;
  522. }
  523. #endregion
  524. #region 私有方法
  525. /// <summary>
  526. /// 添加数据到字典中(相同键的则采用最后一个键对应的值)
  527. /// </summary>
  528. /// <param name="dic">字典</param>
  529. /// <param name="key"></param>
  530. /// <param name="dataValue"></param>
  531. private void AddInfoToDic(Dictionary<string,DataValue> dic,string key,DataValue dataValue)
  532. {
  533. if (dic!=null)
  534. {
  535. if (!dic.ContainsKey(key))
  536. {
  537. dic.Add(key, dataValue);
  538. }
  539. else
  540. {
  541. dic[key] = dataValue;
  542. }
  543. }
  544. }
  545. #endregion
  546. }//Class_end
  547. }

3.2、运行项目测试

C#使用OpcUaHelper开源库开发的客户端实现读取、订阅OPC UA服务器节点项目工程下载

 

原文链接:https://blog.csdn.net/xiaochenXIHUA/article/details/117254108



所属网站分类: 技术文章 > 博客

作者:来呀来呀开心吧

链接:http://www.phpheidong.com/blog/article/86772/ea30ae2fcf77b44a4e74/

来源:php黑洞网

任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任

10 0
收藏该文
已收藏

评论内容:(最多支持255个字符)