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简化操作

posted on 2025-03-19 10:45  张彦山  阅读(463)  评论(0)    收藏  举报