目录
一、内容准备
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服务器节点项目工程下载
转载:https://blog.csdn.net/xiaochenXIHUA/article/details/117254108
查看评论