示例#1
0
        public static async Task <IEnumerable <ReferenceDescription[]> > BrowseOpcServerAsync(UaTcpSessionChannel channel, NodeId BrowseRoot)
        {
            BrowseRequest browseRequest = new BrowseRequest()
            {
                NodesToBrowse = new BrowseDescription[] { new BrowseDescription()
                                                          {
                                                              NodeId = BrowseRoot, BrowseDirection = BrowseDirection.Forward, ReferenceTypeId = NodeId.Parse(ReferenceTypeIds.HierarchicalReferences), NodeClassMask = (uint)NodeClass.Variable | (uint)NodeClass.Object | (uint)NodeClass.Method, IncludeSubtypes = true, ResultMask = (uint)BrowseResultMask.All
                                                          } },
            };
            var browseResponse = await channel.BrowseAsync(browseRequest);

            var temp = browseResponse.Results.Select((a) => a.References ?? new ReferenceDescription[0]);

            return(temp);
        }
示例#2
0
        public async Task BrowseObjects()
        {
            var channel = new UaTcpSessionChannel(
                localDescription,
                certificateStore,
                new AnonymousIdentity(),
                EndpointUrl,
                SecurityPolicyUris.None,
                loggerFactory: loggerFactory);

            await channel.OpenAsync();

            var rds           = new List <ReferenceDescription>();
            var browseRequest = new BrowseRequest {
                NodesToBrowse = new[] { new BrowseDescription {
                                            NodeId = ExpandedNodeId.ToNodeId(ExpandedNodeId.Parse(ObjectIds.ObjectsFolder), channel.NamespaceUris), ReferenceTypeId = NodeId.Parse(ReferenceTypeIds.HierarchicalReferences), ResultMask = (uint)BrowseResultMask.TargetInfo, NodeClassMask = (uint)NodeClass.Unspecified, BrowseDirection = BrowseDirection.Forward, IncludeSubtypes = true
                                        } }, RequestedMaxReferencesPerNode = 1000
            };
            var browseResponse = await channel.BrowseAsync(browseRequest).ConfigureAwait(false);

            rds.AddRange(browseResponse.Results.Where(result => result.References != null).SelectMany(result => result.References));
            var continuationPoints = browseResponse.Results.Select(br => br.ContinuationPoint).Where(cp => cp != null).ToArray();

            while (continuationPoints.Length > 0)
            {
                var browseNextRequest = new BrowseNextRequest {
                    ContinuationPoints = continuationPoints, ReleaseContinuationPoints = false
                };
                var browseNextResponse = await channel.BrowseNextAsync(browseNextRequest);

                rds.AddRange(browseNextResponse.Results.Where(result => result.References != null).SelectMany(result => result.References));
                continuationPoints = browseNextResponse.Results.Select(br => br.ContinuationPoint).Where(cp => cp != null).ToArray();
            }

            rds
            .Should().NotBeEmpty();

            logger.LogInformation("+ Objects, 0:Objects, Object");
            foreach (var rd in rds)
            {
                logger.LogInformation("   + {0}, {1}, {2}", rd.DisplayName, rd.BrowseName, rd.NodeClass);
            }

            logger.LogInformation($"Closing session '{channel.SessionId}'.");
            await channel.CloseAsync();
        }
示例#3
0
        public async Task BrowseRoot()
        {
            var channel = new UaTcpSessionChannel(
                this.localDescription,
                this.certificateStore,
                new AnonymousIdentity(),
                EndpointUrl,
                SecurityPolicyUris.None,
                loggerFactory: this.loggerFactory);

            await channel.OpenAsync();

            var rds           = new List <ReferenceDescription>();
            var browseRequest = new BrowseRequest {
                NodesToBrowse = new[] { new BrowseDescription {
                                            NodeId = ExpandedNodeId.ToNodeId(ExpandedNodeId.Parse(ObjectIds.RootFolder), channel.NamespaceUris), ReferenceTypeId = NodeId.Parse(ReferenceTypeIds.HierarchicalReferences), ResultMask = (uint)BrowseResultMask.TargetInfo, NodeClassMask = (uint)NodeClass.Unspecified, BrowseDirection = BrowseDirection.Forward, IncludeSubtypes = true
                                        } }, RequestedMaxReferencesPerNode = 1000
            };
            var browseResponse = await channel.BrowseAsync(browseRequest).ConfigureAwait(false);

            rds.AddRange(browseResponse.Results.Where(result => result.References != null).SelectMany(result => result.References));
            var continuationPoints = browseResponse.Results.Select(br => br.ContinuationPoint).Where(cp => cp != null).ToArray();

            while (continuationPoints.Length > 0)
            {
                var browseNextRequest = new BrowseNextRequest {
                    ContinuationPoints = continuationPoints, ReleaseContinuationPoints = false
                };
                var browseNextResponse = await channel.BrowseNextAsync(browseNextRequest);

                rds.AddRange(browseNextResponse.Results.Where(result => result.References != null).SelectMany(result => result.References));
                continuationPoints = browseNextResponse.Results.Select(br => br.ContinuationPoint).Where(cp => cp != null).ToArray();
            }

            Assert.IsTrue(rds.Count == 3);

            Console.WriteLine($"Closing session '{channel.SessionId}'.");
            await channel.CloseAsync();
        }
示例#4
0
        private async Task <IList <ReferenceDescription> > BrowseTree(NodeId tree)
        {
            var browseRequest = new BrowseRequest {
                NodesToBrowse = new[] {
                    new BrowseDescription {
                        NodeId          = tree,
                        ReferenceTypeId = NodeId.Parse(ReferenceTypeIds.HierarchicalReferences),
                        ResultMask      = (uint)BrowseResultMask.TargetInfo,
                        NodeClassMask   = (uint)NodeClass.Object | (int)NodeClass.Variable,
                        BrowseDirection = BrowseDirection.Forward,
                        IncludeSubtypes = true
                    }
                },
                RequestedMaxReferencesPerNode = 1000
            };

            var            rds            = new List <ReferenceDescription>();
            BrowseResponse browseResponse = await connection.BrowseAsync(browseRequest);

            rds.AddRange(browseResponse.Results.Where(result => result.References != null).SelectMany(result => result.References));

            var continuationPoints = browseResponse.Results.Select(br => br.ContinuationPoint).Where(cp => cp != null).ToArray();

            while (continuationPoints.Length > 0 && connection != null)
            {
                var browseNextRequest = new BrowseNextRequest {
                    ContinuationPoints = continuationPoints, ReleaseContinuationPoints = false
                };
                var browseNextResponse = await connection.BrowseNextAsync(browseNextRequest);

                rds.AddRange(browseNextResponse.Results.Where(result => result.References != null).SelectMany(result => result.References));
                continuationPoints = browseNextResponse.Results.Select(br => br.ContinuationPoint).Where(cp => cp != null).ToArray();
            }

            return(rds);
        }
示例#5
0
        private static async Task TestAsync()
        {
            var loggerFactory = new LoggerFactory();

            loggerFactory.AddDebug(LogLevel.Trace);

            var discoveryUrl = "opc.tcp://localhost:26543"; // Workstation.NodeServer

            //var discoveryUrl = "opc.tcp://localhost:48010"; // UaCppServer - see  http://www.unified-automation.com/
            //var discoveryUrl = "opc.tcp://localhost:16664"; // open62541

            Console.WriteLine("Step 1 - Describe this app.");
            var appDescription = new ApplicationDescription()
            {
                ApplicationName = "MyHomework",
                ApplicationUri  = $"urn:{System.Net.Dns.GetHostName()}:MyHomework",
                ApplicationType = ApplicationType.Client,
            };

            Console.WriteLine("Step 2 - Create a certificate store.");
            var certificateStore = new DirectoryStore(
                Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Workstation.ConsoleApp", "pki"));

            Console.WriteLine("Step 3 - Create a session with your server.");
            var channel = new UaTcpSessionChannel(
                appDescription,
                certificateStore,
                ShowSignInDialog,
                discoveryUrl,
                loggerFactory: loggerFactory);

            try
            {
                await channel.OpenAsync();

                Console.WriteLine($"  Opened channel with endpoint '{channel.RemoteEndpoint.EndpointUrl}'.");
                Console.WriteLine($"  SecurityPolicyUri: '{channel.RemoteEndpoint.SecurityPolicyUri}'.");
                Console.WriteLine($"  SecurityMode: '{channel.RemoteEndpoint.SecurityMode}'.");
                Console.WriteLine($"  UserIdentity: '{channel.UserIdentity}'.");

                Console.WriteLine("Press any key to continue...");
                Console.ReadKey(true);

                Console.WriteLine("Step 4 - Browse the server namespace.");
                Console.WriteLine("+ Root");
                BrowseRequest browseRequest = new BrowseRequest
                {
                    NodesToBrowse = new BrowseDescription[] { new BrowseDescription {
                                                                  NodeId = NodeId.Parse(ObjectIds.RootFolder), BrowseDirection = BrowseDirection.Forward, ReferenceTypeId = NodeId.Parse(ReferenceTypeIds.HierarchicalReferences), NodeClassMask = (uint)NodeClass.Variable | (uint)NodeClass.Object | (uint)NodeClass.Method, IncludeSubtypes = true, ResultMask = (uint)BrowseResultMask.All
                                                              } },
                };
                BrowseResponse browseResponse = await channel.BrowseAsync(browseRequest);

                foreach (var rd1 in browseResponse.Results[0].References ?? new ReferenceDescription[0])
                {
                    Console.WriteLine("  + {0}: {1}, {2}", rd1.DisplayName, rd1.BrowseName, rd1.NodeClass);
                    browseRequest = new BrowseRequest
                    {
                        NodesToBrowse = new BrowseDescription[] { new BrowseDescription {
                                                                      NodeId = ExpandedNodeId.ToNodeId(rd1.NodeId, channel.NamespaceUris), BrowseDirection = BrowseDirection.Forward, ReferenceTypeId = NodeId.Parse(ReferenceTypeIds.HierarchicalReferences), NodeClassMask = (uint)NodeClass.Variable | (uint)NodeClass.Object | (uint)NodeClass.Method, IncludeSubtypes = true, ResultMask = (uint)BrowseResultMask.All
                                                                  } },
                    };
                    browseResponse = await channel.BrowseAsync(browseRequest);

                    foreach (var rd2 in browseResponse.Results[0].References ?? new ReferenceDescription[0])
                    {
                        Console.WriteLine("    + {0}: {1}, {2}", rd2.DisplayName, rd2.BrowseName, rd2.NodeClass);
                        browseRequest = new BrowseRequest
                        {
                            NodesToBrowse = new BrowseDescription[] { new BrowseDescription {
                                                                          NodeId = ExpandedNodeId.ToNodeId(rd2.NodeId, channel.NamespaceUris), BrowseDirection = BrowseDirection.Forward, ReferenceTypeId = NodeId.Parse(ReferenceTypeIds.HierarchicalReferences), NodeClassMask = (uint)NodeClass.Variable | (uint)NodeClass.Object | (uint)NodeClass.Method, IncludeSubtypes = true, ResultMask = (uint)BrowseResultMask.All
                                                                      } },
                        };
                        browseResponse = await channel.BrowseAsync(browseRequest);

                        foreach (var rd3 in browseResponse.Results[0].References ?? new ReferenceDescription[0])
                        {
                            Console.WriteLine("      + {0}: {1}, {2}", rd3.DisplayName, rd3.BrowseName, rd3.NodeClass);
                        }
                    }
                }

                Console.WriteLine("Press any key to continue...");
                Console.ReadKey(true);

                Console.WriteLine("Step 5 - Create a subscription.");
                var subscriptionRequest = new CreateSubscriptionRequest
                {
                    RequestedPublishingInterval = 1000,
                    RequestedMaxKeepAliveCount  = 10,
                    RequestedLifetimeCount      = 30,
                    PublishingEnabled           = true
                };
                var subscriptionResponse = await channel.CreateSubscriptionAsync(subscriptionRequest);

                var id = subscriptionResponse.SubscriptionId;

                Console.WriteLine("Step 6 - Add items to the subscription.");
                var itemsToCreate = new MonitoredItemCreateRequest[]
                {
                    new MonitoredItemCreateRequest {
                        ItemToMonitor = new ReadValueId {
                            NodeId = NodeId.Parse("i=2258"), AttributeId = AttributeIds.Value
                        }, MonitoringMode = MonitoringMode.Reporting, RequestedParameters = new MonitoringParameters {
                            ClientHandle = 12345, SamplingInterval = -1, QueueSize = 0, DiscardOldest = true
                        }
                    }
                };
                var itemsRequest = new CreateMonitoredItemsRequest
                {
                    SubscriptionId = id,
                    ItemsToCreate  = itemsToCreate,
                };
                var itemsResponse = await channel.CreateMonitoredItemsAsync(itemsRequest);

                Console.WriteLine("Step 7 - Subscribe to PublishResponse stream.");
                var token = channel.Where(pr => pr.SubscriptionId == id).Subscribe(pr =>
                {
                    // loop thru all the data change notifications
                    var dcns = pr.NotificationMessage.NotificationData.OfType <DataChangeNotification>();
                    foreach (var dcn in dcns)
                    {
                        foreach (var min in dcn.MonitoredItems)
                        {
                            Console.WriteLine($"sub: {pr.SubscriptionId}; handle: {min.ClientHandle}; value: {min.Value}");
                        }
                    }
                });

                Console.WriteLine("Press any key to delete the subscription...");
                while (!Console.KeyAvailable)
                {
                    await Task.Delay(500);
                }

                Console.ReadKey(true);

                Console.WriteLine("Step 8 - Delete the subscription.");
                var request = new DeleteSubscriptionsRequest
                {
                    SubscriptionIds = new uint[] { id }
                };
                await channel.DeleteSubscriptionsAsync(request);

                token.Dispose();

                Console.WriteLine("Press any key to close the session...");
                Console.ReadKey(true);

                Console.WriteLine("Step 9 - Close the session.");
                await channel.CloseAsync();
            }
            catch (ServiceResultException ex)
            {
                if ((uint)ex.HResult == StatusCodes.BadSecurityChecksFailed)
                {
                    Console.WriteLine("Error connecting to endpoint. Did the server reject our certificate?");
                }

                await channel.AbortAsync();

                throw;
            }
        }
示例#6
0
        private static async Task TestAsync()
        {
            var discoveryUrl = "opc.tcp://*****:*****@"%LOCALAPPDATA%\Workstation.ConsoleApp\pki")),
                       userIdentity,
                       remoteEndpoint))
            {
                try
                {
                    await session.OpenAsync();
                }
                catch (ServiceResultException ex)
                {
                    if ((uint)ex.HResult == StatusCodes.BadSecurityChecksFailed)
                    {
                        Console.WriteLine("Error connecting to endpoint. Did the server reject our certificate?");
                    }

                    throw ex;
                }

                Console.WriteLine("Step 5 - Browse the server namespace.");
                Console.WriteLine("+ Root");
                BrowseRequest browseRequest = new BrowseRequest
                {
                    NodesToBrowse = new BrowseDescription[] { new BrowseDescription {
                                                                  NodeId = NodeId.Parse(ObjectIds.RootFolder), BrowseDirection = BrowseDirection.Forward, ReferenceTypeId = NodeId.Parse(ReferenceTypeIds.HierarchicalReferences), NodeClassMask = (uint)NodeClass.Variable | (uint)NodeClass.Object | (uint)NodeClass.Method, IncludeSubtypes = true, ResultMask = (uint)BrowseResultMask.All
                                                              } },
                };
                BrowseResponse browseResponse = await session.BrowseAsync(browseRequest);

                foreach (var rd1 in browseResponse.Results[0].References ?? new ReferenceDescription[0])
                {
                    Console.WriteLine("  + {0}: {1}, {2}", rd1.DisplayName, rd1.BrowseName, rd1.NodeClass);
                    browseRequest = new BrowseRequest
                    {
                        NodesToBrowse = new BrowseDescription[] { new BrowseDescription {
                                                                      NodeId = ExpandedNodeId.ToNodeId(rd1.NodeId, session.NamespaceUris), BrowseDirection = BrowseDirection.Forward, ReferenceTypeId = NodeId.Parse(ReferenceTypeIds.HierarchicalReferences), NodeClassMask = (uint)NodeClass.Variable | (uint)NodeClass.Object | (uint)NodeClass.Method, IncludeSubtypes = true, ResultMask = (uint)BrowseResultMask.All
                                                                  } },
                    };
                    browseResponse = await session.BrowseAsync(browseRequest);

                    foreach (var rd2 in browseResponse.Results[0].References ?? new ReferenceDescription[0])
                    {
                        Console.WriteLine("    + {0}: {1}, {2}", rd2.DisplayName, rd2.BrowseName, rd2.NodeClass);
                        browseRequest = new BrowseRequest
                        {
                            NodesToBrowse = new BrowseDescription[] { new BrowseDescription {
                                                                          NodeId = ExpandedNodeId.ToNodeId(rd2.NodeId, session.NamespaceUris), BrowseDirection = BrowseDirection.Forward, ReferenceTypeId = NodeId.Parse(ReferenceTypeIds.HierarchicalReferences), NodeClassMask = (uint)NodeClass.Variable | (uint)NodeClass.Object | (uint)NodeClass.Method, IncludeSubtypes = true, ResultMask = (uint)BrowseResultMask.All
                                                                      } },
                        };
                        browseResponse = await session.BrowseAsync(browseRequest);

                        foreach (var rd3 in browseResponse.Results[0].References ?? new ReferenceDescription[0])
                        {
                            Console.WriteLine("      + {0}: {1}, {2}", rd3.DisplayName, rd3.BrowseName, rd3.NodeClass);
                        }
                    }
                }

                Console.WriteLine("Press any key to continue...");
                Console.ReadKey(true);

                Console.WriteLine("Step 6 - Create a subscription.");
                var subscriptionRequest = new CreateSubscriptionRequest
                {
                    RequestedPublishingInterval = 1000,
                    RequestedMaxKeepAliveCount  = 10,
                    RequestedLifetimeCount      = 30,
                    PublishingEnabled           = true
                };
                var subscriptionResponse = await session.CreateSubscriptionAsync(subscriptionRequest).ConfigureAwait(false);

                var id = subscriptionResponse.SubscriptionId;

                Console.WriteLine("Step 7 - Add items to the subscription.");
                var itemsToCreate = new MonitoredItemCreateRequest[]
                {
                    new MonitoredItemCreateRequest {
                        ItemToMonitor = new ReadValueId {
                            NodeId = NodeId.Parse("i=2258"), AttributeId = AttributeIds.Value
                        }, MonitoringMode = MonitoringMode.Reporting, RequestedParameters = new MonitoringParameters {
                            ClientHandle = 12345, SamplingInterval = -1, QueueSize = 0, DiscardOldest = true
                        }
                    }
                };
                var itemsRequest = new CreateMonitoredItemsRequest
                {
                    SubscriptionId = id,
                    ItemsToCreate  = itemsToCreate,
                };
                var itemsResponse = await session.CreateMonitoredItemsAsync(itemsRequest).ConfigureAwait(false);

                Console.WriteLine("Step 8 - Publish the subscription.");
                var publishRequest = new PublishRequest
                {
                    SubscriptionAcknowledgements = new SubscriptionAcknowledgement[0]
                };
                Console.WriteLine("Press any key to delete the subscription...");
                while (!Console.KeyAvailable)
                {
                    var publishResponse = await session.PublishAsync(publishRequest).ConfigureAwait(false);

                    // loop thru all the data change notifications
                    var dcns = publishResponse.NotificationMessage.NotificationData.OfType <DataChangeNotification>();
                    foreach (var dcn in dcns)
                    {
                        foreach (var min in dcn.MonitoredItems)
                        {
                            Console.WriteLine($"clientHandle: {min.ClientHandle}; value: {min.Value}");
                        }
                    }

                    publishRequest = new PublishRequest
                    {
                        SubscriptionAcknowledgements = new[] { new SubscriptionAcknowledgement {
                                                                   SequenceNumber = publishResponse.NotificationMessage.SequenceNumber, SubscriptionId = publishResponse.SubscriptionId
                                                               } }
                    };
                }

                Console.ReadKey(true);

                Console.WriteLine("Step 9 - Delete the subscription.");
                var request = new DeleteSubscriptionsRequest
                {
                    SubscriptionIds = new uint[] { id }
                };
                await session.DeleteSubscriptionsAsync(request).ConfigureAwait(false);

                Console.WriteLine("Press any key to close the session...");
                Console.ReadKey(true);
                Console.WriteLine("Step 10 - Close the session.");
                await session.CloseAsync();
            }
        }
        /// <summary>
        /// Most important method - reading the tags.
        /// </summary>
        public async Task <List <Tag> > OPCReadAsync(string OPCAdress)
        {
            //Preparing data to connect to OPC server
            Tags = new List <Tag>();
            var loggerFactory = new LoggerFactory();

            var appDescription = new ApplicationDescription()
            {
                ApplicationName = "OPC",
                ApplicationUri  = $"urn:{System.Net.Dns.GetHostName()}:OPC",
                ApplicationType = ApplicationType.Client,
            };

            var certificateStore = new DirectoryStore(
                Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Workstation.ConsoleApp", "pki"));

            var channel = new UaTcpSessionChannel(
                appDescription,
                certificateStore,
                new AnonymousIdentity(), //by now doesn't support signing in
                OPCAdress,
                loggerFactory: loggerFactory);

            try
            {
                Stopwatch stopwatch = new Stopwatch(); //measuring operations time
                stopwatch.Start();

                await channel.OpenAsync(); //opening channel

                OnNewEvent(new LogEventArgs("Connected to OPC Server"));

                //opening OPC tree branches to find actual tags - only proper for B&R X20 PLC
                BrowseRequest browseRequest = new BrowseRequest {
                    NodesToBrowse = new BrowseDescription[] { new BrowseDescription {
                                                                  NodeId = NodeId.Parse(ObjectIds.RootFolder), BrowseDirection = BrowseDirection.Forward, ReferenceTypeId = NodeId.Parse(ReferenceTypeIds.HierarchicalReferences), NodeClassMask = (uint)NodeClass.Variable | (uint)NodeClass.Object | (uint)NodeClass.Method, IncludeSubtypes = true, ResultMask = (uint)BrowseResultMask.All
                                                              } },
                };
                BrowseResponse browseResponse = await channel.BrowseAsync(browseRequest);

                browseRequest = new BrowseRequest {
                    NodesToBrowse = new BrowseDescription[] { new BrowseDescription {
                                                                  NodeId = ExpandedNodeId.ToNodeId(browseResponse.Results[0].References[0].NodeId, channel.NamespaceUris), BrowseDirection = BrowseDirection.Forward, ReferenceTypeId = NodeId.Parse(ReferenceTypeIds.HierarchicalReferences), NodeClassMask = (uint)NodeClass.Variable | (uint)NodeClass.Object | (uint)NodeClass.Method, IncludeSubtypes = true, ResultMask = (uint)BrowseResultMask.All
                                                              } },
                };
                browseResponse = await channel.BrowseAsync(browseRequest);

                browseRequest = new BrowseRequest {
                    NodesToBrowse = new BrowseDescription[] { new BrowseDescription {
                                                                  NodeId = ExpandedNodeId.ToNodeId(browseResponse.Results[0].References[1].NodeId, channel.NamespaceUris), BrowseDirection = BrowseDirection.Forward, ReferenceTypeId = NodeId.Parse(ReferenceTypeIds.HierarchicalReferences), NodeClassMask = (uint)NodeClass.Variable | (uint)NodeClass.Object | (uint)NodeClass.Method, IncludeSubtypes = true, ResultMask = (uint)BrowseResultMask.All
                                                              } },
                };
                browseResponse = await channel.BrowseAsync(browseRequest);

                browseRequest = new BrowseRequest {
                    NodesToBrowse = new BrowseDescription[] { new BrowseDescription {
                                                                  NodeId = ExpandedNodeId.ToNodeId(browseResponse.Results[0].References[0].NodeId, channel.NamespaceUris), BrowseDirection = BrowseDirection.Forward, ReferenceTypeId = NodeId.Parse(ReferenceTypeIds.HierarchicalReferences), NodeClassMask = (uint)NodeClass.Variable | (uint)NodeClass.Object | (uint)NodeClass.Method, IncludeSubtypes = true, ResultMask = (uint)BrowseResultMask.All
                                                              } },
                };
                browseResponse = await channel.BrowseAsync(browseRequest);

                browseRequest = new BrowseRequest {
                    NodesToBrowse = new BrowseDescription[] { new BrowseDescription {
                                                                  NodeId = ExpandedNodeId.ToNodeId(browseResponse.Results[0].References[0].NodeId, channel.NamespaceUris), BrowseDirection = BrowseDirection.Forward, ReferenceTypeId = NodeId.Parse(ReferenceTypeIds.HierarchicalReferences), NodeClassMask = (uint)NodeClass.Variable | (uint)NodeClass.Object | (uint)NodeClass.Method, IncludeSubtypes = true, ResultMask = (uint)BrowseResultMask.All
                                                              } },
                };
                browseResponse = await channel.BrowseAsync(browseRequest);

                browseRequest = new BrowseRequest {
                    NodesToBrowse = new BrowseDescription[] { new BrowseDescription {
                                                                  NodeId = ExpandedNodeId.ToNodeId(browseResponse.Results[0].References[1].NodeId, channel.NamespaceUris), BrowseDirection = BrowseDirection.Forward, ReferenceTypeId = NodeId.Parse(ReferenceTypeIds.HierarchicalReferences), NodeClassMask = (uint)NodeClass.Variable | (uint)NodeClass.Object | (uint)NodeClass.Method, IncludeSubtypes = true, ResultMask = (uint)BrowseResultMask.All
                                                              } },
                };
                browseResponse = await channel.BrowseAsync(browseRequest);

                browseRequest = new BrowseRequest {
                    NodesToBrowse = new BrowseDescription[] { new BrowseDescription {
                                                                  NodeId = ExpandedNodeId.ToNodeId(browseResponse.Results[0].References[10].NodeId, channel.NamespaceUris), BrowseDirection = BrowseDirection.Forward, ReferenceTypeId = NodeId.Parse(ReferenceTypeIds.HierarchicalReferences), NodeClassMask = (uint)NodeClass.Variable | (uint)NodeClass.Object | (uint)NodeClass.Method, IncludeSubtypes = true, ResultMask = (uint)BrowseResultMask.All
                                                              } },
                };
                BrowseResponse browseResponse0 = await channel.BrowseAsync(browseRequest);

                int nestingLevel = 0;                                                       //nesting level counter
                Tag tag          = new Tag();                                               //initializing first tag
                int allTagsCount = browseResponse0.Results[0].References.Length - 1;        //for counting progress percentage

                for (int i = browseResponse0.Results[0].References.Length - 1; i >= 0; i--) //first level loop
                {
                    var rd = browseResponse0.Results[0].References[i];
                    if (Tags.Count > 0 && rd.DisplayName.ToString() == Tags[0].Name)
                    {
                        break;
                    }                                                                           //to avoid getting the same tags second time

                    nestingLevel = 0;
                    ReadValueId[] items = new ReadValueId[1];
                    items[0] = new ReadValueId {
                        NodeId = NodeId.Parse(rd.NodeId.ToString()), AttributeId = AttributeIds.DataType
                    };
                    ReadRequest readRequest = new ReadRequest {
                        NodesToRead = items
                    };
                    ReadResponse readResponse = await channel.ReadAsync(readRequest);


                    if (string.IsNullOrEmpty(tag.Name))
                    {
                        tag = new Tag(rd.DisplayName.ToString());
                    }


                    if (readResponse.Results[0].Value != null)
                    {
                        tag.ConversionFunction = Typ(readResponse.Results[0].Value.ToString());
                    }

                    browseRequest = new BrowseRequest {
                        NodesToBrowse = new BrowseDescription[] { new BrowseDescription {
                                                                      NodeId = ExpandedNodeId.ToNodeId(rd.NodeId, channel.NamespaceUris), BrowseDirection = BrowseDirection.Forward, ReferenceTypeId = NodeId.Parse(ReferenceTypeIds.HierarchicalReferences), NodeClassMask = (uint)NodeClass.Variable | (uint)NodeClass.Object | (uint)NodeClass.Method, IncludeSubtypes = true, ResultMask = (uint)BrowseResultMask.All
                                                                  } },
                    };
                    browseResponse = await channel.BrowseAsync(browseRequest);

                    foreach (var rd1 in browseResponse.Results[0].References ?? new ReferenceDescription[0]) //second level loop (nesting=1)
                    {
                        if (!rd1.NodeId.ToString().Contains("#"))
                        {
                            nestingLevel = 1;
                            tag          = await ReadTag(new ReferenceDescription[] { rd, rd1 }, channel, tag);

                            browseRequest = new BrowseRequest {
                                NodesToBrowse = new BrowseDescription[] { new BrowseDescription {
                                                                              NodeId = ExpandedNodeId.ToNodeId(rd1.NodeId, channel.NamespaceUris), BrowseDirection = BrowseDirection.Forward, ReferenceTypeId = NodeId.Parse(ReferenceTypeIds.HierarchicalReferences), NodeClassMask = (uint)NodeClass.Variable | (uint)NodeClass.Object | (uint)NodeClass.Method, IncludeSubtypes = true, ResultMask = (uint)BrowseResultMask.All
                                                                          } },
                            };
                            browseResponse = await channel.BrowseAsync(browseRequest);

                            foreach (var rd2 in browseResponse.Results[0].References ?? new ReferenceDescription[0]) //third level loop (nesting=2)
                            {
                                if (!rd2.NodeId.ToString().Contains("#"))
                                {
                                    nestingLevel = 2;
                                    tag          = await ReadTag(new ReferenceDescription[] { rd, rd1, rd2 }, channel, tag);

                                    browseRequest = new BrowseRequest {
                                        NodesToBrowse = new BrowseDescription[] { new BrowseDescription {
                                                                                      NodeId = ExpandedNodeId.ToNodeId(rd2.NodeId, channel.NamespaceUris), BrowseDirection = BrowseDirection.Forward, ReferenceTypeId = NodeId.Parse(ReferenceTypeIds.HierarchicalReferences), NodeClassMask = (uint)NodeClass.Variable | (uint)NodeClass.Object | (uint)NodeClass.Method, IncludeSubtypes = true, ResultMask = (uint)BrowseResultMask.All
                                                                                  } },
                                    };
                                    browseResponse = await channel.BrowseAsync(browseRequest);

                                    foreach (var rd3 in browseResponse.Results[0].References ?? new ReferenceDescription[0]) //fourth level loop (nesting=3)
                                    {
                                        if (!rd3.NodeId.ToString().Contains("#"))
                                        {
                                            nestingLevel = 3;
                                            tag          = await ReadTag(new ReferenceDescription[] { rd, rd1, rd2, rd3 }, channel, tag);
                                        }
                                        else if (rd3.NodeId.ToString().Contains("#EngineeringUnits"))
                                        {
                                            await ReadUnit(new ReferenceDescription[] { rd, rd1, rd2, rd3 }, channel, tag);
                                        }

                                        if (nestingLevel == 3 && !string.IsNullOrEmpty(tag.Name))
                                        {
                                            tag = SaveTag(tag);
                                        }
                                    }
                                }
                                else if (rd2.NodeId.ToString().Contains("#EngineeringUnits"))
                                {
                                    await ReadUnit(new ReferenceDescription[] { rd, rd1, rd2 }, channel, tag);
                                }


                                if (nestingLevel == 2 && !string.IsNullOrEmpty(tag.Name))
                                {
                                    tag = SaveTag(tag);
                                }
                            }
                        }

                        else if (rd1.NodeId.ToString().Contains("#EngineeringUnits"))
                        {
                            await ReadUnit(new ReferenceDescription[] { rd, rd1 }, channel, tag);
                        }


                        if (nestingLevel == 1 && !string.IsNullOrEmpty(tag.Name))
                        {
                            tag = SaveTag(tag);
                        }
                    }
                    if (nestingLevel == 0 && !string.IsNullOrEmpty(tag.Name))
                    {
                        tag = SaveTag(tag);
                    }

                    OnProgressChanged(new ProgressChangedArgs((allTagsCount - i) * 100 / allTagsCount)); //computing progress percentage
                }


                await channel.CloseAsync(); //closing the channel

                stopwatch.Stop();

                OnNewEvent(new LogEventArgs(Tags.Count + " tags read, time elapsed: " + stopwatch.Elapsed.TotalSeconds.ToString("F3") + " s"));
            }
            catch (Exception ex)
            {
                OnNewEvent(new LogEventArgs("Error connecting to OPC server."));
                await channel.AbortAsync();
            }

            return(Tags);
        }
        public async Task BrowseObjectFolder()
        {
            // describe this client application.
            var clientDescription = new ApplicationDescription
            {
                ApplicationName = "Workstation.UaClient.FeatureTests",
                ApplicationUri  = $"urn:{System.Net.Dns.GetHostName()}:Workstation.UaClient.FeatureTests",
                ApplicationType = ApplicationType.Client
            };

            // place to store certificates
            var certificateStore = new DirectoryStore("./pki");

            // create a 'UaTcpSessionChannel', a client-side channel that opens a 'session' with the server.
            var channel = new UaTcpSessionChannel(
                clientDescription,
                certificateStore,
                new AnonymousIdentity(),
                "opc.tcp://localhost:48010"); // the endpoint of Unified Automation's UaCPPServer.

            try
            {
                // try opening a session and reading a few nodes.
                await channel.OpenAsync();

                Console.WriteLine($"Opened session with endpoint '{channel.RemoteEndpoint.EndpointUrl}'.");
                Console.WriteLine($"SecurityPolicy: '{channel.RemoteEndpoint.SecurityPolicyUri}'.");
                Console.WriteLine($"SecurityMode: '{channel.RemoteEndpoint.SecurityMode}'.");
                Console.WriteLine($"UserIdentityToken: '{channel.UserIdentity}'.");

                // build a BrowseRequest. See 'OPC UA Spec Part 4' section 5.8.2
                var browseRequest = new BrowseRequest
                {
                    NodesToBrowse = new[] {
                        new BrowseDescription {
                            // gather references of this nodeid.
                            NodeId = NodeId.Parse(ObjectIds.ObjectsFolder),
                            // include just 'Forward' references
                            BrowseDirection = BrowseDirection.Forward,
                            // include 'HierarchicalReferences'
                            ReferenceTypeId = NodeId.Parse(ReferenceTypeIds.HierarchicalReferences),
                            // include 'HierarchicalReferences' and all subtypes of 'HierarchicalReferences'
                            IncludeSubtypes = true,
                            // include all classes of node
                            NodeClassMask = (uint)NodeClass.Unspecified,
                            // return reference descriptions with all the fields filled out
                            ResultMask = (uint)BrowseResultMask.All,
                        }
                    },
                    RequestedMaxReferencesPerNode = 1000
                };

                // send the request to the server
                var browseResponse = await channel.BrowseAsync(browseRequest).ConfigureAwait(false);

                Console.WriteLine("\n+ Objects, 0:Objects, Object, i=85");

                Assert.IsNotNull(browseResponse.Results[0].References);
                foreach (var rd in browseResponse.Results[0].References)
                {
                    Console.WriteLine("   + {0}, {1}, {2}, {3}", rd.DisplayName, rd.BrowseName, rd.NodeClass, rd.NodeId);
                }

                // it is good practice to be prepared to receive a continuationPoint.
                // ContinuationPoints are returned when the server has more information
                // than can be delivered in current response.
                // To test this code, you can reduce the above RequestedMaxReferencesPerNode
                // to 1.
                var cp = browseResponse.Results[0].ContinuationPoint;
                while (cp != null)
                {
                    var browseNextRequest = new BrowseNextRequest {
                        ContinuationPoints = new[] { cp }, ReleaseContinuationPoints = false
                    };
                    var browseNextResponse = await channel.BrowseNextAsync(browseNextRequest);

                    Assert.IsNotNull(browseNextResponse.Results[0].References);
                    foreach (var rd in browseNextResponse.Results[0].References)
                    {
                        Console.WriteLine("   + {0}, {1}, {2}", rd.DisplayName, rd.BrowseName, rd.NodeClass);
                    }
                    cp = browseNextResponse.Results[0].ContinuationPoint;
                }

                Console.WriteLine($"\nClosing session '{channel.SessionId}'.");
                await channel.CloseAsync();
            }
            catch (Exception ex)
            {
                await channel.AbortAsync();

                Console.WriteLine(ex.Message);
            }
        }