I need to create a simple OPS UA client. I found a suitable example and changed it a bit. Here is the resulting code:
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;
}
}
}
}
This works great for getting the values of known tags. In this example, I get the values of two tags known to me: FileData and FileData2. But what should I do if I don't know the names of tags or groups in advance? Please give me an example that lists all server groups and all group tags in the console. Is this possible with namespaces already included or do I need something else?
It seems I have found a solution. All groups and tags can be obtained when creating a session.
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);
}
}
}