How-to guide
Read and write values
Read and write the values of single and multiple nodes, access other attributes and parts of arrays, and evaluate the results with their status.
How-to guide
Read and write values
Read values
Types usedOpcClientOpcNodeIdOpcValueOpcAttributeOpcReadNode
The NodeId (OpcNodeId) defines which node the client reads. By default, the client always reads the current value of the Value attribute. Besides the value, the OpcValue that the client reads contains two timestamps. SourceTimestamp states when the source determined the value. ServerTimestamp states when the server recorded the value. To read another attribute of the node, pass the corresponding OpcAttribute when you call ReadNode or in the respective OpcReadNode instance.
Read the value of the Value attribute of a single node:
OpcValue isRunning = client.ReadNode("ns=2;s=Machine/IsRunning");Dim isRunning As OpcValue = client.ReadNode("ns=2;s=Machine/IsRunning")Read the values of the Value attribute of multiple nodes:
OpcReadNode[] commands = new OpcReadNode[] {
new OpcReadNode("ns=2;s=Machine/Job/Number"),
new OpcReadNode("ns=2;s=Machine/Job/Name"),
new OpcReadNode("ns=2;s=Machine/Job/Speed")
};
IEnumerable<OpcValue> job = client.ReadNodes(commands);Dim commands As OpcReadNode() = New OpcReadNode() { _
New OpcReadNode("ns=2;s=Machine/Job/Number"), _
New OpcReadNode("ns=2;s=Machine/Job/Name"), _
New OpcReadNode("ns=2;s=Machine/Job/Speed") _
}
Dim job As IEnumerable(Of OpcValue) = client.ReadNodes(commands)Read the value of the DisplayName attribute of a single node:
OpcValue isRunningDisplayName = client.ReadNode("ns=2;s=Machine/IsRunning", OpcAttribute.DisplayName);Dim isRunningDisplayName As OpcValue = client.ReadNode("ns=2;s=Machine/IsRunning", OpcAttribute.DisplayName)Read the values of the DisplayName attribute of multiple nodes:
OpcReadNode[] commands = new OpcReadNode[] {
new OpcReadNode("ns=2;s=Machine/Job/Number", OpcAttribute.DisplayName),
new OpcReadNode("ns=2;s=Machine/Job/Name", OpcAttribute.DisplayName),
new OpcReadNode("ns=2;s=Machine/Job/Speed", OpcAttribute.DisplayName)
};
IEnumerable<OpcValue> jobDisplayNames = client.ReadNodes(commands);Dim commands As OpcReadNode() = New OpcReadNode() { _
New OpcReadNode("ns=2;s=Machine/Job/Number", OpcAttribute.DisplayName), _
New OpcReadNode("ns=2;s=Machine/Job/Name", OpcAttribute.DisplayName), _
New OpcReadNode("ns=2;s=Machine/Job/Speed", OpcAttribute.DisplayName) _
}
Dim jobDisplayNames As IEnumerable(Of OpcValue) = client.ReadNodes(commands)Write values
Types usedOpcClientOpcNodeIdOpcValueOpcAttributeOpcStatusOpcStatusCollectionOpcWriteNode
The NodeId (OpcNodeId) defines which node the client writes. By default, the client always writes the current value of the Value attribute. By default, the client sends the timestamp of the OpcValue you pass as the source timestamp (SourceTimestamp). If you pass a plain value, it sends no timestamp. The section Timestamps when writing shows how to change this. To write another attribute of the node, pass the corresponding OpcAttribute when you call WriteNode or in the respective OpcWriteNode instance.
Write the value of a single node:
OpcStatus result = client.WriteNode("ns=2;s=Machine/Job/Cancel", true);Dim result As OpcStatus = client.WriteNode("ns=2;s=Machine/Job/Cancel", True)Write the values of multiple nodes:
OpcWriteNode[] commands = new OpcWriteNode[] {
new OpcWriteNode("ns=2;s=Machine/Job/Number", "0002"),
new OpcWriteNode("ns=2;s=Machine/Job/Name", "MAN_F01_78910"),
new OpcWriteNode("ns=2;s=Machine/Job/Speed", 1220.5)
};
OpcStatusCollection results = client.WriteNodes(commands);Dim commands As OpcWriteNode() = New OpcWriteNode() { _
New OpcWriteNode("ns=2;s=Machine/Job/Number", "0002"), _
New OpcWriteNode("ns=2;s=Machine/Job/Name", "MAN_F01_78910"), _
New OpcWriteNode("ns=2;s=Machine/Job/Speed", 1220.5) _
}
Dim results As OpcStatusCollection = client.WriteNodes(commands)Write the value of the DisplayName attribute of a single node:
client.WriteNode("ns=2;s=Machine/IsRunning", OpcAttribute.DisplayName, "IsActive");client.WriteNode("ns=2;s=Machine/IsRunning", OpcAttribute.DisplayName, "IsActive")Write the values of the DisplayName attribute of multiple nodes:
OpcWriteNode[] commands = new OpcWriteNode[] {
new OpcWriteNode("ns=2;s=Machine/Job/Number", OpcAttribute.DisplayName, "Serial"),
new OpcWriteNode("ns=2;s=Machine/Job/Name", OpcAttribute.DisplayName, "Description"),
new OpcWriteNode("ns=2;s=Machine/Job/Speed", OpcAttribute.DisplayName, "Rotations per Second")
};
OpcStatusCollection results = client.WriteNodes(commands);Dim commands As OpcWriteNode() = New OpcWriteNode() { _
New OpcWriteNode("ns=2;s=Machine/Job/Number", OpcAttribute.DisplayName, "Serial"), _
New OpcWriteNode("ns=2;s=Machine/Job/Name", OpcAttribute.DisplayName, "Description"), _
New OpcWriteNode("ns=2;s=Machine/Job/Speed", OpcAttribute.DisplayName, "Rotations per Second") _
}
Dim results As OpcStatusCollection = client.WriteNodes(commands)Timestamps when writing
Types usedOpcClientOpcTimestampSource
Some servers reject writing a value with the status BadWriteNotSupported if the timestamp sent does not meet their expectations. In that case, the client automatically retries the write with the other values of the OpcTimestampSource enumeration in turn (MinValue, UtcNow, Now, and MaxValue). It uses the first value the server accepts for all further writes of the session. To set the timestamp yourself instead, specify the source like this:
// Always send the current time as the source timestamp of the values to write.
client.Services.WriteNodes.TimestampSource = OpcTimestampSource.UtcNow;'Always send the current time as the source timestamp of the values to write.
client.Services.WriteNodes.TimestampSource = OpcTimestampSource.UtcNowRead and write parts of arrays
Types usedOpcClientOpcNodeIdOpcRangeOpcValueOpcStatus
If a node provides an array as its value, the client does not always have to read or write the entire array. An instance of the OpcRange class defines which elements of the array the client reads or writes. In OPC UA, this range is called IndexRange. The first value is the index of the first element, the second value the index of the last element.
Read a part of an array:
// Read the elements with the index 2 to 4 of the array.
OpcValue speeds = client.ReadNode(
"ns=2;s=Machine/Job/Speeds",
new OpcRange(start: 2, end: 4));'Read the elements with the index 2 to 4 of the array.
Dim speeds As OpcValue = client.ReadNode( _
"ns=2;s=Machine/Job/Speeds", _
New OpcRange(start:=2, [end]:=4))Write a part of an array:
// Write the elements with the index 2 to 4 of the array.
OpcStatus result = client.WriteNode(
"ns=2;s=Machine/Job/Speeds",
new OpcRange(start: 2, end: 4),
new int[] { 1200, 1300, 1400 });'Write the elements with the index 2 to 4 of the array.
Dim result As OpcStatus = client.WriteNode( _
"ns=2;s=Machine/Job/Speeds", _
New OpcRange(start:=2, [end]:=4), _
New Integer() {1200, 1300, 1400})For multidimensional arrays, pass a further OpcRange instance for each dimension (OpcRange(start, end, next)). Whether a server supports reading and writing parts of arrays depends on the server.
Evaluate the values read
Types usedOpcClientOpcNodeIdOpcValueOpcStatusOpcStatusCollection
The ReadNode methods always return an OpcValue. The ReadNodes methods return a collection with one OpcValue per node read. The value read is in the Value property. You check the result of the read request with the Status property. The SourceTimestamp property returns the timestamp at which the source determined the value. The ServerTimestamp property returns the timestamp at which the server recorded the value.
Read the value of a single node:
OpcValue value = client.ReadNode("ns=2;s=Machine/Job/Speed");Dim value As OpcValue = client.ReadNode("ns=2;s=Machine/Job/Speed")Check the result of the read request:
if (value.Status.IsGood) {
// Your code to operate on the value.
}If value.Status.IsGood Then
'Your code to operate on the value.
End IfGet the scalar value of the OpcValue:
int intValue = (int)value.Value;Dim intValue As Integer = CInt(value.Value)Get the array value of the OpcValue:
int[] intValues = (int[])value.Value;Dim intValues As Integer() = CType(value.Value, Integer())The WriteNode methods always return an OpcStatus. The WriteNodes methods return an OpcStatusCollection that contains one OpcStatus for each node written. You check the result of the write request with the properties of the individual OpcStatus objects.
Write the scalar value of a single node:
OpcStatus status = client.WriteNode("ns=2;s=Machine/Job/Speed", 1200);Dim status As OpcStatus = client.WriteNode("ns=2;s=Machine/Job/Speed", 1200)Write the array value of a single node:
int[] values = new int[3] { 1200, 1350, 1780 };
OpcStatus status = client.WriteNode("ns=2;s=Machine/Job/Speeds", values);Dim values As Integer() = New Integer(2) {1200, 1350, 1780}
Dim status As OpcStatus = client.WriteNode("ns=2;s=Machine/Job/Speeds", values)Check the result of the write request:
if (!status.IsGood) {
// Your code to handle a failed write operation.
}If Not status.IsGood Then
'Your code to handle a failed write operation.
End IfIf you only change single elements, writing a part of the array is usually easier (section Read and write parts of arrays). With the steps shown for scalar values and array values, you change the array value of a variable node like this:
using (var client = new OpcClient("opc.tcp://localhost:4840")) {
client.Connect();
OpcValue arrayValue = client.ReadNode("ns=2;s=Machine/Job/Speeds");
if (arrayValue.Status.IsGood) {
int[] intArrayValue = (int[])arrayValue.Value;
intArrayValue[2] = 100;
intArrayValue[4] = 200;
intArrayValue[9] = 300;
OpcStatus status = client.WriteNode("ns=2;s=Machine/Job/Speeds", intArrayValue);
if (!status.IsGood)
Console.WriteLine("Failed to write array value!");
}
}Using client As New OpcClient("opc.tcp://localhost:4840")
client.Connect()
Dim arrayValue As OpcValue = client.ReadNode("ns=2;s=Machine/Job/Speeds")
If arrayValue.Status.IsGood Then
Dim intArrayValue As Integer() = CType(arrayValue.Value, Integer())
intArrayValue(2) = 100
intArrayValue(4) = 200
intArrayValue(9) = 300
Dim status As OpcStatus = client.WriteNode("ns=2;s=Machine/Job/Speeds", intArrayValue)
If Not status.IsGood Then _
Console.WriteLine("Failed to write array value!")
End If
End UsingRead and write typed values
Types usedOpcClientOpcNodeValueOpcStatus
The OpcNodeValue<T> class combines the identifier of a node with the .NET type of its value. Read returns the value directly as T, without converting it through OpcValue.Value. Write writes a value of this type. If the value read has a bad status, Read returns the default value of T. The object holds the status in its Status property. Check it before you use the value:
var speed = new OpcNodeValue<double>("ns=2;s=Machine/Speed");
double current = speed.Read(client);
if (speed.Status.IsGood) {
OpcStatus result = speed.Write(client, current + 10);
}Dim speed = New OpcNodeValue(Of Double)("ns=2;s=Machine/Speed")
Dim current As Double = speed.Read(client)
If speed.Status.IsGood Then
Dim result As OpcStatus = speed.Write(client, current + 10)
End IfThe client reads multiple typed values with a single call to ReadNodes:
var temperatures = new OpcNodeValue<double>[] {
new OpcNodeValue<double>("ns=2;s=Machine/Temperature1"),
new OpcNodeValue<double>("ns=2;s=Machine/Temperature2"),
new OpcNodeValue<double>("ns=2;s=Machine/Temperature3")
};
double[] values = temperatures.Read(client);Dim temperatures = New OpcNodeValue(Of Double)() { _
New OpcNodeValue(Of Double)("ns=2;s=Machine/Temperature1"), _
New OpcNodeValue(Of Double)("ns=2;s=Machine/Temperature2"), _
New OpcNodeValue(Of Double)("ns=2;s=Machine/Temperature3") _
}
Dim values As Double() = temperatures.Read(client)Multidimensional arrays
The client returns values with more than one dimension (a matrix in OPC UA) as a multidimensional .NET array, for example double[,]. It also writes a multidimensional array as a matrix. You do not have to manage the dimensions separately:
var grid = new double[2, 3] { { 1, 2, 3 }, { 4, 5, 6 } };
client.WriteNode("ns=2;s=Machine/Grid", grid);
double[,] values = (double[,])client.ReadNode("ns=2;s=Machine/Grid").Value;
double value = values[1, 2];Dim grid = New Double(1, 2) {{1, 2, 3}, {4, 5, 6}}
client.WriteNode("ns=2;s=Machine/Grid", grid)
Dim values As Double(,) = CType(client.ReadNode("ns=2;s=Machine/Grid").Value, Double(,))
Dim value As Double = values(1, 2)Address nodes by their namespace URI
Types usedOpcClientOpcNodeIdOpcNamespace
The namespace index in ns=2;s=... is only a reference into the namespace table of the server. It can differ between servers and change after a server restart. The URI of the namespace, in contrast, is stable. An identifier with nsu= instead of ns= names the URI. The client resolves it against the current namespace table of the session only when it sends the request, also after a reconnect:
OpcValue speed = client.ReadNode("nsu=http://example.com/machine/;s=Machine/Speed");Dim speed As OpcValue = client.ReadNode("nsu=http://example.com/machine/;s=Machine/Speed")Alternatively, client.Namespaces.ResolveIndex returns the current index of a namespace URI, or -1 if the server does not know the namespace:
int index = client.Namespaces.ResolveIndex("http://example.com/machine/");
if (index >= 0) {
var temperatureId = new OpcNodeId("Machine/Temperature", namespaceIndex: index);
OpcValue temperature = client.ReadNode(temperatureId);
}Dim index As Integer = client.Namespaces.ResolveIndex("http://example.com/machine/")
If index >= 0 Then
Dim temperatureId = New OpcNodeId("Machine/Temperature", namespaceIndex:=index)
Dim temperature As OpcValue = client.ReadNode(temperatureId)
End IfRegister frequently read nodes
Types usedOpcClientOpcNodeIdOpcNodeIdCollectionOpcReadNode
If a client reads or writes the same nodes again and again, it can register them with the server. RegisterNodes returns an identifier for each node that the server can optimize for repeated access. Whether and how much it does so depends on the server. The registered identifiers are valid only in the session in which the client registered them. After a new session, register them again (section What to do after a new session). When you no longer need the identifiers, UnregisterNodes releases them:
OpcNodeIdCollection registeredNodeIds = client.RegisterNodes(
"ns=2;s=Machine/Speed",
"ns=2;s=Machine/Temperature");
var commands = new OpcReadNode[registeredNodeIds.Count];
for (int index = 0; index < commands.Length; index++)
commands[index] = new OpcReadNode(registeredNodeIds[index]);
for (int cycle = 0; cycle < 10; cycle++)
client.ReadNodes(commands);
client.UnregisterNodes(registeredNodeIds);Dim registeredNodeIds As OpcNodeIdCollection = client.RegisterNodes( _
"ns=2;s=Machine/Speed", _
"ns=2;s=Machine/Temperature")
Dim commands = New OpcReadNode(registeredNodeIds.Count - 1) {}
For index As Integer = 0 To commands.Length - 1
commands(index) = New OpcReadNode(registeredNodeIds(index))
Next
For cycle As Integer = 0 To 9
client.ReadNodes(commands)
Next
client.UnregisterNodes(registeredNodeIds)
