Anleitung
Adressraum bearbeiten
Nodes und Verweise im Adressraum eines Servers vom Client aus erstellen und löschen.
Anleitung
Adressraum bearbeiten
Nodes anlegen
Beteiligte TypenOpcClientOpcAddNodeOpcAddNodeResultOpcAddNodeResultCollectionOpcAddDataItemNodeOpcAddAnalogItemNodeOpcAddObjectNodeOpcAddFolderNodeOpcAddDataVariableNodeOpcAddPropertyNode
Ein Server stellt seinen Clients einen vordefinierten Satz an Standard-Nodes bereit. Ein Client kann den Server veranlassen, weitere Nodes bereitzustellen. Dafür nutzt er die Schnittstelle AddNodes des Servers. Für typspezifische Nodes bietet das SDK zahlreiche Unterklassen der Klasse OpcAddNode. So legen Sie einen neuen Ordner-Node an:
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"))Die Parameter im Beispiel enthalten die mindestens nötigen Angaben. Der erste Parameter name legt den Namen (Eigenschaft Name, der BrowseName des Nodes) und den Anzeigenamen (Eigenschaft DisplayName) des Nodes fest. Eine Beschreibung legen Sie über die Eigenschaft Description fest. Der zweite Parameter nodeId gibt dem Server vor, welchen Identifier er dem Node zuweisen soll. Wenn ein anderer Node im Adressraum des Servers diesen Identifier bereits verwendet, legt der Server den Node nicht an. Ein mit dem SDK entwickelter Server liefert dann den Code BadNodeIdRejected, andere Server liefern unter Umständen BadNodeIdExists. Wenn Sie wie im Beispiel OpcNodeId.Null übergeben, erzeugt der Server selbst einen neuen Identifier und weist ihn dem Node zu. Der Parameter parentNodeId legt schließlich den Identifier des Eltern-Nodes fest, unter dem der Server den neuen Node im Baum anlegt. Wenn kein Eltern-Node angegeben ist, legt der Server den Node unterhalb des ObjectsFolder an.
Der Aufruf der Methode AddNode liefert eine Instanz der Klasse OpcAddNodeResult. Sie enthält neben dem Ausgang der Operation auch den Identifier, den der Server tatsächlich für den neuen Node verwendet hat:
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 IfSo legen Sie mehrere Nodes gleichzeitig an:
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))Der Aufruf der Methode AddNodes liefert eine Instanz der Klasse OpcAddNodeResultCollection. Sie enthält Instanzen von OpcAddNodeResult, die Sie wie oben beschrieben auswerten und weiterverarbeiten.
Den Methoden AddNode und AddNodes können Sie auch ganze Bäume von Nodes übergeben:
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"))))Einen solchen Baum können Sie auch über die zugehörigen Eigenschaften aufbauen:
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)Wenn Sie andere Typdefinitionen verwenden möchten als die der Unterklassen von OpcAddNode, legen Sie Objekt- und Variablen-Nodes anhand ihrer Typdefinition an:
client.AddObjectNode(OpcObjectType.DeviceFailureEventType, "FailureInfo");
client.AddVariableNode(OpcVariableType.XYArrayItem, "Coordinates");client.AddObjectNode(OpcObjectType.DeviceFailureEventType, "FailureInfo")
client.AddVariableNode(OpcVariableType.XYArrayItem, "Coordinates")Neben den von der Foundation definierten Typdefinitionen können Sie Nodes auch anhand des Identifiers ihrer Typdefinition anlegen. Dazu deklarieren Sie den Typ vorab über eine objekt- beziehungsweise variablenspezifische Typdefinition. OpcNodeId.Parse erzeugt den Identifier der Typdefinition aus seiner Zeichenfolge. Diesen Identifier verwenden Sie beliebig oft, um weitere Nodes dieses Typs zu erstellen:
// 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")))Nodes löschen
Beteiligte TypenOpcClientOpcDeleteNodeOpcStatusOpcStatusCollection
Über die Schnittstelle DeleteNodes des Servers löschen Sie sowohl vom Server bereitgestellte als auch von einem Client erstellte Nodes. Dafür benötigen Sie vor allem den Identifier des Nodes, den Sie löschen möchten:
OpcStatus result = client.DeleteNode("ns=2;s=Machine/Jobs");Dim result As OpcStatus = client.DeleteNode("ns=2;s=Machine/Jobs")Das Beispiel oben löscht mit einer Instanz der Klasse OpcDeleteNode. Sie löscht standardmäßig auch alle Verweise, die auf den Node zeigen. Wenn die Verweise auf den Node bestehen bleiben sollen, setzen Sie zusätzlich den Parameter includeTargetReferences auf 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)So löschen Sie mehrere Nodes gleichzeitig:
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"))Verweise anlegen
Beteiligte TypenOpcClientOpcAddReferenceOpcStatusOpcStatusCollection
Nodes im Adressraum eines Servers können unterschiedliche Beziehungen zueinander haben. Der Adressraum beschreibt diese Beziehungen über Verweise (engl. References). Neben der Einordnung als Eltern- oder Kind-Node können zwischen Nodes weitere logische Beziehungen bestehen. Diese Beziehungen beschreiben genauer, welche Funktion die Nodes haben und wie sie voneinander abhängen. Außerdem lassen sich über Verweise weitere Bäume im Adressraum des Servers definieren, ohne vorhandene Nodes neu zu organisieren.
Um einen Verweis anzulegen, nutzt der Client die Schnittstelle AddReferences des Servers:
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)Das Beispiel erzeugt einen Verweis vom Typ Organizes, der vom Node mit dem Identifier ns=2;s=Plant zum Node ns=2;s=Machines/MAC01 führt. Standardmäßig verwendet der Client den Verweistyp Organizes und die Richtung OpcReferenceDirection.ParentToChild. Bei dieser Richtung wird der erste Node zum Eltern-Node. Die Anweisung führt damit zum selben Ergebnis wie das folgende Beispiel:
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)Der erste Identifier gibt immer den Quell-Node an, der Parameter targetNodeId den Identifier des Ziel-Nodes. Mit der Richtung OpcReferenceDirection.ChildToParent legt der Client den Verweis stattdessen vom Ziel-Node zum Quell-Node an. Der zusätzliche Parameter targetNodeCategory muss der Eigenschaft Category des Ziel-Nodes entsprechen, in der Spezifikation die NodeClass. Anhand dieses Werts stellt der Server sicher, dass der gewünschte Ziel-Node ausreichend bekannt ist.
So legen Sie mehrere Verweise gleichzeitig an:
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))Das Beispiel oben ordnet drei Nodes zusätzlich unterhalb der Nodes „Plant01“ und „Plant02“ ein. Jeder dieser Nodes repräsentiert eine Maschine und liegt unterhalb des Nodes „Machines“. Durch den standardmäßig verwendeten Verweistyp Organizes bleiben die Nodes weiterhin unterhalb von „Machines“ verfügbar. Zusätzlich erscheinen „MAC01“ und „MAC02“ unterhalb von „Plant01“ und „MAC03“ unterhalb von „Plant02“.
Verweise löschen
Beteiligte TypenOpcClientOpcDeleteReferenceOpcStatusOpcStatusCollection
Bestehende Verweise zwischen Nodes im Adressraum des Servers löschen Sie über die Schnittstelle DeleteReferences des Servers:
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")Das Beispiel löscht alle Organizes-Verweise zwischen den Nodes mit den Identifiern ns=2;s=Machines/MAC03 und ns=2;s=Plant, und zwar in beiden Richtungen. So löschen Sie nur die Organizes-Verweise in einer bestimmten Richtung vom Quell- zum Ziel-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)Um Verweise eines anderen Typs als Organizes zu löschen, geben Sie den Typ über den zusätzlichen Parameter referenceType beziehungsweise referenceTypeId an:
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)So löschen Sie mehrere Verweise gleichzeitig:
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"))
