C#使用OpcUaHelper开源库开发客户端实现读取、订阅OPC UA服务器节点信息
·
目录
一、内容准备
1.1、搭建OPC UA服务器环境
②注意:OPC UA服务器环境可以使用虚拟机搭建,如果从本机访问OPC UA服务器连接不上或超时,请先关闭OPC UA服务器的防火墙,或者在防火墙打开对应的端口即可。
1.2、项目安装OPCUaHelper开源库
1.3、OpcUaHelper开源库
二、实现操作
2.1、连接OPC UA服务器,浏览所有节点信息
①打开OPC UA服务器连接面板代码如下:
using (FormBrowseServer form = new FormBrowseServer())
{
form.ShowDialog();
}
②执行该代码后即可弹窗输入OPC UA服务器URL,连接服务器
③查看服务器的节点
2.2、OpcUaHelper帮助类的常用方法
2.2.1、连接OPC UA服务器方法
//实例化操作
OpcUaClient m_OpcUaClient = new OpcUaClient();
//设置匿名连接
m_OpcUaClient.UserIdentity = new UserIdentity( new AnonymousIdentityToken( ) );
//设置用户名连接
m_OpcUaClient.UserIdentity = new UserIdentity( "user", "password" );
//使用证书连接
X509Certificate2 certificate = new X509Certificate2( "[证书的路径]", "[密钥]", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.Exportable );
m_OpcUaClient.UserIdentity = new UserIdentity( certificate );
//设置完连接的权限之后,就可以真正的启动连接操作了,连接的操作必须要放到try...catch...之前,必须使用async标记方法
private async void button1_Click( object sender, EventArgs e )
{
// 这是一个连接服务器的示例
try
{
await m_OpcUaClient.ConnectServer( "opc.tcp://192.168.146.137:49321/Kepware.KEPServerEX.V6" );
}
catch (Exception ex)
{
ClientUtils.HandleException( "连接失败!!!", ex );
}
}
2.2.2、读取OPC UA服务器的节点数据
①如果我们想要读取上图节点浏览器的温度数据,节点字符串为:
ns=2;s=数据类型示例.16 位设备.R 寄存器.Long4
②同步方式读取节点信息【1-单节点数据读取 ;2-多节点批量读取】
//1-同步单节点数据读取,类型为Int32, 所以我们使用下面的方法读取
try
{
Int32 value = m_OpcUaClient.ReadNode<Int32>( "ns=2;s=数据类型示例.16 位设备.R 寄存器.Long4" );
}
catch(Exception ex)
{
ClientUtils.HandleException( “读取失败!!!”, ex );
}
//2-同步批量节点数据读取的操作,分为类型不一致和类型一致两种操作,下面都做个示例
try
{
// 添加所有的读取的节点,此处的示例是类型不一致的情况
List<NodeId> nodeIds = new List<NodeId>( );
nodeIds.Add( new NodeId( "ns=2;s=数据类型示例.16 位设备.R 寄存器.DWord1" ) );
nodeIds.Add( new NodeId( "ns=2;s=数据类型示例.16 位设备.R 寄存器.Float1" ) );
nodeIds.Add( new NodeId( "ns=2;s=数据类型示例.16 位设备.R 寄存器.LLong4" ) );
);
// dataValues按顺序定义的值,每个值里面需要重新判断类型
List<DataValue> dataValues = m_OpcUaClient.ReadNodes( nodeIds.ToArray() );
// 如果你批量读取的值的类型都是一样的,比如float,那么有简便的方式
List<string> tags = new List<string>( );
tags.Add( "ns=2;s=数据类型示例.16 位设备.R 寄存器.Float1" );
tags.Add( "ns=2;s=数据类型示例.16 位设备.R 寄存器.Float2" );
tags.Add( "ns=2;s=数据类型示例.16 位设备.R 寄存器.Float3" );
// 按照顺序定义的值
List<float> values = m_OpcUaClient.ReadNodes<float>( tags.ToArray() );
}
catch (Exception ex)
{
ClientUtils.HandleException( this.Text, ex );
}
③异步方式读取节点信息【1-单节点数据读取 ;2-多节点批量读取】
//1-异步单节点数据读取,类型为Int32, 所以我们使用下面的方法读取
try
{
Int32 value =await m_OpcUaClient.ReadNodeAsync<Int32>( "ns=2;s=数据类型示例.16 位设备.R 寄存器.Long4" );
}
catch(Exception ex)
{
ClientUtils.HandleException( “读取失败!!!”, ex );
}
//2-异步批量节点数据读取的操作,分为类型不一致和类型一致两种操作,下面都做个示例
try
{
// 添加所有的读取的节点,此处的示例是类型不一致的情况
List<NodeId> nodeIds = new List<NodeId>( );
nodeIds.Add( new NodeId( "ns=2;s=数据类型示例.16 位设备.R 寄存器.DWord1" ) );
nodeIds.Add( new NodeId( "ns=2;s=数据类型示例.16 位设备.R 寄存器.Float1" ) );
nodeIds.Add( new NodeId( "ns=2;s=数据类型示例.16 位设备.R 寄存器.LLong4" ) );
);
// dataValues按顺序定义的值,每个值里面需要重新判断类型
List<DataValue> dataValues =await m_OpcUaClient.ReadNodesAsync( nodeIds.ToArray() );
}
catch (Exception ex)
{
ClientUtils.HandleException( this.Text, ex );
}
④订阅方式读取节点信息【1、单节点数据读取;2-多节点批量读取】
//1-单节点数据订阅
m_OpcUaClient.AddSubscription( "A", "ns=2;s=数据类型示例.16 位设备.R 寄存器.Long4", SubCallback );
//1-单节点数据订阅的回调函数
private void SubCallback(string key, MonitoredItem monitoredItem, MonitoredItemNotificationEventArgs args )
{
if (InvokeRequired)
{
Invoke( new Action<string, MonitoredItem, MonitoredItemNotificationEventArgs>( SubCallback ), key, monitoredItem, args );
return;
}
if (key == "A")
{
// 如果有多个的订阅值都关联了当前的方法,可以通过key和monitoredItem来区分
MonitoredItemNotification notification = args.NotificationValue as MonitoredItemNotification;
if (notification != null)
{
textBox3.Text = notification.Value.WrappedValue.Value.ToString( );
}
}
}
//1-取消单节点数据订阅
m_OpcUaClient.RemoveSubscription( "A" );
//2-多节点批量数据订阅
private string[] MonitorNodeTags = null;
private void button5_Click( object sender, EventArgs e )
{
// 多个节点的订阅
MonitorNodeTags = new string[]
{
"ns=2;s=数据类型示例.16 位设备.R 寄存器.DWord1",
"ns=2;s=数据类型示例.16 位设备.R 寄存器.LLong4",
"ns=2;s=数据类型示例.16 位设备.R 寄存器.Long4",
};
m_OpcUaClient.AddSubscription( "B", MonitorNodeTags, SubCallback );
}
//2-多节点批量数据订阅回调函数
private void SubCallback(string key, MonitoredItem monitoredItem, MonitoredItemNotificationEventArgs args )
{
if (InvokeRequired)
{
Invoke( new Action<string, MonitoredItem, MonitoredItemNotificationEventArgs>( SubCallback ), key, monitoredItem, args );
return;
}
if (key == "A")
{
// 如果有多个的订阅值都关联了当前的方法,可以通过key和monitoredItem来区分
MonitoredItemNotification notification = args.NotificationValue as MonitoredItemNotification;
if (notification != null)
{
textBox3.Text = notification.Value.WrappedValue.Value.ToString( );
}
}
else if(key == "B")
{
// 需要区分出来每个不同的节点信息
MonitoredItemNotification notification = args.NotificationValue as MonitoredItemNotification;
if (monitoredItem.StartNodeId.ToString( ) == MonitorNodeTags[0])
{
"ns=2;s=数据类型示例.16 位设备.R 寄存器.DWord1" = notification.Value.WrappedValue.Value.ToString( );
}
else if (monitoredItem.StartNodeId.ToString( ) == MonitorNodeTags[1])
{
"ns=2;s=数据类型示例.16 位设备.R 寄存器.LLong4" = notification.Value.WrappedValue.Value.ToString( );
}
else if (monitoredItem.StartNodeId.ToString( ) == MonitorNodeTags[2])
{
"ns=2;s=数据类型示例.16 位设备.R 寄存器.Long4" = notification.Value.WrappedValue.Value.ToString( );
}
}
}
//2-取消所有节点订阅
m_OpcUaClient.RemoveAllSubscription();
⑤读取单节点的历史数据
try
{
// 此处演示读取历史数据的操作,读取8月18日12点到13点的数据,如果想要读取成功,该节点是支持历史记录的
List<float> values = m_OpcUaClient.ReadHistoryRawDataValues<float>( "ns=2;s=数据类型示例.16 位设备.R 寄存器.Long4",
new DateTime( 2021, 5, 1, 12, 0, 0 ), new DateTime( 2021, 2, 25, 13, 0, 0 ) ).ToList( );
// 列表数据可用于显示曲线之类的操作
}
catch (Exception ex)
{
ClientUtils.HandleException( this.Text, ex );
}
2.2.3、读取OPC UA服务器中节点信息
①读取一个节点的关联节点,包含了几个简单的基本信息
try
{
ReferenceDescription[] references = m_OpcUaClient.BrowseNodeReference( "ns=2;s=数据类型示例.16 位设备.R 寄存器" );
foreach (var item in references)
{
str = string.Format("节点:{0},节点类型:{1},节点名称:{2},节点显示名称:{3}",
item.NodeId, item.NodeClass, item.BrowseName, item.DisplayName);
}
;
}
catch (Exception ex)
{
ClientUtils.HandleException( this.Text, ex );
}
//执行结果
节点: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
②读取一个节点的相关的所有的属性,主要包含了值,描述,名称,权限等级,等等操作
string str=null;
try
{
OpcNodeAttribute[] nodeAttributes = m_OpcUaClient.ReadNoteAttributes( "ns=2;s=数据类型示例.16 位设备.R 寄存器.Long4" );
foreach (var item in nodeAttributes)
{
str += string.Format("属性名称:{0},属性类型:{1},属性状态:{2},属性值:{3}",
item.Name, item.Type, item.StatusCode, item.Value);
}
}
catch (Exception ex)
{
ClientUtils.HandleException( this.Text, ex );
}
//执行结果
属性名称: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、自己写的核心类
/***
* Title:"数据采集" 项目
* 主题:OPCUA与kepserver通讯帮助类
* Description:
* 功能:
* 1、打开连接【匿名方式】、【账号方式】、【证书方式】
* 2、关闭连接
* 3、获取到当前节点的值【同步读取】
* 4、获取到当前节点数据【同步读取】
* 5、获取到批量节点数据【同步读取】
* 6、获取到当前节点的值【异步读取】
* 7、获取到批量节点数据【异步读取】
* 8、获取到当前节点的关联节点
* 9、获取到当前节点的所有属性
* 10、写入单个节点【同步方式】
* 11、批量写入节点【同步方式】
* 12、写入单个节点【异步方式】
* 13、读取单个节点的历史数据记录
* 14、读取单个节点的历史数据记录
* 15、单节点数据订阅
* 16、取消单节点数据订阅
* 17、批量节点数据订阅
* 18、取消所有节点的数据订阅
*
* Date:2021
* Version:0.1版本
* Author:Coffee
* Modify Recoder:
*/
using Opc.Ua;
using Opc.Ua.Client;
using OpcUaHelper;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
namespace Utils
{
public class OPCUAHelper
{
#region 基础参数
//OPCUA客户端
private OpcUaClient opcUaClient;
#endregion
/// <summary>
/// 构造函数
/// </summary>
public OPCUAHelper()
{
opcUaClient = new OpcUaClient();
}
/// <summary>
/// 连接状态
/// </summary>
public bool ConnectStatus
{
get { return opcUaClient.Connected; }
}
#region 公有方法
/// <summary>
/// 打开连接【匿名方式】
/// </summary>
/// <param name="serverUrl">服务器URL【格式:opc.tcp://服务器IP地址/服务名称】</param>
public async void OpenConnectOfAnonymous(string serverUrl)
{
if (!string.IsNullOrEmpty(serverUrl))
{
try
{
opcUaClient.UserIdentity = new UserIdentity(new AnonymousIdentityToken());
await opcUaClient.ConnectServer(serverUrl);
}
catch (Exception ex)
{
ClientUtils.HandleException("连接失败!!!", ex);
}
}
}
/// <summary>
/// 打开连接【账号方式】
/// </summary>
/// <param name="serverUrl">服务器URL【格式:opc.tcp://服务器IP地址/服务名称】</param>
/// <param name="userName">用户名称</param>
/// <param name="userPwd">用户密码</param>
public async void OpenConnectOfAccount(string serverUrl,string userName,string userPwd)
{
if (!string.IsNullOrEmpty(serverUrl) &&
!string.IsNullOrEmpty(userName) && !string.IsNullOrEmpty(userPwd))
{
try
{
opcUaClient.UserIdentity = new UserIdentity(userName,userPwd);
await opcUaClient.ConnectServer(serverUrl);
}
catch (Exception ex)
{
ClientUtils.HandleException("连接失败!!!", ex);
}
}
}
/// <summary>
/// 打开连接【证书方式】
/// </summary>
/// <param name="serverUrl">服务器URL【格式:opc.tcp://服务器IP地址/服务名称】</param>
/// <param name="certificatePath">证书路径</param>
/// <param name="secreKey">密钥</param>
public async void OpenConnectOfCertificate(string serverUrl,string certificatePath,string secreKey)
{
if (!string.IsNullOrEmpty(serverUrl) &&
!string.IsNullOrEmpty(certificatePath) && !string.IsNullOrEmpty(secreKey))
{
try
{
X509Certificate2 certificate = new X509Certificate2(certificatePath, secreKey, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.Exportable);
opcUaClient.UserIdentity = new UserIdentity(certificate);
await opcUaClient.ConnectServer(serverUrl);
}
catch (Exception ex)
{
ClientUtils.HandleException("连接失败!!!", ex);
}
}
}
/// <summary>
/// 关闭连接
/// </summary>
public void CloseConnect()
{
if (opcUaClient!=null)
{
try
{
opcUaClient.Disconnect();
}
catch (Exception ex)
{
ClientUtils.HandleException("关闭连接失败!!!", ex);
}
}
}
/// <summary>
/// 获取到当前节点的值【同步读取】
/// </summary>
/// <typeparam name="T">节点对应的数据类型</typeparam>
/// <param name="nodeId">节点</param>
/// <returns>返回当前节点的值</returns>
public T GetCurrentNodeValue<T>(string nodeId)
{
T value = default(T);
if (!string.IsNullOrEmpty(nodeId) && ConnectStatus)
{
try
{
value = opcUaClient.ReadNode<T>(nodeId);
}
catch (Exception ex)
{
ClientUtils.HandleException("读取失败!!!",ex);
}
}
return value;
}
/// <summary>
/// 获取到当前节点数据【同步读取】
/// </summary>
/// <typeparam name="T">节点对应的数据类型</typeparam>
/// <param name="nodeId">节点</param>
/// <returns>返回当前节点的值</returns>
public DataValue GetCurrentNodeValue(string nodeId)
{
DataValue dataValue = null;
if (!string.IsNullOrEmpty(nodeId) && ConnectStatus)
{
try
{
dataValue = opcUaClient.ReadNode(nodeId);
}
catch (Exception ex)
{
ClientUtils.HandleException("读取失败!!!", ex);
}
}
return dataValue;
}
/// <summary>
/// 获取到批量节点数据【同步读取】
/// </summary>
/// <param name="nodeIds">节点列表</param>
/// <returns>返回节点数据字典</returns>
public Dictionary<string,DataValue> GetBatchNodeDatasOfSync(List<NodeId> nodeIdList)
{
Dictionary<string, DataValue> dicNodeInfo = new Dictionary<string, DataValue>();
if (nodeIdList != null && nodeIdList.Count>0 && ConnectStatus)
{
try
{
List<DataValue> dataValues = opcUaClient.ReadNodes(nodeIdList.ToArray());
int count = nodeIdList.Count;
for (int i = 0; i < count; i++)
{
AddInfoToDic(dicNodeInfo, nodeIdList[i].ToString(),dataValues[i]);
}
}
catch (Exception ex)
{
ClientUtils.HandleException("读取失败!!!", ex);
}
}
return dicNodeInfo;
}
/// <summary>
/// 获取到当前节点的值【异步读取】
/// </summary>
/// <typeparam name="T">节点对应的数据类型</typeparam>
/// <param name="nodeId">节点</param>
/// <returns>返回当前节点的值</returns>
public async Task<T> GetCurrentNodeValueOfAsync<T>(string nodeId)
{
T value = default(T);
if (!string.IsNullOrEmpty(nodeId) && ConnectStatus)
{
try
{
value =await opcUaClient.ReadNodeAsync<T>(nodeId);
}
catch (Exception ex)
{
ClientUtils.HandleException("读取失败!!!", ex);
}
}
return value;
}
/// <summary>
/// 获取到批量节点数据【异步读取】
/// </summary>
/// <param name="nodeIds">节点列表</param>
/// <returns>返回节点数据字典</returns>
public async Task<Dictionary<string, DataValue>> GetBatchNodeDatasOfAsync(List<NodeId> nodeIdList)
{
Dictionary<string, DataValue> dicNodeInfo = new Dictionary<string, DataValue>();
if (nodeIdList != null && nodeIdList.Count > 0 && ConnectStatus)
{
try
{
List<DataValue> dataValues = await opcUaClient.ReadNodesAsync(nodeIdList.ToArray());
int count = nodeIdList.Count;
for (int i = 0; i < count; i++)
{
AddInfoToDic(dicNodeInfo, nodeIdList[i].ToString(), dataValues[i]);
}
}
catch (Exception ex)
{
ClientUtils.HandleException("读取失败!!!", ex);
}
}
return dicNodeInfo;
}
/// <summary>
/// 获取到当前节点的关联节点
/// </summary>
/// <param name="nodeId">当前节点</param>
/// <returns>返回当前节点的关联节点</returns>
public ReferenceDescription[] GetAllRelationNodeOfNodeId(string nodeId)
{
ReferenceDescription[] referenceDescriptions = null;
if (!string.IsNullOrEmpty(nodeId) && ConnectStatus)
{
try
{
referenceDescriptions = opcUaClient.BrowseNodeReference(nodeId);
}
catch (Exception ex)
{
string str = "获取当前: "+nodeId+" 节点的相关节点失败!!!";
ClientUtils.HandleException(str, ex);
}
}
return referenceDescriptions;
}
/// <summary>
/// 获取到当前节点的所有属性
/// </summary>
/// <param name="nodeId">当前节点</param>
/// <returns>返回当前节点对应的所有属性</returns>
public OpcNodeAttribute[] GetCurrentNodeAttributes(string nodeId)
{
OpcNodeAttribute[] opcNodeAttributes=null;
if (!string.IsNullOrEmpty(nodeId) && ConnectStatus)
{
try
{
opcNodeAttributes = opcUaClient.ReadNoteAttributes(nodeId);
}
catch (Exception ex)
{
string str = "读取节点;" + nodeId + " 的所有属性失败!!!";
ClientUtils.HandleException(str, ex);
}
}
return opcNodeAttributes;
}
/// <summary>
/// 写入单个节点【同步方式】
/// </summary>
/// <typeparam name="T">写入节点值得数据类型</typeparam>
/// <param name="nodeId">节点</param>
/// <param name="value">节点对应的数据值(比如:(short)123))</param>
/// <returns>返回写入结果(true:表示写入成功)</returns>
public bool WriteSingleNodeIdOfSync<T>(string nodeId,T value)
{
bool success = false;
if (opcUaClient!=null && ConnectStatus)
{
if (!string.IsNullOrEmpty(nodeId))
{
try
{
success = opcUaClient.WriteNode(nodeId, value);
}
catch (Exception ex)
{
string str = "当前节点:" + nodeId + " 写入失败";
ClientUtils.HandleException(str, ex);
}
}
}
return success;
}
/// <summary>
/// 批量写入节点
/// </summary>
/// <param name="nodeIdArray">节点数组</param>
/// <param name="nodeIdValueArray">节点对应数据数组</param>
/// <returns>返回写入结果(true:表示写入成功)</returns>
public bool BatchWriteNodeIds(string[] nodeIdArray, object[] nodeIdValueArray)
{
bool success = false;
if (nodeIdArray != null && nodeIdArray.Length > 0 &&
nodeIdValueArray != null && nodeIdValueArray.Length > 0)
{
try
{
success = opcUaClient.WriteNodes(nodeIdArray, nodeIdValueArray);
}
catch (Exception ex)
{
ClientUtils.HandleException("批量写入节点失败!!!", ex);
}
}
return success;
}
/// <summary>
/// 写入单个节点【异步方式】
/// </summary>
/// <typeparam name="T">写入节点值得数据类型</typeparam>
/// <param name="nodeId">节点</param>
/// <param name="value">节点对应的数据值</param>
/// <returns>返回写入结果(true:表示写入成功)</returns>
public async Task<bool> WriteSingleNodeIdOfAsync<T>(string nodeId, T value)
{
bool success = false;
if (opcUaClient != null && ConnectStatus)
{
if (!string.IsNullOrEmpty(nodeId))
{
try
{
success = await opcUaClient.WriteNodeAsync(nodeId, value);
}
catch (Exception ex)
{
string str = "当前节点:"+nodeId+" 写入失败";
ClientUtils.HandleException(str, ex);
}
}
}
return success;
}
/// <summary>
/// 读取单个节点的历史数据记录
/// </summary>
/// <typeparam name="T">节点的数据类型</typeparam>
/// <param name="nodeId">节点</param>
/// <param name="startTime">开始时间</param>
/// <param name="endTime">结束时间</param>
/// <returns>返回该节点对应的历史数据记录</returns>
public List<T> ReadSingleNodeIdHistoryDatas<T>(string nodeId, DateTime startTime, DateTime endTime)
{
List<T> nodeIdDatas = null;
if (!string.IsNullOrEmpty(nodeId) && startTime!=null && endTime!=null && endTime>startTime)
{
try
{
nodeIdDatas = opcUaClient.ReadHistoryRawDataValues<T>(nodeId, startTime, endTime).ToList();
}
catch (Exception ex)
{
ClientUtils.HandleException("读取失败", ex);
}
}
return nodeIdDatas;
}
/// <summary>
/// 读取单个节点的历史数据记录
/// </summary>
/// <typeparam name="T">节点的数据类型</typeparam>
/// <param name="nodeId">节点</param>
/// <param name="startTime">开始时间</param>
/// <param name="endTime">结束时间</param>
/// <returns>返回该节点对应的历史数据记录</returns>
public List<DataValue> ReadSingleNodeIdHistoryDatas(string nodeId, DateTime startTime, DateTime endTime)
{
List<DataValue> nodeIdDatas = null;
if (!string.IsNullOrEmpty(nodeId) && startTime != null && endTime != null && endTime > startTime)
{
if (ConnectStatus)
{
try
{
nodeIdDatas = opcUaClient.ReadHistoryRawDataValues(nodeId, startTime, endTime).ToList();
}
catch (Exception ex)
{
ClientUtils.HandleException("读取失败", ex);
}
}
}
return nodeIdDatas;
}
/// <summary>
/// 单节点数据订阅
/// </summary>
/// <param name="key">订阅的关键字(必须唯一)</param>
/// <param name="nodeId">节点</param>
/// <param name="callback">数据订阅的回调方法</param>
public void SingleNodeIdDatasSubscription(string key, string nodeId, Action<string, MonitoredItem, MonitoredItemNotificationEventArgs> callback)
{
if (ConnectStatus)
{
try
{
opcUaClient.AddSubscription(key,nodeId,callback);
}
catch (Exception ex)
{
string str = "订阅节点:" + nodeId + " 数据失败!!!";
ClientUtils.HandleException(str, ex);
}
}
}
/// <summary>
/// 取消单节点数据订阅
/// </summary>
/// <param name="key">订阅的关键字</param>
public bool CancelSingleNodeIdDatasSubscription(string key)
{
bool success = false;
if (!string.IsNullOrEmpty(key))
{
if (ConnectStatus)
{
try
{
opcUaClient.RemoveSubscription(key);
success = true;
}
catch (Exception ex)
{
string str = "取消 " +key+ " 的订阅失败";
ClientUtils.HandleException(str, ex);
}
}
}
return success;
}
/// <summary>
/// 批量节点数据订阅
/// </summary>
/// <param name="key">订阅的关键字(必须唯一)</param>
/// <param name="nodeIds">节点数组</param>
/// <param name="callback">数据订阅的回调方法</param>
public void BatchNodeIdDatasSubscription(string key, string[] nodeIds, Action<string, MonitoredItem, MonitoredItemNotificationEventArgs> callback)
{
if (!string.IsNullOrEmpty(key) && nodeIds!=null && nodeIds.Length>0)
{
if (ConnectStatus)
{
try
{
opcUaClient.AddSubscription(key, nodeIds, callback);
}
catch (Exception ex)
{
string str = "批量订阅节点数据失败!!!";
ClientUtils.HandleException(str, ex);
}
}
}
}
/// <summary>
/// 取消所有节点的数据订阅
/// </summary>
/// <returns></returns>
public bool CancelAllNodeIdDatasSubscription()
{
bool success = false;
if (ConnectStatus)
{
try
{
opcUaClient.RemoveAllSubscription();
success = true;
}
catch (Exception ex)
{
ClientUtils.HandleException("取消所有的节点数据订阅失败!!!", ex);
}
}
return success;
}
#endregion
#region 私有方法
/// <summary>
/// 添加数据到字典中(相同键的则采用最后一个键对应的值)
/// </summary>
/// <param name="dic">字典</param>
/// <param name="key">键</param>
/// <param name="dataValue">值</param>
private void AddInfoToDic(Dictionary<string,DataValue> dic,string key,DataValue dataValue)
{
if (dic!=null)
{
if (!dic.ContainsKey(key))
{
dic.Add(key, dataValue);
}
else
{
dic[key] = dataValue;
}
}
}
#endregion
}//Class_end
}
3.2、运行项目测试
C#使用OpcUaHelper开源库开发的客户端实现读取、订阅OPC UA服务器节点项目工程下载
更多推荐
已为社区贡献21条内容
所有评论(0)