OPCUA 同步和异步读取节点值
一、获取服务器节点列表信息
1、二级节点
new NodeId("ns=2;s=通道 1")
节点格式
ns: namespace XML格式结构,比如<Window xmlns:x="dfsefsef" xmlns:>,一般固定2,第二层级
s:string字符串
i: int i=83
如果需要所有分枝 需要利用递归处理
2、一级所有标签全部拿到?
ObjectIds.ObjectsFolder 一级菜单
3、如何获取根节点root
Objects、Types、Vews
每个节点都有对应的节点id
用Soft OPC Client连接服务端
服务端信任生成的请求证书

重新验证,成功

注意,连接产生的证书会过一段时间才会显示到列表中
信任后需要重新初始化

读取节点代码
// 浏览节点的目的就是为了可以做节点浏览配置 private static void BrowseNodes(Session session) { // 两种处理方式 Browser browser = new Browser(session); // 正确处理? 是,正确拿列表 // 关于NodeId:格式有要求 // ns namespace XML格式结构 // s string // i int i=84 // <Window xmlns:x="dfsefsef" xmlns:> // </Windows> //var collection = browser.Browse(new NodeId("ns=2;s=通道 1"));//通道 1.设备 1.标记 1 var collection = browser.Browse(new NodeId("ns=0;i=84")); foreach (var item in collection) { var temp = browser.Browse((NodeId)item.NodeId); foreach (var t in temp) { } } // 如果需要所有分枝 需要利用递归处理 // 第二种方法,传参数比较多麻烦一些,就不展示了 //session.Browse(); }
二、同步读取
session.Read方法
1、同步单个读
private static void UARead(Session session) { //RequestHeader requestHeader, 请求参数 //double maxAge, 毫秒 1000,设置为0,直接获取最新当前数据,没有缓存历史数据 //TimestampsToReturn timestampsToReturn, 返回结果(两个:服务端/客户端)的时间戳 //ReadValueIdCollection nodesToRead, 需要请求的Node集合 //out DataValueCollection results, 返回对应的Node的数据 //out DiagnosticInfoCollection diagnosticInfos 诊断信息 ReadValueIdCollection readValueIds = new ReadValueIdCollection(); ReadValueId readValueId = new ReadValueId() { NodeId = "ns=2;s=通道 2.设备 1.湿度",// 值 AttributeId = Attributes.Value //也可以读其他属性 }; readValueIds.Add(readValueId); session.Read( new RequestHeader(), 0, TimestampsToReturn.Both, readValueIds, out DataValueCollection results, out DiagnosticInfoCollection diagnosticInfos ); foreach (var value in results) { if (value.WrappedValue.TypeInfo.ValueRank == -1)//针对值结果 Console.WriteLine(value); else if (value.WrappedValue.TypeInfo.ValueRank == 1)// 针对集合结果 { foreach (var v in (ushort[])value.WrappedValue.Value) Console.WriteLine(v); } } }
2、多个读、集合读

readValueId = new ReadValueId() { NodeId = "ns=2;s=数据类型示例.16 位设备.R 寄存器.Word4",// 值 AttributeId = Attributes.Value }; readValueIds.Add(readValueId); readValueId = new ReadValueId() { Handle = 10, NodeId = "ns=2;s=数据类型示例.16 位设备.R 寄存器.WordArray",// 集合 AttributeId = Attributes.Value }; readValueIds.Add(readValueId);
结果

参数判断是否是集合

Rank队列
-1不是集合
1是集合
foreach (var value in results) { if (value.WrappedValue.TypeInfo.ValueRank == -1)//针对值结果 Console.WriteLine(value); else if (value.WrappedValue.TypeInfo.ValueRank == 1)// 针对集合结果 { foreach (var v in (ushort[])value.WrappedValue.Value) Console.WriteLine(v); } }


通过下标的方式一一对应
三、异步
session.BeginRead方法 和
EndRead方法
前面四个参数一样
后面返回的不一样,异步没有直接返回,需要一个异步回调委托
callback: ReadCommpleted,
session
//RequestHeader requestHeader, // double maxAge, // TimestampsToReturn timestampsToReturn, // ReadValueIdCollection nodesToRead, // AsyncCallback callback, // object asyncState session.BeginRead( new RequestHeader(), 0, TimestampsToReturn.Both, readValueIds, callback: ReadCommpleted, session//传递到回调方法里面 );
回调方法,结果在这里面获取
result.AsyncState 获取到会话
EndRead获取结果
private static void ReadCommpleted(IAsyncResult result) { var session = result.AsyncState as Session; session.EndRead( result, out DataValueCollection results, out DiagnosticInfoCollection diagnosticInfos); foreach (var value in results) { if (value.WrappedValue.TypeInfo.ValueRank == -1)//针对值结果 Console.WriteLine(value); else if (value.WrappedValue.TypeInfo.ValueRank == 1)// 针对集合结果 { foreach (var v in (ushort[])value.WrappedValue.Value) Console.WriteLine(v); } } }
2、List集合一对一获取值
// 业务层 class RequestNode { public string NodeId { get; set; } public object Value { get; set; } }
UAAsyncRead
List<RequestNode> nodes = new List<RequestNode>(); nodes.Add(new RequestNode { NodeId = "ns=2;s=通道 1.设备 1.标记 2" }); nodes.Add(new RequestNode { NodeId = "ns=2;s=数据类型示例.16 位设备.R 寄存器.WordArray" }); UAAsyncRead(session, nodes, () => { foreach (var node in nodes) { Console.WriteLine($"{node.NodeId}:{node.Value}"); } });
增加一个Action callback回调方法,在上面调用委托
() =>之后执行拿到的结果
private static async void UAAsyncRead(Session session, List<RequestNode> nodes, Action callback) { ReadValueIdCollection readValueIds = new ReadValueIdCollection(); foreach (var node in nodes) { readValueIds.Add(new ReadValueId { NodeId = node.NodeId, AttributeId = Attributes.Value }); } //CancellationToken cancellationToken = new CancellationToken(); //var result = await session.ReadAsync(null, 0, TimestampsToReturn.Both, readValueIds, cancellationToken); session.BeginRead( new RequestHeader(), 0, TimestampsToReturn.Both, readValueIds, callback: result => { session.EndRead( result, out DataValueCollection results, out DiagnosticInfoCollection diagnosticInfos); for (int i = 0; i < nodes.Count; i++) { nodes[i].Value = results[i].Value; } callback(); }, session ); }
3、也可以通过
await session.ReadAsync方式返回Task方式拿到结果
//CancellationToken cancellationToken = new CancellationToken();
//var result = await session.ReadAsync(null, 0, TimestampsToReturn.Both, readValueIds, cancellationToken);
积累技术栈多,可以多一种思路解决,不钻牛角尖,提升开发周期
可以使用OpcUaHelper简化操作
浙公网安备 33010602011771号