using System;
using System.Threading;
using System.Threading.Tasks;
using Opc.Ua;
using Opc.Ua.Client;
using Opc.Ua.Configuration;
namespace ConsoleApp1
{
//参考至:https://github.com/dathlin/OpcUaHelper
class Program
{
/*
* 当前连接的会话
*/
private static Session m_session;
static async Task Main1(string[] args)
{
/*连接地址*/
string discoveryUrl = "opc.tcp://desktop-qk37pau:4990/FactoryTalkLinxGateway1";
m_session = await createSession(discoveryUrl);
/*
* 保持活动回调方法 订阅?
*/
//m_session.KeepAlive += new KeepAliveEventHandler(Session_KeepAlive);
/**
* 获取根节点
* @Param ObjectIds.ObjectsFolder 根节点
* @Param ReferenceTypes.Organizes 根节点的协议类型
*/
ReferenceDescriptionCollection rootRDs = getNode(ObjectIds.ObjectsFolder, ReferenceTypes.Organizes,
m_session);
/**
* 根节点数据结构及返回值探究
*/
testRoot(rootRDs);
/**
* Server节点下的信息
* @Param ReferenceTypes.Aggregates 是Server节点的协议类型
*/
NodeId serverNode = (NodeId) rootRDs[0].NodeId;
ReferenceDescriptionCollection serverRDs = getNode(serverNode, ReferenceTypes.Aggregates, m_session);
/**
* factoryTalkLinxGateway节点下的信息
* @Param ReferenceTypes.Organizes 是factoryTalkLinxGateway节点的协议类型
*/
NodeId ftgNode = (NodeId) rootRDs[1].NodeId;
ReferenceDescriptionCollection ftgRDs = getNode(ftgNode, ReferenceTypes.Organizes, m_session);
/**
* factoryTalkLinxGateway节点下
* xx 设备节点
*/
NodeId xxNode = (NodeId) ftgRDs[0].NodeId;
ReferenceDescriptionCollection xxRDs = getNode(xxNode, ReferenceTypes.Organizes, m_session);
/**
* xx 设备节点下
* online 节点
*/
NodeId onlineNode = (NodeId) xxRDs[1].NodeId;
ReferenceDescriptionCollection onlineRDs = getNode(onlineNode, ReferenceTypes.Organizes, m_session);
/**
* online 节点
* i1 节点
*/
NodeId i1Node = (NodeId) onlineRDs[0].NodeId;
NodeId i2Node = (NodeId) onlineRDs[1].NodeId;
ReferenceDescriptionCollection i1RDs = getNode(i1Node, ReferenceTypes.Organizes, m_session);
/**
* 修改i1节点参数
*/
overWriteNode(m_session, i1Node);
/**
* 获取节点的某属性
*/
DataValueCollection DataValues = getAtrrbutes(m_session, i1Node, i2Node);
/**
* 获取历史数据
*/
HistoryReadResultCollection historys = getHistory(m_session, i1Node);
}
static async Task Main(string[] args)
{
// string discoveryUrl = “opc.tcp://118.24.36.220:62547/DataAccessServer”;
string discoveryUrl = “opc.tcp://DESKTOP-QK37PAU:4990/FactoryTalkLinxGateway1”;
m_session = await createSession(discoveryUrl);
NodeId node = new NodeId("ns=3;s=[xx]i1");
//订阅
subNodes(m_session, node);
while (true)
{
Thread.Sleep(1000);
Console.WriteLine("程序运行中"+DateTime.Now);
}
}
/*
* 创建应用实例 并进行配置
*/
private static ApplicationInstance initConfig()
{
/**
*不加证书验证配置会报错
*/
var certificateValidator = new CertificateValidator();
certificateValidator.CertificateValidation += (sender, eventArgs) =>
{
if (ServiceResult.IsGood(eventArgs.Error))
eventArgs.Accept = true;
else if (eventArgs.Error.StatusCode.Code == StatusCodes.BadCertificateUntrusted)
eventArgs.Accept = true;
else
throw new Exception(string.Format("Failed to validate certificate with error code {0}: {1}",
eventArgs.Error.Code, eventArgs.Error.AdditionalInfo));
};
return new ApplicationInstance
{
/*
* 指定应用类型
*/
ApplicationType = ApplicationType.Client,
/*
* 配置名
*/
ConfigSectionName = "ConnentDemoConfig",
/*
* 应用的个配置项
*/
ApplicationConfiguration = new ApplicationConfiguration
{
ApplicationName = "ConnentDemo",
ApplicationType = ApplicationType.Client,
/*
* 证书验证配置
*/
CertificateValidator = certificateValidator,
/*
* 服务端配置
*/
ServerConfiguration = new ServerConfiguration
{
MaxSubscriptionCount = 100000,
MaxMessageQueueSize = 1000000,
MaxNotificationQueueSize = 1000000,
MaxPublishRequestCount = 10000000,
},
/*
* 安全配置
*/
SecurityConfiguration = new SecurityConfiguration
{
AutoAcceptUntrustedCertificates = true,
RejectSHA1SignedCertificates = false,
MinimumCertificateKeySize = 1024,
},
TransportQuotas = new TransportQuotas
{
OperationTimeout = 6000000,
MaxStringLength = int.MaxValue,
MaxByteStringLength = int.MaxValue,
MaxArrayLength = 65535,
MaxMessageSize = 419430400,
MaxBufferSize = 65535,
ChannelLifetime = -1,
SecurityTokenLifetime = -1
},
/*
* 客户端配置
*/
ClientConfiguration = new ClientConfiguration
{
DefaultSessionTimeout = -1,
MinSubscriptionLifetime = -1,
},
DisableHiResClock = true
}
};
}
/*
* TODO
* 事件委托 当会话有变化时会执行下面方法
*/
private static void Session_KeepAlive(Session session, KeepAliveEventArgs e)
{
Console.WriteLine("Session:" + session);
Console.WriteLine("KeepAliveEventArgs:" + e);
}
/**
* 创建客户端 配置服务端
* @Param url 服务端地址
* @Param application 实例配置
* @return 返回服务端配置信息
*/
private static ConfiguredEndpoint createClient(String url, ApplicationInstance application)
{
Uri serverUrl = new Uri(url);
/*节点配置 默认*/
EndpointConfiguration configuration = EndpointConfiguration.Create();
/*
* @Param serverUrl 服务器 url
* @与配置类 生成客户端连接
*/
EndpointDescription endpointDescription = null;
using (DiscoveryClient discoveryClient = DiscoveryClient.Create(serverUrl, configuration))
{
/*获取所有的节点*/
EndpointDescriptionCollection endpoints = discoveryClient.GetEndpoints((StringCollection) null);
/*取出起一个节点*/
endpointDescription = endpoints[0];
}
EndpointConfiguration endpointConfiguration =
EndpointConfiguration.Create(application.ApplicationConfiguration);
ConfiguredEndpoint configuredEndpoint =
new ConfiguredEndpoint(null, endpointDescription, endpointConfiguration);
return configuredEndpoint;
}
/**
* 创建Session
*/
private static async Task createSession(String Url)
{
/*获取应用实例 并对其进行参数配置*/
ApplicationInstance application = initConfig();
/*
* 登录策略 默认匿名
* TODO 用户名密码策略与证书登录策略未实验
*/
IUserIdentity iUserIdentity = new UserIdentity();
/**
* 获取连接配置
*/
ConfiguredEndpoint configuredEndpoint = createClient(Url, application);
/*
* 创建会话连接
*/
Session session = await Session.Create(
application.ApplicationConfiguration,
configuredEndpoint,
false,
false,
application.ApplicationConfiguration.ApplicationName,
60000,
iUserIdentity,
new string[] { });
return session;
}
/**
* 设置要查找的节点
*/
private static BrowseDescriptionCollection nodeConfig(NodeId nodeId, NodeId referenceTypeId)
{
/**
* @see Opc.Ua.ObjectIds 要查找节点的定义
* 要浏览的节点描述
* 当页面初始化时使用 ObjectIds.ObjectsFolder 获取节点
*/
BrowseDescription nodeToBrowse = new BrowseDescription();
nodeToBrowse.NodeId = nodeId;
nodeToBrowse.BrowseDirection = BrowseDirection.Forward;
/**
* 要查找的节点要与其协议类型匹配 不然查找不到节点信息
* @see Opc.Ua.ReferenceTypeIds
* Organizes 组织
* Aggregates 合计 根节点下的server子节点使用此类型
*/
nodeToBrowse.ReferenceTypeId = referenceTypeId;
nodeToBrowse.IncludeSubtypes = true;
/**
* 查找节点的类型
* Unspecified 不指定 则显示所有类型
* Variable 变量
*/
nodeToBrowse.NodeClassMask = (uint) NodeClass.Unspecified;
/**
* 设置BrowseResult的返回信息
* BrowseResultMask.All显示全部
*/
nodeToBrowse.ResultMask = (uint) BrowseResultMask.All;
BrowseDescriptionCollection BDCollection = new BrowseDescriptionCollection();
BDCollection.Add(nodeToBrowse);
return BDCollection;
}
/**
* 获取根节点
* @Param nodeId 要查找的节点
* @Param referenceTypeId 要查找的节点的协议类型
* @Param nodeId session 与opcServer连接的session
* @Param nodeId results 返回值
* @Param nodeId diagnosticInfos TODO
*/
private static ReferenceDescriptionCollection getNode(NodeId nodeId, NodeId referenceTypeId, Session session)
{
BrowseDescriptionCollection BDCollection = nodeConfig(nodeId, referenceTypeId);
// 发送请求 获取节点
session.Browse(
null,
null,
0,
BDCollection,
out BrowseResultCollection results,
out DiagnosticInfoCollection diagnosticInfos
);
return results[0].References;
}
/**
* 根节点
*/
private static void testRoot(ReferenceDescriptionCollection referenceDescriptions)
{
foreach (var references in referenceDescriptions)
{
NodeId nodeId = (NodeId) references.NodeId;
/**
* Server节点类型为Numeric 它没有节点名和命名空间
*/
if (nodeId.IdType == IdType.Numeric)
continue;
//节点名
String name = (String) nodeId.Identifier;
//命名空间
int namespaceIndex = nodeId.NamespaceIndex;
}
}
/**
* 修改节点值
*/
private static void overWriteNode(Session session, params NodeId[] nodeId)
{
/**
* 修改节点数据
* @see Opc.Ua.BuiltInType UA内置参数类型 可用于参数校验
*/
WriteValue valueToWrite = new WriteValue();
// 要修改的节点 测试取第一个
valueToWrite.NodeId = nodeId[0];
// 要修改什么属性
valueToWrite.AttributeId = Attributes.Value;
// 修改值
valueToWrite.Value.Value = 9;
// 可省略
// valueToWrite.Value.StatusCode = StatusCodes.Good;
// valueToWrite.Value.ServerTimestamp = DateTime.MinValue;
// valueToWrite.Value.SourceTimestamp = DateTime.MinValue;
WriteValueCollection valuesToWrite = new WriteValueCollection(1);
valuesToWrite.Add(valueToWrite);
// 发送修改请求 TODO 为什么成功返回的状态值有一个bad
session.Write(
null,
valuesToWrite,
out StatusCodeCollection statusCodeResults,
out DiagnosticInfoCollection diagnosticInfos);
}
/**
* 节点属性
*/
private static DataValueCollection getAtrrbutes(Session session, params NodeId[] nodeIds)
{
/**
* 要读取的点
*/
ReadValueIdCollection nodesToRead = new ReadValueIdCollection();
foreach (var nodeId in nodeIds)
{
ReadValueId readValueId = new ReadValueId();
readValueId.NodeId = nodeId;
readValueId.AttributeId = Attributes.BrowseName;
nodesToRead.Add(readValueId);
}
m_session.Read(
null,
0,
TimestampsToReturn.Neither,
nodesToRead,
out DataValueCollection results,
out DiagnosticInfoCollection diagnosticInfos);
return results;
}
/**
* 获取节点的历史数据 TODO 读取不了
*/
private static HistoryReadResultCollection getHistory(Session session, params NodeId[] nodeIds)
{
HistoryReadValueIdCollection nodesToRead = new HistoryReadValueIdCollection();
/**
* 要查找的点
*/
foreach (var nodeId in nodeIds)
{
HistoryReadValueId node = new HistoryReadValueId()
{
NodeId = nodeId
};
nodesToRead.Add(node);
}
/**
* 要获取节点的信息
*/
ReadRawModifiedDetails m_details = new ReadRawModifiedDetails
{
// 开始时间
StartTime = new DateTime(2018, 12, 1),
// 结束时间
EndTime = new DateTime(2019, 12, 10),
NumValuesPerNode = 1,
IsReadModified = false,
ReturnBounds = false
};
m_session.HistoryRead(
null,
new ExtensionObject(m_details),
TimestampsToReturn.Both,
false,
nodesToRead,
out HistoryReadResultCollection results,
out DiagnosticInfoCollection diagnosticInfos);
return results;
}
/**
* 订阅
*/
private static void subNodes(Session session, params NodeId[] nodeIds)
{
/**
* 订阅的相关配置
*/
Subscription subConfig = new Subscription(session.DefaultSubscription);
subConfig.PublishingEnabled = true;
subConfig.PublishingInterval = 0;
subConfig.KeepAliveCount = uint.MaxValue;
subConfig.LifetimeCount = uint.MaxValue;
subConfig.MaxNotificationsPerPublish = uint.MaxValue;
subConfig.Priority = 100;
//订阅的主题key
subConfig.DisplayName = "test";
//要监听的点
foreach (var node in nodeIds)
{
var item = new MonitoredItem
{
StartNodeId = node,
AttributeId = Attributes.Value,
DisplayName = node.ToString(),
SamplingInterval = 100,
};
/**
* 当监听点发生改变时调用的函数
*/
item.Notification += (MonitoredItem monitoredItem, MonitoredItemNotificationEventArgs args) =>
{
subCallback("test", monitoredItem, args);
};
/**
* 将点添加到订阅配置中
*/
subConfig.AddItem(item);
}
/**
* AddSubscription 添加订阅
* RemoveSubscription 删除订阅
* 执行删除方法前要将 Subscription中的Delete方法传入true
* 例:subConfig.Delete(true);
*/
session.AddSubscription(subConfig);
/**
* TODO??
*/
subConfig.Create();
}
/**
* 当监听点发生改变时调用的函数
*/
private static void subCallback(string key, MonitoredItem monitoredItem, MonitoredItemNotificationEventArgs args )
{
MonitoredItemNotification notification = args.NotificationValue as MonitoredItemNotification;
ExpandedNodeId e=notification.TypeId;
DataValue d=notification.Value;
NotificationMessage n=notification.Message;
}
}
}