How-to guide
Edit the address space
Create and delete nodes and references in the address space of a server from the client.
How-to guide
Edit the address space
Create nodes
Types usedOpcClientOpcAddNodeOpcAddNodeResultOpcAddNodeResultCollectionOpcAddDataItemNodeOpcAddAnalogItemNodeOpcAddObjectNodeOpcAddFolderNodeOpcAddDataVariableNodeOpcAddPropertyNode
A server provides its clients with a predefined set of standard nodes. A client can make the server provide additional nodes. For this, the client uses the AddNodes interface of the server. For type-specific nodes, the SDK provides many subclasses of the OpcAddNode class. To create a new folder node:
OpcAddNodeResult result = client.AddNode(new OpcAddFolderNode(
name: "Jobs",
nodeId: OpcNodeId.Null,
parentNodeId: "ns=2;s=Machine"));Dim result As OpcAddNodeResult = client.AddNode(New OpcAddFolderNode( _
name:="Jobs", _
nodeId:=OpcNodeId.Null, _
parentNodeId:="ns=2;s=Machine"))The parameters in the example contain the minimum required information. The first parameter, name, sets the name (property Name, the BrowseName of the node) and the display name (property DisplayName) of the node. To set a description, use the Description property. The second parameter, nodeId, tells the server which identifier to assign to the node. If another node in the address space of the server already uses this identifier, the server does not create the node. A server developed with the SDK then returns the code BadNodeIdRejected; other servers might return BadNodeIdExists. If you pass OpcNodeId.Null as in the example, the server generates a new identifier itself and assigns it to the node. Finally, the parentNodeId parameter sets the identifier of the parent node under which the server creates the new node in the tree. If you do not specify a parent node, the server creates the node below the ObjectsFolder.
The AddNode method returns an instance of the OpcAddNodeResult class. Besides the outcome of the operation, it contains the identifier the server actually used for the new node:
if (result.IsGood)
Console.WriteLine("NodeId of 'Jobs': {0}", result.NodeId);
else
Console.WriteLine("Failed to add node: {0}", result.Description);If result.IsGood Then
Console.WriteLine("NodeId of 'Jobs': {0}", result.NodeId)
Else
Console.WriteLine("Failed to add node: {0}", result.Description)
End IfTo create multiple nodes at once:
OpcNodeId jobsNodeId = result.NodeId;
OpcAddNodeResultCollection results = client.AddNodes(
new OpcAddDataVariableNode<string>("CurrentJob", jobsNodeId),
new OpcAddDataVariableNode<string>("NextJob", jobsNodeId),
new OpcAddDataVariableNode<int>("NumberOfJobs", jobsNodeId));Dim jobsNodeId As OpcNodeId = result.NodeId
Dim results As OpcAddNodeResultCollection = client.AddNodes( _
New OpcAddDataVariableNode(Of String)("CurrentJob", jobsNodeId), _
New OpcAddDataVariableNode(Of String)("NextJob", jobsNodeId), _
New OpcAddDataVariableNode(Of Integer)("NumberOfJobs", jobsNodeId))The AddNodes method returns an instance of the OpcAddNodeResultCollection class. It contains instances of OpcAddNodeResult, which you evaluate and process as described above.
You can also pass entire trees of nodes to the AddNode and AddNodes methods:
OpcAddNodeResultCollection results = client.AddNodes(
new OpcAddObjectNode(
"JOB001",
nodeId: OpcNodeId.Null,
parentNodeId: jobsNodeId,
new OpcAddDataVariableNode<sbyte>("Status", -1),
new OpcAddDataVariableNode<string>("Serial", "J01-DX-11.001"),
new OpcAddAnalogItemNode<float>("Speed", 1200f) {
EngineeringUnit = new OpcEngineeringUnitInfo(5067859, "m/s", "metre per second"),
EngineeringUnitRange = new OpcValueRange(5400, 0),
Definition = "DB100.DBW 0"
},
new OpcAddObjectNode(
"Setup",
new OpcAddPropertyNode<bool>("UseCutter"),
new OpcAddPropertyNode<bool>("UseDrill")),
new OpcAddObjectNode(
"Schedule",
new OpcAddPropertyNode<DateTime>("EarliestStartTime"),
new OpcAddPropertyNode<DateTime>("LatestStartTime"),
new OpcAddPropertyNode<TimeSpan>("EstimatedRunTime"))),
new OpcAddObjectNode(
"JOB002",
nodeId: OpcNodeId.Null,
parentNodeId: jobsNodeId,
new OpcAddDataVariableNode<sbyte>("Status", -1),
new OpcAddDataVariableNode<string>("Serial", "J01-DX-53.002"),
new OpcAddAnalogItemNode<float>("Speed", 3210f) {
EngineeringUnit = new OpcEngineeringUnitInfo(5067859, "m/s", "metre per second"),
EngineeringUnitRange = new OpcValueRange(5400, 0),
Definition = "DB200.DBW 0"
},
new OpcAddObjectNode(
"Setup",
new OpcAddPropertyNode<bool>("UseCutter"),
new OpcAddPropertyNode<bool>("UseDrill")),
new OpcAddObjectNode(
"Schedule",
new OpcAddPropertyNode<DateTime>("EarliestStartTime"),
new OpcAddPropertyNode<DateTime>("LatestStartTime"),
new OpcAddPropertyNode<TimeSpan>("EstimatedRunTime"))));Dim results As OpcAddNodeResultCollection = client.AddNodes( _
New OpcAddObjectNode( _
"JOB001", _
nodeId:=OpcNodeId.Null, _
parentNodeId:=jobsNodeId, _
New OpcAddDataVariableNode(Of SByte)("Status", -1), _
New OpcAddDataVariableNode(Of String)("Serial", "J01-DX-11.001"), _
New OpcAddAnalogItemNode(Of Single)("Speed", 1200F) With {
.EngineeringUnit = New OpcEngineeringUnitInfo(5067859, "m/s", "metre per second"),
.EngineeringUnitRange = New OpcValueRange(5400, 0),
.Definition = "DB100.DBW 0"
}, _
New OpcAddObjectNode( _
"Setup", _
New OpcAddPropertyNode(Of Boolean)("UseCutter"), _
New OpcAddPropertyNode(Of Boolean)("UseDrill")), _
New OpcAddObjectNode( _
"Schedule", _
New OpcAddPropertyNode(Of DateTime)("EarliestStartTime"), _
New OpcAddPropertyNode(Of DateTime)("LatestStartTime"), _
New OpcAddPropertyNode(Of TimeSpan)("EstimatedRunTime"))), _
New OpcAddObjectNode( _
"JOB002", _
nodeId:=OpcNodeId.Null, _
parentNodeId:=jobsNodeId, _
New OpcAddDataVariableNode(Of SByte)("Status", -1), _
New OpcAddDataVariableNode(Of String)("Serial", "J01-DX-53.002"), _
New OpcAddAnalogItemNode(Of Single)("Speed", 3210F) With {
.EngineeringUnit = New OpcEngineeringUnitInfo(5067859, "m/s", "metre per second"),
.EngineeringUnitRange = New OpcValueRange(5400, 0),
.Definition = "DB200.DBW 0" _
}, _
New OpcAddObjectNode( _
"Setup", _
New OpcAddPropertyNode(Of Boolean)("UseCutter"), _
New OpcAddPropertyNode(Of Boolean)("UseDrill")), _
New OpcAddObjectNode( _
"Schedule", _
New OpcAddPropertyNode(Of DateTime)("EarliestStartTime"), _
New OpcAddPropertyNode(Of DateTime)("LatestStartTime"), _
New OpcAddPropertyNode(Of TimeSpan)("EstimatedRunTime"))))You can also build such a tree through the corresponding properties:
var jobsNodeId = result.NodeId;
var job = new OpcAddObjectNode(
name: "JOB003",
nodeId: OpcNodeId.Null,
parentNodeId: jobsNodeId);
job.Children.Add(new OpcAddDataVariableNode<sbyte>("Status", -1));
job.Children.Add(new OpcAddDataVariableNode<string>("Serial", "J01-DX-78.003"));
job.Children.Add(new OpcAddAnalogItemNode<float>("Speed", 1200f) {
EngineeringUnit = new OpcEngineeringUnitInfo(5067859, "m/s", "metre per second"),
EngineeringUnitRange = new OpcValueRange(5400, 0),
Definition = "DB100.DBW 0"
});
var setup = new OpcAddObjectNode("Setup");
setup.Children.Add(new OpcAddPropertyNode<bool>("UseCutter"));
setup.Children.Add(new OpcAddPropertyNode<bool>("UseDrill"));
job.Children.Add(setup);
var schedule = new OpcAddObjectNode("Schedule");
schedule.Children.Add(new OpcAddPropertyNode<DateTime>("EarliestStartTime"));
schedule.Children.Add(new OpcAddPropertyNode<DateTime>("LatestStartTime"));
schedule.Children.Add(new OpcAddPropertyNode<TimeSpan>("EstimatedRunTime"));
job.Children.Add(schedule);
OpcAddNodeResult result = client.AddNode(job);Dim jobsNodeId = result.NodeId
Dim job = New OpcAddObjectNode( _
name:="JOB003", _
nodeId:=OpcNodeId.Null, _
parentNodeId:=jobsNodeId)
job.Children.Add(New OpcAddDataVariableNode(Of SByte)("Status", -1))
job.Children.Add(New OpcAddDataVariableNode(Of String)("Serial", "J01-DX-78.003"))
job.Children.Add(new OpcAddAnalogItemNode(Of Single)("Speed", 1200f) With {
.EngineeringUnit = new OpcEngineeringUnitInfo(5067859, "m/s", "metre per second"),
.EngineeringUnitRange = new OpcValueRange(5400, 0),
.Definition = "DB100.DBW 0" _
})
Dim setup = New OpcAddObjectNode("Setup")
setup.Children.Add(New OpcAddPropertyNode(Of Boolean)("UseCutter"))
setup.Children.Add(New OpcAddPropertyNode(Of Boolean)("UseDrill"))
job.Children.Add(setup)
Dim schedule = New OpcAddObjectNode("Schedule")
schedule.Children.Add(New OpcAddPropertyNode(Of DateTime)("EarliestStartTime"))
schedule.Children.Add(New OpcAddPropertyNode(Of DateTime)("LatestStartTime"))
schedule.Children.Add(New OpcAddPropertyNode(Of TimeSpan)("EstimatedRunTime"))
job.Children.Add(schedule)
Dim result As OpcAddNodeResult = client.AddNode(job)To use type definitions other than those of the OpcAddNode subclasses, create object and variable nodes based on their type definition:
client.AddObjectNode(OpcObjectType.DeviceFailureEventType, "FailureInfo");
client.AddVariableNode(OpcVariableType.XYArrayItem, "Coordinates");client.AddObjectNode(OpcObjectType.DeviceFailureEventType, "FailureInfo")
client.AddVariableNode(OpcVariableType.XYArrayItem, "Coordinates")Besides the type definitions defined by the OPC Foundation, you can also create nodes based on the identifier of their type definition. To do this, declare the type in advance through an object-specific or variable-specific type definition. OpcNodeId.Parse creates the identifier of the type definition from its string. You can use this identifier as often as you like to create more nodes of this type:
// Declare Job Type
var jobType = OpcAddObjectNode.OfType(OpcNodeId.Parse("ns=2;s=Types/JobType"));
client.AddNodes(
jobType.Create("JOB001", nodeId: OpcNodeId.Null, parentNodeId: jobsNodeId),
jobType.Create("JOB002", nodeId: OpcNodeId.Null, parentNodeId: jobsNodeId),
jobType.Create("JOB003", nodeId: OpcNodeId.Null, parentNodeId: jobsNodeId),
jobType.Create("JOB004", nodeId: OpcNodeId.Null, parentNodeId: jobsNodeId));
var scheduleNodeId = OpcNodeId.Parse("ns=2;s=Machine/JOB002/Schedule");
// Declare Shift Time Type
var shiftTimeType = OpcAddVariableNode.OfType(OpcNodeId.Parse("ns=2;s=Types/ShiftTimeType"));
OpcAddNodeResult result = client.AddNode(new OpcAddObjectNode(
"ShiftPlanning",
nodeId: OpcNodeId.Null,
parentNodeId: scheduleNodeId,
shiftTimeType.Create("Early"),
shiftTimeType.Create("Noon"),
shiftTimeType.Create("Late")));'Declare Job Type
Dim jobType = OpcAddObjectNode.OfType(OpcNodeId.Parse("ns=2;s=Types/JobType"))
client.AddNodes( _
jobType.Create("JOB001", nodeId:=OpcNodeId.Null, parentNodeId:=jobsNodeId), _
jobType.Create("JOB002", nodeId:=OpcNodeId.Null, parentNodeId:=jobsNodeId), _
jobType.Create("JOB003", nodeId:=OpcNodeId.Null, parentNodeId:=jobsNodeId), _
jobType.Create("JOB004", nodeId:=OpcNodeId.Null, parentNodeId:=jobsNodeId))
Dim scheduleNodeId = OpcNodeId.Parse("ns=2;s=Machine/JOB002/Schedule")
'Declare Shift Time Type
Dim shiftTimeType = OpcAddVariableNode.OfType(OpcNodeId.Parse("ns=2;s=Types/ShiftTimeType"))
Dim result As OpcAddNodeResult = client.AddNode(New OpcAddObjectNode( _
"ShiftPlanning", _
nodeId:=OpcNodeId.Null, _
parentNodeId:=scheduleNodeId, _
shiftTimeType.Create("Early"), _
shiftTimeType.Create("Noon"), _
shiftTimeType.Create("Late")))Delete nodes
Types usedOpcClientOpcDeleteNodeOpcStatusOpcStatusCollection
Through the DeleteNodes interface of the server, you can delete both nodes provided by the server and nodes created by a client. Above all, you need the identifier of the node you want to delete:
OpcStatus result = client.DeleteNode("ns=2;s=Machine/Jobs");Dim result As OpcStatus = client.DeleteNode("ns=2;s=Machine/Jobs")The example above deletes the node with an instance of the OpcDeleteNode class. By default, it also deletes all references that point to the node. To keep the references to the node, also set the includeTargetReferences parameter to false:
OpcStatus result = client.DeleteNode(
"ns=2;s=Machine/Jobs",
includeTargetReferences: false);Dim result As OpcStatus = client.DeleteNode( _
"ns=2;s=Machine/Jobs", _
includeTargetReferences:=False)To delete multiple nodes at once:
OpcStatusCollection results = client.DeleteNodes(
new OpcDeleteNode("ns=2;s=Machine/Jobs/JOB001"),
new OpcDeleteNode("ns=2;s=Machine/Jobs/JOB002"),
new OpcDeleteNode("ns=2;s=Machine/Jobs/JOB003"));Dim results As OpcStatusCollection = client.DeleteNodes( _
New OpcDeleteNode("ns=2;s=Machine/Jobs/JOB001"), _
New OpcDeleteNode("ns=2;s=Machine/Jobs/JOB002"), _
New OpcDeleteNode("ns=2;s=Machine/Jobs/JOB003"))Create references
Types usedOpcClientOpcAddReferenceOpcStatusOpcStatusCollection
Nodes in the address space of a server can relate to each other in different ways. The address space describes these relationships through references. Besides the parent-child arrangement, nodes can have further logical relationships. These relationships describe in more detail what function the nodes have and how they depend on each other. References also let you define additional trees in the address space of the server without reorganizing existing nodes.
To create a reference, the client uses the AddReferences interface of the server:
client.AddReference(
"ns=2;s=Plant",
targetNodeId: "ns=2;s=Machines/MAC01",
targetNodeCategory: OpcNodeCategory.Object);client.AddReference( _
"ns=2;s=Plant", _
targetNodeId:="ns=2;s=Machines/MAC01", _
targetNodeCategory:=OpcNodeCategory.Object)The example creates a reference of the type Organizes that leads from the node with the identifier ns=2;s=Plant to the node ns=2;s=Machines/MAC01. By default, the client uses the reference type Organizes and the direction OpcReferenceDirection.ParentToChild. With this direction, the first node becomes the parent node. The statement therefore has the same result as the following example:
client.AddReference(
"ns=2;s=Plant",
targetNodeId: "ns=2;s=Machines/MAC01",
targetNodeCategory: OpcNodeCategory.Object,
direction: OpcReferenceDirection.ParentToChild,
referenceType: OpcReferenceType.Organizes);client.AddReference( _
"ns=2;s=Plant", _
targetNodeId:="ns=2;s=Machines/MAC01", _
targetNodeCategory:=OpcNodeCategory.Object, _
direction:=OpcReferenceDirection.ParentToChild, _
referenceType:=OpcReferenceType.Organizes)The first identifier always specifies the source node, the targetNodeId parameter the identifier of the target node. With the direction OpcReferenceDirection.ChildToParent, the client creates the reference from the target node to the source node instead. The additional targetNodeCategory parameter must match the Category property of the target node, the NodeClass in the specification. The server uses this value to make sure that it knows the requested target node well enough.
To create multiple references at once:
client.AddReferences(
new OpcAddReference(
"ns=2;s=Plant01",
targetNodeId: "ns=2;s=Machines/MAC01",
targetNodeCategory: OpcNodeCategory.Object),
new OpcAddReference(
"ns=2;s=Plant01",
targetNodeId: "ns=2;s=Machines/MAC02",
targetNodeCategory: OpcNodeCategory.Object),
new OpcAddReference(
"ns=2;s=Plant02",
targetNodeId: "ns=2;s=Machines/MAC03",
targetNodeCategory: OpcNodeCategory.Object));client.AddReferences( _
New OpcAddReference( _
"ns=2;s=Plant01", _
targetNodeId:="ns=2;s=Machines/MAC01", _
targetNodeCategory:=OpcNodeCategory.Object), _
New OpcAddReference( _
"ns=2;s=Plant01", _
targetNodeId:="ns=2;s=Machines/MAC02", _
targetNodeCategory:=OpcNodeCategory.Object), _
New OpcAddReference( _
"ns=2;s=Plant02", _
targetNodeId:="ns=2;s=Machines/MAC03", _
targetNodeCategory:=OpcNodeCategory.Object))The example above also places three nodes below the nodes "Plant01" and "Plant02". Each of these nodes represents a machine and is located below the node "Machines". Because the default reference type is Organizes, the nodes remain available below "Machines". In addition, "MAC01" and "MAC02" appear below "Plant01", and "MAC03" appears below "Plant02".
Delete references
Types usedOpcClientOpcDeleteReferenceOpcStatusOpcStatusCollection
To delete existing references between nodes in the address space of the server, use the DeleteReferences interface of the server:
client.DeleteReference(
nodeId: "ns=2;s=Machines/MAC03",
targetNodeId: "ns=2;s=Plant");client.DeleteReference( _
nodeId:="ns=2;s=Machines/MAC03", _
targetNodeId:="ns=2;s=Plant")The example deletes all Organizes references between the nodes with the identifiers ns=2;s=Machines/MAC03 and ns=2;s=Plant, in both directions. To delete only the Organizes references in one direction, from the source node to the target node:
client.DeleteReference(
nodeId: "ns=2;s=Machines/MAC03",
targetNodeId: "ns=2;s=Plant",
direction: OpcReferenceDirection.ChildToParent);client.DeleteReference( _
nodeId:="ns=2;s=Machines/MAC03", _
targetNodeId:="ns=2;s=Plant", _
direction:=OpcReferenceDirection.ChildToParent)To delete references of a type other than Organizes, specify the type through the additional referenceType or referenceTypeId parameter:
client.DeleteReference(
nodeId: "ns=2;s=Machines/MAC03",
targetNodeId: "ns=2;s=Plant",
direction: OpcReferenceDirection.ChildToParent,
referenceType: OpcReferenceType.HierarchicalReferences);client.DeleteReference( _
nodeId:="ns=2;s=Machines/MAC03", _
targetNodeId:="ns=2;s=Plant", _
direction:=OpcReferenceDirection.ChildToParent, _
referenceType:=OpcReferenceType.HierarchicalReferences)To delete multiple references at once:
client.DeleteReferences(
new OpcDeleteReference("ns=2;s=Machines/MAC01", "ns=2;s=Plant01"),
new OpcDeleteReference("ns=2;s=Machines/MAC02", "ns=2;s=Plant01"),
new OpcDeleteReference("ns=2;s=Machines/MAC03", "ns=2;s=Plant02"));client.DeleteReferences( _
New OpcDeleteReference("ns=2;s=Machines/MAC01", "ns=2;s=Plant01"), _
New OpcDeleteReference("ns=2;s=Machines/MAC02", "ns=2;s=Plant01"), _
New OpcDeleteReference("ns=2;s=Machines/MAC03", "ns=2;s=Plant02"))
