First steps PLCcom.Opc.Ua.Sdk for .Net
Important note
With the PLCcom.Opc.Ua.Sdk you or the user will be able to monitor and control systems, machines or similar at your own discretion. For this purpose the user has to have the needed knowledge or activity.
Before the resulting work can be applied to the plant, machine or similar, the creator of a project must test all functions and check for function and interactions with the system, machine or similar. These tests are to be repeated after every software change and after every change to the system, machine or similar or the periphery (network, server, etc.).
If malfunctions occur or are detected, the PLCcom.Opc.Ua.Sdk must not be operated at the plant, machine or similar.
What is Opc.Ua?
With the Opc Ua specification, the OPC Foundation provides a newly developed communication model for the uniform transport of machine data.
The goal was to adapt the OPC communication model to the requirements of future applications and to compensate for the existing disadvantages of the DCOM-based OPC interface.
The Opc Ua communication model is a complete new development, differs considerably from its predecessor and is also not based on the DCOM interface.
The first version of the Opc Ua specification was made available in 2006, a revision took place in 2009. With Opc Ua, a future-proof standardized communication standard is provided
that also covers the requirements of industry 4.0 applications.
Which developing plattforms supports PLCcom.Opc.Ua.Sdk?
The PLCcom.Opc.Ua.Sdk is a .net library released in two formats />
- .net Standard 2.1
- .net 6.0
- .net 7.0
- .net 8.0
- .net Framework 4.7.2
- .net Framework 4.8
- .net Framework 4.8.1
Which this library you can write your own software with following platforms:
- .net Standard 2.1 or higher
- .net Framework 4.7.2 or higher
- .net 6.0 higher
- .net 7.0 higher
- .net 8.0 higher
Source: https://docs.microsoft.com/en-us/dotnet/standard/net-standard
Included in the software package are extensive code examples and tutorials, which illustrate the easy connection of an Opc Ua server via an
OPC interface to your application and can also be used in your projects. For development support,
test server and client applications are included in the delivery package.
What PLCcom.Opc.Ua.Sdk has to offer?
The PLCcom.Opc.Ua.Sdk is a highly optimized and modern component specially developed for .NET software developers to provide a convenient access to a client-side Opc Ua interface, e.g. To read or write data.
Depending on the version, the libraries are 100% .Net files. The component can be directly linked as a reference, API calls are not necessary. It is easily to use the components in 32 or 64 bit environments as well as across platforms.
The internal routines are optimized for high-performance access.
With the PLCcom.Opc.Ua.Sdk, you can create applications that support the most common OPC specifications.
These includes:
- DataAccess (most used)
- Alarm and Conditions
- Historical Data
- Historical Events
Included in the software package are extensive code examples and tutorials, which illustrate the easy connection of an Opc Ua server via an
OPC interface to your application and can also be used in your projects. For development support,
test server and client applications are included in the delivery package.
Which advantages provide PLCcom.Opc.Ua.Sdk?
With the Sdk, .Net developers are able to add a standardized Opc.Ua client access to
their developed applications with a few lines of code, thereby accessing existing Opc Ua server instances.
During the development of the Sdk, the focus has been placed on the possibility of rapid learning and using. For this reason,
simple pre-configured commands have been provided for most functionalities.
The addressing of the OPC nodes can also be carried out as a string in the Sdk via the browse name.
The complex finding of the NodeIDs leads the PLCcom.Opc.Ua.Sdk for you in the
background, e.g. "Objects.Data.Static.Scalar.Int64Value"
Here are some examples to illustrate the simple implementation of Opc Ua functions.
Example Queries of existing endpoints of a server
EndpointDescriptionCollection endpoints = UaClient.GetEndpoints(new Uri("opc.tcp://localhost:50520/UA/DataAccessServer"));
Dim endpoints As EndpointDescriptionCollection = UaClient.GetEndpoints(New Uri("opc.tcp://localhost:50520/UA/DataAccessServer"))
Example read a variable by path
ReadValueIdCollection nodesToRead = new ReadValueIdCollection();
ReadValueId nodeToRead = new ReadValueId();
nodeToRead.NodeId = client.GetNodeIdByPath("Objects.Data.Static.Scalar.Int16Value");
nodeToRead.AttributeId = Attributes.Value;
nodesToRead.Add(nodeToRead);
DataValueCollection readresults = client.Read(nodesToRead);
Dim nodesToRead As ReadValueIdCollection = New ReadValueIdCollection()
Dim nodeToRead As ReadValueId = New ReadValueId()
nodeToRead.NodeId = client.GetNodeIdByPath("Objects.Data.Static.Scalar.Int16Value")
nodeToRead.AttributeId = Attributes.Value
nodesToRead.Add(nodeToRead)
Dim readresults As DataValueCollection = client.Read(nodesToRead)
Example read a variable by nodeId
ReadValueIdCollection nodesToRead = new ReadValueIdCollection();
ReadValueId nodeToRead = new ReadValueId();
nodeToRead.NodeId = nodeToRead.NodeId = new NodeId("ns=2;i=10223");
nodeToRead.AttributeId = Attributes.Value;
nodesToRead.Add(nodeToRead);
DataValueCollection readresults = client.Read(nodesToRead);
Dim nodesToRead As ReadValueIdCollection = New ReadValueIdCollection()
Dim nodeToRead As ReadValueId = New ReadValueId()
nodeToRead.NodeId = = New NodeId("ns=2;i=10223")
nodeToRead.AttributeId = Attributes.Value
nodesToRead.Add(nodeToRead)
Dim readresults As DataValueCollection = client.Read(nodesToRead)
Example monitor a variable
using (Subscription subscription = new Subscription())
{
subscription.PublishingInterval = 1000;
subscription.PublishingEnabled = false;
subscription.DisplayName = "mySubsription";
subscription.StateChanged += Subscription_StateChanged;
subscription.PublishStatusChanged += Subscription_PublishStatusChanged;
client.AddSubscription(subscription);
NodeId nodeId = client.GetNodeIdByPath("Objects.Data.Dynamic.Scalar.Int64Value");
MonitoredItem monitoredItem = new MonitoredItem(subscription.DefaultItem)
{
StartNodeId = nodeId,
SamplingInterval = 500,
QueueSize = UInt32.MaxValue,
DisplayName = nodeId.ToString()
};
monitoredItem.Notification += Client_MonitorNotification;
subscription.AddItem(monitoredItem);
nodeId = client.GetNodeIdByPath("Objects.Data.Dynamic.Scalar.BooleanValue");
monitoredItem = new MonitoredItem(subscription.DefaultItem)
{
StartNodeId = nodeId,
SamplingInterval = 500,
QueueSize = UInt32.MaxValue,
DisplayName = nodeId.ToString()
};
monitoredItem.Notification += Client_MonitorNotification;
subscription.AddItem(monitoredItem);
subscription.ApplyChanges();
subscription.SetPublishingMode(true);
subscription.Modify();
}
private void Client_MonitorNotification(MonitoredItem monitoredItem, MonitoredItemNotificationEventArgs e)
{
MonitoredItemNotification notification = e.NotificationValue as MonitoredItemNotification;
Console.WriteLine(monitoredItem.StartNodeId.Identifier + " Value: " + notification.Value + " Status: " + notification.Value.StatusCode.ToString());
}
Using subscription As Subscription = New Subscription()
subscription.PublishingInterval = 1000
subscription.PublishingEnabled = False
subscription.DisplayName = "mySubsription"
AddHandler subscription.StateChanged, AddressOf Subscription_StateChanged
AddHandler subscription.PublishStatusChanged, AddressOf Subscription_PublishStatusChanged
client.AddSubscription(subscription)
Dim nodeId As NodeId = client.GetNodeIdByPath("Objects.Data.Dynamic.Scalar.Int64Value")
Dim monitoredItem As MonitoredItem = New MonitoredItem(subscription.DefaultItem) With {
.StartNodeId = nodeId,
.SamplingInterval = 500,
.QueueSize = UInteger.MaxValue,
.DisplayName = nodeId.ToString()
}
AddHandler monitoredItem.Notification, AddressOf Client_MonitorNotification
subscription.AddItem(monitoredItem)
nodeId = client.GetNodeIdByPath("Objects.Data.Dynamic.Scalar.BooleanValue")
monitoredItem = New MonitoredItem(subscription.DefaultItem) With {
.StartNodeId = nodeId,
.SamplingInterval = 500,
.QueueSize = UInteger.MaxValue,
.DisplayName = nodeId.ToString()
}
AddHandler monitoredItem.Notification, AddressOf Client_MonitorNotification
subscription.AddItem(monitoredItem)
subscription.ApplyChanges()
subscription.SetPublishingMode(True)
subscription.Modify()
End Using
Private Sub Client_MonitorNotification(ByVal monitoredItem As MonitoredItem, ByVal e As MonitoredItemNotificationEventArgs)
Dim notification As MonitoredItemNotification = TryCast(e.NotificationValue, MonitoredItemNotification)
Console.WriteLine($"{monitoredItem.StartNodeId.Identifier} Value: {notification.Value} Status: {notification.Value.StatusCode.ToString()}")
End Sub
Further advantages:
• Easy to use, many functions can be called by a single line of code
• At default, automatic Connect, Reconnect, and Disconnect functionality, the connection state does not need to be monitored by the developer
• The server state is tracked by active keep-alive monitoring
• Extensive tutorials for a quick introduction to the .Net languages C# and Visual Basic in the delivery package
• For the fast familiarization and tests, the example OPC server and OPC clients are installed
System requirements for creating applications with PLCcom.Opc.Ua.Sdk?
To create applications with the Sdk, advanced programming skills in a .Net programming language are advantageously
required with C # or Visual Basic.
The following system components are also required for the operation of the PLCcom.Opc.Ua.Sdk:
-
Microsoft .net Framework 4.7.2 or higher,
Microsoft .net Core 3.1 or higher
Microsoft .net Standard 2.1 or higher
To execute the included examples you need to have-
Visual Studio 2017 or higher
How do I submit the licensing information?
The PLCcom.Opc.Ua.Sdk must be enabled by entering license information. This license information has been sent
to you either after purchase or by sending a 30 day demo key.
The licensing information is passed during the creation of a client instance.
UaClient client = new UaClient("[Enter your UserName here]",
"[Enter your Serial here]",
sessionConfiguration);
Dim UaClient As New UaClient("[Enter your UserName here]",
"[Enter your Serial here]",
sessionConfiguration)
How to use the Discovery functionality?
The communication between the UA client and the UA server is carried out via so-called endpoints,
which are made available by the respective Opc Ua server.
To create a client-side connection, either the endpoint information of the Opc Ua server must
be known, or this information can be determined using the discovery functions of the PLCcom.Opc.Ua.Sdk.
The determination can be carried out in two ways:
1. Via a configured server-side Opc Ua Discovery server or
2. Discovery of the target server if at least one port provided is known
EndpointDescriptionCollection Endpoints = UaClient.GetEndpoints(new Uri("opc.tcp://localhost:50520/PLCcom/DataAccessServer"));
Dim Endpoints As EndpointDescriptionCollection = UaClient.GetEndpoints(New Uri("opc.tcp://localhost:50520/PLCcom/DataAccessServer"))
How to create a new client instance?
To create a new client instance, a session configuration has to created and parameterized first.
For a simple session configuration the transfer of the server endpoint is sufficient.
EndpointDescriptionCollection Endpoints = UaClient.GetEndpoints(new Uri("opc.tcp://localhost:50520/PLCcom/DataAccessServer"));
SessionConfiguration sessionConfiguration = SessionConfiguration.Build(System.Reflection.Assembly.GetEntryAssembly().GetName().Name,Endpoints[0]);
Dim Endpoints As EndpointDescriptionCollection = UaClient.GetEndpoints(New Uri("opc.tcp://localhost:50520/PLCcom/DataAccessServer"))
Dim sessionConfiguration As SessionConfiguration = SessionConfiguration.Build(Assembly.GetEntryAssembly().GetName().Name, Endpoints(0))
The second step is to create the client instance and pass the session configuration object:
UaClient client = new UaClient("[Enter your UserName here]",
"[Enter your Serial here]",
sessionConfiguration);
Dim UaClient As New UaClient("[Enter your UserName here]",
"[Enter your Serial here]",
sessionConfiguration)
Events can be registered to monitor the session:
client.ServerConnectionLost += Client_ServerConnectionLost;
client.ServerConnected += Client_ServerConnected;
client.KeepAlive += Client_KeepAlive;
client.CertificateValidation += client_CertificateValidation;
void client_CertificateValidation(CertificateValidator sender, CertificateValidationEventArgs e)
{
if (ServiceResult.IsGood(e.Error))
e.Accept = true;
else if ((e.Error.StatusCode.Code == StatusCodes.BadCertificateUntrusted || e.Error.StatusCode.Code == StatusCodes.BadCertificateChainIncomplete) && autoAcceptUntrustedCertificates)
e.Accept = true;
else
{
throw new Exception(string.Format("Failed to validate certificate with error code {0}: {1}", e.Error.Code, e.Error.AdditionalInfo));
}
}
private void Client_ServerConnected(object sender, EventArgs e)
{
Console.WriteLine(DateTime.Now.ToLocalTime() + " Session connected");
}
private void Client_ServerConnectionLost(object sender, EventArgs e)
{
Console.WriteLine(DateTime.Now.ToLocalTime() + " Session connection lost");
}
void Client_KeepAlive(Session session, KeepAliveEventArgs e)
{
}
AddHandler client.ServerConnectionLost, AddressOf Client_ServerConnectionLost
AddHandler client.ServerConnected, AddressOf Client_ServerConnected
AddHandler client.KeepAlive, AddressOf Client_KeepAlive
AddHandler client.CertificateValidation, AddressOf client_CertificateValidation
Private Sub client_CertificateValidation(ByVal sender As CertificateValidator, ByVal e As CertificateValidationEventArgs)
If ServiceResult.IsGood(e.Error) Then
e.Accept = True
ElseIf (e.Error.StatusCode.Code = StatusCodes.BadCertificateUntrusted OrElse e.Error.StatusCode.Code = StatusCodes.BadCertificateChainIncomplete) AndAlso autoAcceptUntrustedCertificates Then
e.Accept = True
Else
Throw New Exception($"Failed to validate certificate with error code {e.Error.Code}: {e.Error.AdditionalInfo}")
End If
End Sub
Private Sub Client_ServerConnected(ByVal sender As Object, ByVal e As EventArgs)
Console.WriteLine($"{Date.Now.ToLocalTime()} Session connected")
End Sub
Private Sub Client_ServerConnectionLost(ByVal sender As Object, ByVal e As EventArgs)
Console.WriteLine($"{Date.Now.ToLocalTime()} Session connection lost")
End Sub
Private Sub Client_KeepAlive(ByVal session As Session, ByVal e As KeepAliveEventArgs)
End Sub
Now, you can e.g. read data, write data, and monitor data or the browse the server via the client instance.
In the default setting, the client instance connects and disconnects itself.
Browse Nodes
Browse with node path
The PLCcom.Opc.Ua.Sdk has also been used to simplify the browsing of nodes. For this purpose, the browse command is
provided and executed by a configured client instance. The GetPathFromNodeId and GetNodeIdFromPath
commands are used to convert a NodeID to a BrowsePath and back.
This example browses the node "Objects.Server" forward. First create a BrowseDescription object:
NodeId sourceNode = client.GetNodeIdByPath("Objects.Data.Dynamic.Scalar");
BrowseDescription nodeToBrowse1 = new BrowseDescription();
nodeToBrowse1.NodeId = sourceNode;
nodeToBrowse1.BrowseDirection = BrowseDirection.Forward;
nodeToBrowse1.ReferenceTypeId = ReferenceTypeIds.Aggregates;
nodeToBrowse1.IncludeSubtypes = true;
nodeToBrowse1.NodeClassMask = (uint)(NodeClass.Object | NodeClass.Variable);
nodeToBrowse1.ResultMask = (uint)BrowseResultMask.All;
BrowseDescription nodeToBrowse2 = new BrowseDescription();
nodeToBrowse2.NodeId = sourceNode;
nodeToBrowse2.BrowseDirection = BrowseDirection.Forward;
nodeToBrowse2.ReferenceTypeId = ReferenceTypeIds.Organizes;
nodeToBrowse2.IncludeSubtypes = true;
nodeToBrowse2.NodeClassMask = (uint)(NodeClass.Object | NodeClass.Variable);
nodeToBrowse2.ResultMask = (uint)BrowseResultMask.All;
BrowseDescriptionCollection nodesToBrowse = new BrowseDescriptionCollection();
nodesToBrowse.Add(nodeToBrowse1);
nodesToBrowse.Add(nodeToBrowse2);
Dim sourceNode As NodeId = client.GetNodeIdByPath("Objects.Data.Dynamic.Scalar")
Dim nodeToBrowse1 As BrowseDescription = New BrowseDescription()
nodeToBrowse1.NodeId = sourceNode
nodeToBrowse1.BrowseDirection = BrowseDirection.Forward
nodeToBrowse1.ReferenceTypeId = ReferenceTypeIds.Aggregates
nodeToBrowse1.IncludeSubtypes = True
nodeToBrowse1.NodeClassMask = CUInt(NodeClass.Object Or NodeClass.Variable)
nodeToBrowse1.ResultMask = CUInt(BrowseResultMask.All)
Dim nodeToBrowse2 As BrowseDescription = New BrowseDescription()
nodeToBrowse2.NodeId = sourceNode
nodeToBrowse2.BrowseDirection = BrowseDirection.Forward
nodeToBrowse2.ReferenceTypeId = ReferenceTypeIds.Organizes
nodeToBrowse2.IncludeSubtypes = True
nodeToBrowse2.NodeClassMask = CUInt(NodeClass.Object Or NodeClass.Variable)
nodeToBrowse2.ResultMask = CUInt(BrowseResultMask.All)
Dim nodesToBrowse As BrowseDescriptionCollection = New BrowseDescriptionCollection()
nodesToBrowse.Add(nodeToBrowse1)
nodesToBrowse.Add(nodeToBrowse2)
Now you can browse the "Objects.Server" node and get back a ReferenceDescriptionCollection
object with the result of the operation:
ReferenceDescriptionCollection rdc = client.BrowseFull(nodesToBrowse);
if ( rdc.Count > 0)
{
foreach (ReferenceDescription rd in rdc)
{
Console.WriteLine("Child NodeID found => "+ rd.NodeId+
" NodeClass => " + rd.NodeClass.ToString() +
" BrowseName => " + rd.BrowseName.ToString() +
" DisplayName => " + rd.DisplayName.ToString());
}
}
else
{
Console.WriteLine("no references found");
}
Dim rdc As ReferenceDescriptionCollection = client.BrowseFull(nodesToBrowse)
If rdc.Count > 0 Then
For Each rd As ReferenceDescription In rdc
Console.WriteLine($"Child NodeID found => {rd.NodeId} NodeClass => {rd.NodeClass.ToString()} BrowseName => {rd.BrowseName.ToString()} DisplayName => {rd.DisplayName.ToString()}")
Next
Else
Console.WriteLine("no references found")
End If
Browse with NodeId
In this example, the object is browsed forward through the Objects node. To do this, we pass
the NodeId ObjectIds.ObjectsFolder to the BrowseDescription:
NodeId sourceNode = new NodeId("ns=2;i=10223");
BrowseDescription nodeToBrowse1 = new BrowseDescription();
nodeToBrowse1.NodeId = sourceNode;
nodeToBrowse1.BrowseDirection = BrowseDirection.Forward;
nodeToBrowse1.ReferenceTypeId = ReferenceTypeIds.Aggregates;
nodeToBrowse1.IncludeSubtypes = true;
nodeToBrowse1.NodeClassMask = (uint)(NodeClass.Object | NodeClass.Variable);
nodeToBrowse1.ResultMask = (uint)BrowseResultMask.All;
BrowseDescription nodeToBrowse2 = new BrowseDescription();
nodeToBrowse2.NodeId = sourceNode;
nodeToBrowse2.BrowseDirection = BrowseDirection.Forward;
nodeToBrowse2.ReferenceTypeId = ReferenceTypeIds.Organizes;
nodeToBrowse2.IncludeSubtypes = true;
nodeToBrowse2.NodeClassMask = (uint)(NodeClass.Object | NodeClass.Variable);
nodeToBrowse2.ResultMask = (uint)BrowseResultMask.All;
BrowseDescriptionCollection nodesToBrowse = new BrowseDescriptionCollection();
nodesToBrowse.Add(nodeToBrowse1);
nodesToBrowse.Add(nodeToBrowse2);
Dim sourceNode As NodeId = New NodeId("ns=2;i=10223")
Dim nodeToBrowse1 As BrowseDescription = New BrowseDescription()
nodeToBrowse1.NodeId = sourceNode
nodeToBrowse1.BrowseDirection = BrowseDirection.Forward
nodeToBrowse1.ReferenceTypeId = ReferenceTypeIds.Aggregates
nodeToBrowse1.IncludeSubtypes = True
nodeToBrowse1.NodeClassMask = CUInt(NodeClass.Object Or NodeClass.Variable)
nodeToBrowse1.ResultMask = CUInt(BrowseResultMask.All)
Dim nodeToBrowse2 As BrowseDescription = New BrowseDescription()
nodeToBrowse2.NodeId = sourceNode
nodeToBrowse2.BrowseDirection = BrowseDirection.Forward
nodeToBrowse2.ReferenceTypeId = ReferenceTypeIds.Organizes
nodeToBrowse2.IncludeSubtypes = True
nodeToBrowse2.NodeClassMask = CUInt(NodeClass.Object Or NodeClass.Variable)
nodeToBrowse2.ResultMask = CUInt(BrowseResultMask.All)
Dim nodesToBrowse As BrowseDescriptionCollection = New BrowseDescriptionCollection()
nodesToBrowse.Add(nodeToBrowse1)
nodesToBrowse.Add(nodeToBrowse2)
Now you can browse the "Objects" node and get back a ReferenceDescriptionCollection
object with the result of the operation:
foreach (ReferenceDescription rd in client.BrowseFull(nodeToBrowse))
{
Console.WriteLine("Child NodeID found => " + rd.NodeId + " " +
rd.DisplayName.ToString() + " NodeClass => " + rd.NodeClass.ToString() +
" FullPath => " + client.GetPathFromNodeId(rd.NodeId)[0]);
For Each rd As ReferenceDescription In client.Browse(nodeToBrowse)
Console.WriteLine(("Child NodeID found => " & rd.NodeId.ToString() & " " & _ rd.DisplayName.ToString() & " NodeClass => " & rd.NodeClass.ToString() & _
" FullPath => ") + client.GetPathFromNodeId(rd.NodeId)(0))
Next
Dim rdc As ReferenceDescriptionCollection = client.BrowseFull(nodesToBrowse)
If rdc.Count > 0 Then
For Each rd As ReferenceDescription In rdc
Console.WriteLine($"Child NodeID found => {rd.NodeId} NodeClass => {rd.NodeClass.ToString()} BrowseName => {rd.BrowseName.ToString()} DisplayName => {rd.DisplayName.ToString()}")
Next
Else
Console.WriteLine("no references found")
End If
Read and write data
The usual reading and writing of values can be performed with a single line of code.
A prerequisite is a configured client instance (see above).
By default, the PLCcom.Opc.Ua.Sdk automatically connects to the server and also monitors its connection.
As you already know, you can also simply address the node with the complete browse name during monitoring, and the conversion
to the NodeID is performed automatically in the background in the Sdk.
The following examples illustrates how to read and write data from/to an Opc Ua DataAccess server.
Available Attributes read or write
In PLCcom.Opc.Ua.Sdk the possible attributes for reading or writing are preconfigured in the enum
PLCcom.Opc.Ua.Sdk.AttributeId:
NodeIdNodeClassBrowseNameDisplayNameDescriptionWriteMaskUserWriteMaskIsAbstractSymmetricInverseNameContainsNoLoopsEventNotifierValueDataTypeValueRankArrayDimensionsAccessLevelUserAccessLevelMinimumSamplingIntervalHistorizingExecutableUserExecutableDataTypeDefinitionRolePermissionsUserRolePermissionsAccessRestrictionsAccessLevelEx
Read values or attributes
The following example illustrates how to read and write data or attributes from/to an Opc Ua DataAccess server.
By giving the parameter AttributeId you can determine which attributes you want to read:
ReadValueIdCollection nodesToRead = new ReadValueIdCollection();
ReadValueId nodeToRead = new ReadValueId();
nodeToRead.NodeId = client.GetNodeIdByPath("Objects.Data.Static.Scalar.Int16Value");
nodeToRead.AttributeId = Attributes.Value;
nodesToRead.Add(nodeToRead);
nodeToRead = new ReadValueId();
nodeToRead.NodeId = client.GetNodeIdByPath("Objects.Data.Static.Scalar.Int32Value");
nodeToRead.AttributeId = Attributes.Value;
nodesToRead.Add(nodeToRead);
nodeToRead = new ReadValueId();
nodeToRead.NodeId = client.GetNodeIdByPath("Objects.Data.Static.Scalar.Int32Value");
nodeToRead.AttributeId = Attributes.Value;
nodesToRead.Add(nodeToRead);
DataValueCollection readresults = client.Read(nodesToRead);
Dim nodesToRead As ReadValueIdCollection = New ReadValueIdCollection()
Dim nodeToRead As ReadValueId = New ReadValueId()
nodeToRead.NodeId = client.GetNodeIdByPath("Objects.Data.Static.Scalar.Int16Value")
nodeToRead.AttributeId = Attributes.Value
nodesToRead.Add(nodeToRead)
nodeToRead = New ReadValueId()
nodeToRead.NodeId = client.GetNodeIdByPath("Objects.Data.Static.Scalar.Int32Value")
nodeToRead.AttributeId = Attributes.Value
nodesToRead.Add(nodeToRead)
nodeToRead = New ReadValueId()
nodeToRead.NodeId = client.GetNodeIdByPath("Objects.Data.Static.Scalar.Int32Value")
nodeToRead.AttributeId = Attributes.Value
nodesToRead.Add(nodeToRead)
Dim readresults As DataValueCollection = client.Read(nodesToRead)
Write data or attributes
The following example illustrates how to read and write data or attributes from/to an
Opc Ua DataAccess server. By giving the parameter AttributeId you can determine which attributes you want to write:
WriteValueCollection nodesToWrite = new WriteValueCollection();
WriteValue writeValue = new WriteValue();
writeValue.NodeId = client.GetNodeIdByPath("Objects.Data.Static.Scalar.Int16Value");
writeValue.Value = new DataValue((Int16)(-16));
writeValue.AttributeId = Attributes.Value;
nodesToWrite.Add(writeValue);
writeValue = new WriteValue();
writeValue.NodeId = client.GetNodeIdByPath("Objects.Data.Static.Scalar.Int32Value");
writeValue.AttributeId = Attributes.Value;
writeValue.Value = new DataValue(-3232);
nodesToWrite.Add(writeValue);
writeValue = new WriteValue();
writeValue.NodeId = client.GetNodeIdByPath("Objects.Data.Static.Scalar.Int64Value");
writeValue.AttributeId = Attributes.Value;
writeValue.Value = new DataValue((Int64)(-64646464));
nodesToWrite.Add(writeValue);
StatusCodeCollection writeResults = client.Write(nodesToWrite);
Dim nodesToWrite As WriteValueCollection = New WriteValueCollection()
Dim writeValue As WriteValue = New WriteValue()
writeValue.NodeId = client.GetNodeIdByPath("Objects.Data.Static.Scalar.Int16Value")
writeValue.Value = New DataValue(CShort(-16))
writeValue.AttributeId = Attributes.Value
nodesToWrite.Add(writeValue)
writeValue = New WriteValue()
writeValue.NodeId = client.GetNodeIdByPath("Objects.Data.Static.Scalar.Int32Value")
writeValue.AttributeId = Attributes.Value
writeValue.Value = New DataValue(-3232)
nodesToWrite.Add(writeValue)
writeValue = New WriteValue()
writeValue.NodeId = client.GetNodeIdByPath("Objects.Data.Static.Scalar.Int64Value")
writeValue.AttributeId = Attributes.Value
writeValue.Value = New DataValue(CLng(-64646464))
nodesToWrite.Add(writeValue)
Dim writeResults As StatusCodeCollection = client.Write(nodesToWrite)
Monitoring data
The monitoring functions of the PLCcom.Opc.Ua.Sdk have also
been made extremely convenient and easy for the developer.
A prerequisite is a configured client instance (see above).
By default, the PLCcom.Opc.Ua.Sdk automatically connects to the server
and also monitors its connection. You will be notified of an upcoming connection via an event.
As you already know, you can also address the node with the complete browse name during
monitoring, and the conversion to the NodeID is performed automatically in the background in the Sdk.
Create subscription-instances
To create a new subscription you have to call the following function of the Sdk.
In this case the default values from client configuration will be used.
The function is an overwritten function, it is possible to use parameters like for example publishing interval.
Subscription subscription = new Subscription()
subscription.PublishingInterval = 1000;
subscription.PublishingEnabled = false;
subscription.DisplayName = "mySubsription";
subscription.StateChanged += Subscription_StateChanged;
subscription.PublishStatusChanged += Subscription_PublishStatusChanged;
client.AddSubscription(subscription);
Dim subscription As Subscription = New Subscription()
subscription.PublishingInterval = 1000
subscription.PublishingEnabled = False
subscription.DisplayName = "mySubsription"
AddHandler subscription.StateChanged, AddressOf Subscription_StateChanged
AddHandler subscription.PublishStatusChanged, AddressOf Subscription_PublishStatusChanged
client.AddSubscription(subscription)
Edit subscription parameters
With the methods of Sdk you can edit your subscriptions.
The following code edit the parameter ‘publishing interval’ to 1000ms and setting ‘publishing’ mode to true.
subscription.PublishingInterval = 1000;
subscription.SetPublishingMode(true);
subscription.Modify();
subscription As Subscription = client.CreateSubscription("mySubsription", 500)
subscription.PublishingInterval = 1000
subscription.SetPublishingMode(True)
subscription.Modify()
Management of MonitoredItems
A MonitoredItems object corresponds to a node of an Opc Ua server to be monitored.
One or many MonitoredItems are logically bundled in a subscription.
The Subscription object can be used to create, modify or delete MonitoredItems objects.
Create a subscription object. Then create one or more MonitoredItems objects and add these objects to your subscription.
You link the "Notification Event" with a "Notification Method" (see example).
Via the "Notification-Event" the value changes of the MonitoredItem object are now made available to you.
Finally, call the method subscription.ApplyChanges ().
...
Subscription subscription = new Subscription()
subscription.PublishingInterval = 1000;
subscription.PublishingEnabled = false;
subscription.DisplayName = "mySubsription";
NodeId nodeId = client.GetNodeIdByPath("Objects.Data.Dynamic.Scalar.Int64Value");
MonitoredItem monitoredItem = new MonitoredItem(subscription.DefaultItem)
{
StartNodeId = nodeId,
SamplingInterval = 500,
QueueSize = UInt32.MaxValue,
DisplayName = nodeId.ToString()
};
monitoredItem.Notification += Client_MonitorNotification;
subscription.AddItem(monitoredItem);
subscription.ApplyChanges();
...
private void Client_MonitorNotification(MonitoredItem monitoredItem, MonitoredItemNotificationEventArgs e)
{
MonitoredItemNotification notification = e.NotificationValue as MonitoredItemNotification;
Console.WriteLine(monitoredItem.StartNodeId.Identifier + " Value: " + notification.Value + " Status: " + notification.Value.StatusCode.ToString());
}
...
subscription As Subscription = client.CreateSubscription("mySubsription", 500)
subscription.PublishingInterval = 1000
subscription.SetPublishingMode(True)
subscription.Modify()
Dim nodeId As NodeId = client.GetNodeIdByPath("Objects.Data.Dynamic.Scalar.Int64Value")
Dim monitoredItem As MonitoredItem = New MonitoredItem(subscription.DefaultItem) With {
.StartNodeId = nodeId,
.SamplingInterval = 500,
.QueueSize = UInteger.MaxValue,
.DisplayName = nodeId.ToString()
}
AddHandler monitoredItem.Notification, AddressOf Client_MonitorNotification
subscription.AddItem(monitoredItem)
subscription.ApplyChanges()
...
Private Sub Client_MonitorNotification(ByVal monitoredItem As MonitoredItem, ByVal e As MonitoredItemNotificationEventArgs)
Dim notification As MonitoredItemNotification = TryCast(e.NotificationValue, MonitoredItemNotification)
Console.WriteLine($"{monitoredItem.StartNodeId.Identifier} Value: {notification.Value} Status: {notification.Value.StatusCode.ToString()}")
End Sub
Call methods
Use a call-method to call server methods from the client.
Attention:
Not every Opc Ua server supports all call-methods.
See the documentation of your Opc-Server-manufacturer.
In the delivery package you will find several code examples within the tutorials
for the execution of call calls with the transfer of simple flat data and even complex structures.
Following, the definition of data structure to passing with method call:
int myIntValue1 = 1;
string myStringValue2 = "testvalue";
int myIntValue3 = 3333;
int myIntValue4 = 4444;
string myStringValue5 = "a_string_value";
Dim myIntValue1 As Integer = 1
Dim myStringValue2 As String = "testvalue"
Dim myIntValue3 As Integer = 3333
Dim myIntValue4 As Integer = 4444
Dim myStringValue5 As String = "a_string_value"
Next step, preparation and execution of the call method:
BinaryEncoder encoder = new BinaryEncoder(client.getMessageContext());
encoder.WriteInt32("", myIntValue1);
encoder.WriteString("", myStringValue2);
encoder.WriteInt32("", myIntValue3);
encoder.WriteInt32("", myIntValue4);
byte[] argumentByteArray = new byte[encoder.BaseStream.Length];
encoder.BaseStream.Position = 0;
encoder.BaseStream.Read(argumentByteArray, 0, argumentByteArray.Length);
ExtensionObject extensionObjectWithInputArguments = new ExtensionObject();
extensionObjectWithInputArguments.Body = argumentByteArray;
extensionObjectWithInputArguments.TypeId = new ExpandedNodeId("DataStructure_One", 3);
VariantCollection inputArguments = new VariantCollection();
inputArguments.Add(new Variant(extensionObjectWithInputArguments));
NodeId objectNode = new NodeId("myObjectNode", 3);
NodeId methodNode = new NodeId("myMethodNode", 3);
CallMethodRequest request = new CallMethodRequest();
request.ObjectId = objectNode;
request.MethodId = methodNode;
request.InputArguments = inputArguments;
CallMethodResult result = client.Call(request);
if (StatusCode.IsGood(result.StatusCode))
{
foreach (Variant outputArgument in result.OutputArguments)
{
if (outputArgument != Variant.Null)
Console.WriteLine("output argument: " + outputArgument.ToString());
}
}
Dim encoder As BinaryEncoder = New BinaryEncoder(client.getMessageContext)
encoder.WriteInt32("", myIntValue1)
encoder.WriteString("", myStringValue2)
encoder.WriteInt32("", myIntValue3)
encoder.WriteInt32("", myIntValue4)
encoder.WriteString("", myStringValue5)
Dim argumentByteArray() As Byte = New Byte((encoder.BaseStream.Length) - 1) {}
encoder.BaseStream.Position = 0
encoder.BaseStream.Read(argumentByteArray, 0, argumentByteArray.Length)
Dim extensionObjectWithInputArguments As ExtensionObject = New ExtensionObject()
extensionObjectWithInputArguments.Body = argumentByteArray
extensionObjectWithInputArguments.TypeId = New ExpandedNodeId( _
New NodeId("DataStructure_One", 3))
Dim inputArguments As VariantCollection = New VariantCollection
inputArguments.Add(New PLCcom.Opc.Ua.Variant(extensionObjectWithInputArguments))
Dim objectNode As NodeId = New NodeId("myObjectNode", 3)
Dim methodNode As NodeId = New NodeId("myMethodNode", 3)
Dim request As CallMethodRequest = New CallMethodRequest
request.ObjectId = objectNode
request.MethodId = methodNode
request.InputArguments = inputArguments
Dim result As CallMethodResult = client.Call(request)
If StatusCode.IsGood(result.StatusCode) Then
For Each outputArgument As PLCcom.Opc.Ua.Variant In result.OutputArguments
If (outputArgument <> PLCcom.Opc.Ua.Variant.Null) Then
Console.WriteLine(("output argument: " + outputArgument.ToString))
End If
Next
Else
Console.WriteLine(("Method call failed " + result.StatusCode.ToString))
End If