Anleitung
Datentypen zur Laufzeit
Strukturen und Enumerationen erst zur Laufzeit definieren, im Adressraum veröffentlichen und ihre Werte ohne eigene .NET-Typen bereitstellen.
Anleitung
Datentypen zur Laufzeit
Beteiligte TypenOpcServerOpcStructOpcStructFieldOpcEnumOpcEnumFieldOpcDataTypeNodeOpcDataObject
Benutzerdefinierte Datentypen legen Sie üblicherweise über .NET-Typen und Attribute fest. Das beschreibt der Abschnitt Datentypen bereitstellen. Wenn die Datentypen erst zur Laufzeit feststehen, zum Beispiel weil sie aus einer Konfiguration oder einer angebundenen Steuerung stammen, definieren Sie sie stattdessen über die Klassen OpcStruct (Strukturen) und OpcEnum (Enumerationen). Die Werte solcher Datentypen stellt der Server als Instanzen von OpcDataObject bereit, ganz ohne eigene .NET-Typen.
Dynamische Datentypen aktivieren
Damit der Server Werte dynamisch definierter Datentypen kodieren kann, aktivieren Sie die Eigenschaft UseDynamic des Servers. Standardmäßig bestimmt sie OpcAutomatism.UseDynamic, das deaktiviert ist:
server.UseDynamic = true;server.UseDynamic = TrueStrukturen definieren
Eine Struktur definieren Sie über die Methode DefineType der Klasse OpcStruct. Sie erhält die OpcNodeId und den Namen des Datentyps sowie seine Felder als Instanzen von OpcStructField. Jedes Feld besteht aus seinem Namen, der OpcNodeId seines Datentyps (zum Beispiel aus der Klasse OpcDataTypes) und optional einer Beschreibung. Die Methode AsArray macht ein Feld zum Array, die Methode AsOptional zu einem optionalen Feld:
var machineDataTypeId = new OpcNodeId("MachineData", namespaceIndex: 2);
var machineDataType = OpcStruct.DefineType(
machineDataTypeId,
new OpcName("MachineData", namespaceIndex: 2),
new OpcStructField("Speed", OpcDataTypes.Int32),
new OpcStructField("JobName", OpcDataTypes.String),
new OpcStructField("Temperatures", OpcDataTypes.Double).AsArray(),
new OpcStructField("Comment", OpcDataTypes.String, description: "Optional comment.")
.AsOptional());Dim machineDataTypeId = New OpcNodeId("MachineData", namespaceIndex:=2)
Dim machineDataType = OpcStruct.DefineType( _
machineDataTypeId, _
New OpcName("MachineData", namespaceIndex:=2), _
New OpcStructField("Speed", OpcDataTypes.Int32), _
New OpcStructField("JobName", OpcDataTypes.String), _
New OpcStructField("Temperatures", OpcDataTypes.Double).AsArray(), _
New OpcStructField("Comment", OpcDataTypes.String, description:="Optional comment.") _
.AsOptional())Wenn eine Struktur eine andere erweitern soll, definieren Sie sie über die Methode DefineSubType und geben den Basistyp an:
var extendedDataType = OpcStruct.DefineSubType(
machineDataTypeId,
new OpcNodeId("ExtendedMachineData", namespaceIndex: 2),
new OpcName("ExtendedMachineData", namespaceIndex: 2),
new OpcStructField("Operator", OpcDataTypes.String));Dim extendedDataType = OpcStruct.DefineSubType( _
machineDataTypeId, _
New OpcNodeId("ExtendedMachineData", namespaceIndex:=2), _
New OpcName("ExtendedMachineData", namespaceIndex:=2), _
New OpcStructField("Operator", OpcDataTypes.String))Enumerationen definieren
Eine Enumeration definieren Sie über die Klasse OpcEnum, und zwar auf eine von zwei Arten:
- über die Methode
DefineStringsals Liste von Namen (EnumStrings). Der Wert eines Eintrags ist sein Index. - über die Methode
DefineValuesals Liste von Name-Wert-Paaren (EnumValues). Die Werte müssen nicht fortlaufend sein, und jeder Eintrag kann eine Beschreibung erhalten.
var jobKindId = new OpcNodeId("JobKind", namespaceIndex: 2);
var jobKind = OpcEnum.DefineStrings(
jobKindId,
new OpcName("JobKind", namespaceIndex: 2),
new OpcEnumField("Production"),
new OpcEnumField("Maintenance"));
var errorCode = OpcEnum.DefineValues(
new OpcNodeId("ErrorCode", namespaceIndex: 2),
new OpcName("ErrorCode", namespaceIndex: 2),
new OpcEnumField("None", value: 0),
new OpcEnumField("Overheated", value: 10, description: "The temperature exceeded the limit."),
new OpcEnumField("OutOfMaterial", value: 20, description: "The material supply is empty."));Dim jobKindId = New OpcNodeId("JobKind", namespaceIndex:=2)
Dim jobKind = OpcEnum.DefineStrings( _
jobKindId, _
New OpcName("JobKind", namespaceIndex:=2), _
New OpcEnumField("Production"), _
New OpcEnumField("Maintenance"))
Dim errorCode = OpcEnum.DefineValues( _
New OpcNodeId("ErrorCode", namespaceIndex:=2), _
New OpcName("ErrorCode", namespaceIndex:=2), _
New OpcEnumField("None", value:=0), _
New OpcEnumField("Overheated", value:=10, description:="The temperature exceeded the limit."), _
New OpcEnumField("OutOfMaterial", value:=20, description:="The material supply is empty."))Variablen mit dynamischen Datentypen anlegen
Variablen, die einen dynamisch definierten Datentyp verwenden, legen Sie wie gewohnt im Node-Manager an. Ihren Datentyp legt die Eigenschaft DataTypeId fest:
// MyNodeManager.CreateNodes(...)
var machineDataNode = new OpcDataVariableNode(machineNode, "Data");
machineDataNode.DataTypeId = machineDataTypeId;
var jobKindNode = new OpcDataVariableNode(machineNode, "JobKind");
jobKindNode.DataTypeId = jobKindId;'MyNodeManager.CreateNodes(...)
Dim machineDataNode = New OpcDataVariableNode(machineNode, "Data")
machineDataNode.DataTypeId = machineDataTypeId
Dim jobKindNode = New OpcDataVariableNode(machineNode, "JobKind")
jobKindNode.DataTypeId = jobKindIdDatentypen veröffentlichen
Der Server veröffentlicht die Datentypen über Datentyp-Nodes. Diese Nodes erzeugt die Methode Create der Klasse OpcDataTypeNode aus der jeweiligen Definition. Weil der Server zum Erzeugen dieser Nodes die Datentypen der Felder auflöst, fügen Sie sie erst nach dem Start des Servers über die Methode AddNode des Node-Managers hinzu:
server.Start();
// The data type nodes are added after the server has been started.
nodeManager.AddNode(OpcDataTypeNode.Create(machineDataType));
nodeManager.AddNode(OpcDataTypeNode.Create(jobKind));
nodeManager.AddNode(OpcDataTypeNode.Create(errorCode));server.Start()
'The data type nodes are added after the server has been started.
nodeManager.AddNode(OpcDataTypeNode.Create(machineDataType))
nodeManager.AddNode(OpcDataTypeNode.Create(jobKind))
nodeManager.AddNode(OpcDataTypeNode.Create(errorCode))Werte bereitstellen
Einen Wert einer Struktur erzeugen Sie als OpcDataObject. Den dazu benötigten Datentyp liefert die Methode GetDataType des Servers, sobald der Datentyp-Node veröffentlicht ist. Die Felder sprechen Sie über ihren Namen an. Optionale Felder, denen Sie keinen Wert zuweisen, bleiben leer. Der Wert einer Enumeration ist eine Zahl: bei EnumStrings der Index, bei EnumValues der Wert des Eintrags:
var dataType = server.GetDataType(machineDataTypeId);
var data = new OpcDataObject(dataType);
data["Speed"].Value = 1200;
data["JobName"].Value = "JOB0815";
data["Temperatures"].Value = new double[] { 20.5, 21.0, 21.3 };
machineDataNode.Value = data;
machineDataNode.ApplyChanges(server.SystemContext);
// Enumeration values are numbers (index or value of the field), here: Maintenance.
jobKindNode.Value = 1;
jobKindNode.ApplyChanges(server.SystemContext);Dim dataType = server.GetDataType(machineDataTypeId)
Dim data = New OpcDataObject(dataType)
data("Speed").Value = 1200
data("JobName").Value = "JOB0815"
data("Temperatures").Value = New Double() {20.5, 21.0, 21.3}
machineDataNode.Value = data
machineDataNode.ApplyChanges(server.SystemContext)
'Enumeration values are numbers (index or value of the field), here: Maintenance.
jobKindNode.Value = 1
jobKindNode.ApplyChanges(server.SystemContext)Ein Client, der die Datentypen des Servers zur Laufzeit auflöst (zum Beispiel über OpcClient.UseDynamic), erhält die Werte der Struktur ebenfalls als OpcDataObject. Das beschreibt die Seite Strukturierte Daten.

