Как получить список всех тегов и групп от OPC UA сервера?

Мне необходимо создать свой OPC UA клиент. Я нашёл неплохой пример, немного модифицировал и всё заработало. Вот этот пример:

using System;
using System.Threading;
using System.Collections.Generic;
using Opc.Ua.Client;
using Opc.Ua;
using Opc.Ua.Configuration;
 
namespace FerstProject
{
    class MainClass
    {
        static OPCUAClass myOPCUAServer;
        static Dictionary<String, OPCUAClass.TagClass> TagList = new Dictionary<String, OPCUAClass.TagClass>();
 
        public static void Main(string[] args)
        {
            Console.WriteLine("Start");
 
            TagList.Add("Value 1", new OPCUAClass.TagClass("Number 1", "FileValue.FileData"));
            TagList.Add("Value 2", new OPCUAClass.TagClass("Number 2", "FileValue.FileData2"));
 
            myOPCUAServer = new OPCUAClass("127.0.0.1", "8666", TagList, true, 1, "2");
        }
 
        public class OPCUAClass
        {
            public string ServerAddress { get; set; }
            public string ServerPortNumber { get; set; }
            public bool SecurityEnabled { get; set; }
            public string MyApplicationName { get; set; }
            public Session OPCSession { get; set; }
            public string OPCNameSpace { get; set; }
            public Dictionary<string, TagClass> TagList { get; set; }
 
            public bool SessionRenewalRequired { get; set; }
            public double SessionRenewalPeriodMins { get; set; }
            public DateTime LastTimeSessionRenewed { get; set; }
            public DateTime LastTimeOPCServerFoundAlive { get; set; }
            public bool ClassDisposing { get; set; }
            public bool InitialisationCompleted { get; set; }
            private Thread RenewerTHread { get; set; }
            public OPCUAClass(string serverAddres, string serverport, Dictionary<string, TagClass> taglist, bool sessionrenewalRequired, double sessionRenewalMinutes, string nameSpace)
            {
                ServerAddress = serverAddres;
                ServerPortNumber = serverport;
                MyApplicationName = "MyApplication";
                TagList = taglist;
                SessionRenewalRequired = sessionrenewalRequired;
                SessionRenewalPeriodMins = sessionRenewalMinutes;
                OPCNameSpace = nameSpace;
                LastTimeOPCServerFoundAlive = DateTime.Now;
                InitializeOPCUAClient();
 
                if (SessionRenewalRequired)
                {
                    LastTimeSessionRenewed = DateTime.Now;
                    RenewerTHread = new Thread(renewSessionThread);
                    RenewerTHread.Start();
                }
            }
 
            OPCUAClass()
            {
                ClassDisposing = true;
                try
                {
                    OPCSession.Close();
                    OPCSession.Dispose();
                    OPCSession = null;
                    RenewerTHread.Abort();
                }
                catch { }
            }
 
            private void renewSessionThread()
            {
                while (!ClassDisposing)
                {
                    if ((DateTime.Now - LastTimeSessionRenewed).TotalMinutes > SessionRenewalPeriodMins
                        || (DateTime.Now - LastTimeOPCServerFoundAlive).TotalSeconds > 60)
                    {
                        Console.WriteLine("Renewing Session");
                        try
                        {
                            OPCSession.Close();
                            OPCSession.Dispose();
                        }
                        catch { }
                        InitializeOPCUAClient();
                        LastTimeSessionRenewed = DateTime.Now;
                    }
                    Thread.Sleep(2000);
                }
            }
 
            public void InitializeOPCUAClient()
            {
                var config = new ApplicationConfiguration()
                {
                    ApplicationName = MyApplicationName,
                    ApplicationUri = Utils.Format(@"urn:{0}:" + MyApplicationName + "", ServerAddress),
                    ApplicationType = ApplicationType.Client,
                    SecurityConfiguration = new SecurityConfiguration
                    {
                        ApplicationCertificate = new CertificateIdentifier { StoreType = @"Directory", StorePath = @"%CommonApplicationData%\OPC Foundation\CertificateStores\MachineDefault", SubjectName = Utils.Format(@"CN={0}, DC={1}", MyApplicationName, ServerAddress) },
                        TrustedIssuerCertificates = new CertificateTrustList { StoreType = @"Directory", StorePath = @"%CommonApplicationData%\OPC Foundation\CertificateStores\UA Certificate Authorities" },
                        TrustedPeerCertificates = new CertificateTrustList { StoreType = @"Directory", StorePath = @"%CommonApplicationData%\OPC Foundation\CertificateStores\UA Applications" },
                        RejectedCertificateStore = new CertificateTrustList { StoreType = @"Directory", StorePath = @"%CommonApplicationData%\OPC Foundation\CertificateStores\RejectedCertificates" },
                        AutoAcceptUntrustedCertificates = true,
                        AddAppCertToTrustedStore = true
                    },
                    TransportConfigurations = new TransportConfigurationCollection(),
                    TransportQuotas = new TransportQuotas { OperationTimeout = 15000 },
                    ClientConfiguration = new ClientConfiguration { DefaultSessionTimeout = 60000 },
                    TraceConfiguration = new TraceConfiguration()
                };
                config.Validate(ApplicationType.Client).GetAwaiter().GetResult();
                if (config.SecurityConfiguration.AutoAcceptUntrustedCertificates)
                {
                    config.CertificateValidator.CertificateValidation += (s, e) => { e.Accept = (e.Error.StatusCode == StatusCodes.BadCertificateUntrusted); };
                }
                var application = new ApplicationInstance
                {
                    ApplicationName = MyApplicationName,
                    ApplicationType = ApplicationType.Client,
                    ApplicationConfiguration = config
                };
 
                string serverAddress = ServerAddress;
                var selectedEndpoint = CoreClientUtils.SelectEndpoint("opc.tcp://" + serverAddress + ":" + ServerPortNumber + "", true, 15000);
 
                OPCSession = Session.Create(config, new ConfiguredEndpoint(null, selectedEndpoint, EndpointConfiguration.Create(config)), false, "", 60000, null, null).GetAwaiter().GetResult();
                {
                    var subscription = new Subscription(OPCSession.DefaultSubscription) { PublishingInterval = 1000 };
                    var list = new List<MonitoredItem> { };
 
                    foreach (KeyValuePair<string, TagClass> td in TagList)
                    {
                        MonitoredItem monitoredItem = new MonitoredItem();
                        monitoredItem.DisplayName = td.Value.DisplayName;
                        monitoredItem.StartNodeId = "ns=" + OPCNameSpace + ";s=" + td.Value.NodeID + "";
                        list.Add(monitoredItem);
                    }
 
                    for (int i=0; i<list.Count; i++)
                        list[i].Notification += OnTagValueChange;
 
                    subscription.AddItems(list);
                    OPCSession.AddSubscription(subscription);
                    subscription.Create();
                }
            }
 
            public class TagClass
            {
                public TagClass(string displayName, string nodeID)
                {
                    DisplayName = displayName;
                    NodeID = nodeID;
                }
 
                public DateTime LastUpdatedTime { get; set; }
                public DateTime LastSourceTimeStamp { get; set; }
                public string StatusCode { get; set; }
                public string LastGoodValue { get; set; }
                public string CurrentValue { get; set; }
                public string NodeID { get; set; }
                public string DisplayName { get; set; }
            }
 
            public void OnTagValueChange(MonitoredItem item, MonitoredItemNotificationEventArgs e)
            {
                foreach (var value in item.DequeueValues())
                {
                    if (item.DisplayName == "ServerStatusCurrentTime")
                        LastTimeOPCServerFoundAlive = value.SourceTimestamp.ToLocalTime();
                    else
                    {
                        if (value.Value != null)
                            Console.WriteLine("{0}: {1}, {2}, {3}", item.DisplayName, value.Value.ToString(), value.SourceTimestamp.ToLocalTime(), value.StatusCode);
                        else
                            Console.WriteLine("{0}: {1}, {2}, {3}", item.DisplayName, "Null Value", value.SourceTimestamp, value.StatusCode);
 
                        if (TagList.ContainsKey(item.DisplayName))
                        {
                            if (value.Value != null)
                            {
                                TagList[item.DisplayName].LastGoodValue = value.Value.ToString();
                                TagList[item.DisplayName].CurrentValue = value.Value.ToString();
                                TagList[item.DisplayName].LastUpdatedTime = DateTime.Now;
                                TagList[item.DisplayName].LastSourceTimeStamp = value.SourceTimestamp.ToLocalTime();
                                TagList[item.DisplayName].StatusCode = value.StatusCode.ToString();
                            }
                            else
                            {
                                TagList[item.DisplayName].StatusCode = value.StatusCode.ToString();
                                TagList[item.DisplayName].CurrentValue = null;
                            }
                        }
                    }
                }
                InitialisationCompleted = true;
            }
        }
    }
}

Обращаю внимание, что здесь происходит получение значений конкретных тегов: FileValue.FileData и FileValue.FileData2. Но что делать если мне надо получить список всех тегов? Или даже список групп? Это определённо возможно, но как - не могу понять. Пожалуйста, дайте пример.


Ответы (1 шт):

Автор решения: FaceHoof

Кажется, я нашёл решение. Все группы и теги можно получить при создании сессии следующим образом:

OPCSession = Session.Create(config, new ConfiguredEndpoint(null, selectedEndpoint, EndpointConfiguration.Create(config)), false, "", 60000, null, null).GetAwaiter().GetResult();
            {
                ReferenceDescriptionCollection RDC;
                Byte[] ArrBytes;
                OPCSession.Browse(null, null, ObjectIds.ObjectsFolder, 0u, BrowseDirection.Forward, ReferenceTypeIds.HierarchicalReferences, true, (uint)NodeClass.Variable | (uint)NodeClass.Object | (uint)NodeClass.Method, out ArrBytes, out RDC);
                foreach (var RD in RDC)
                {
                    Console.WriteLine("DisplayName: " + RD.DisplayName + " BrowseName: " + RD.BrowseName + " NodeClass: " + RD.NodeClass);

                    ReferenceDescriptionCollection NewRDC;
                    byte[] NewArrBytes;
                    OPCSession.Browse(null, null, ExpandedNodeId.ToNodeId(RD.NodeId, OPCSession.NamespaceUris), 0u, BrowseDirection.Forward, ReferenceTypeIds.HierarchicalReferences, true, (uint)NodeClass.Variable | (uint)NodeClass.Object | (uint)NodeClass.Method, out NewArrBytes, out NewRDC);
                    foreach (var newRD in NewRDC)
                    {
                        Console.WriteLine("NEW - DisplayName: " + newRD.DisplayName + " BrowseName: " + newRD.BrowseName + " NodeClass: " + newRD.NodeClass);
                    }
                }
            }
→ Ссылка