Introduction
The SimplexOPC UA Server SDK implements the common elements of the OPC UAspecification and provides APIs that allow users to add their ownfunctionality.
Create OPC UAserver
Class TOpcUaServer implements the functionalityof the OPC UA server. The record SpxServerConfig contains the OPC UA server parameters. For server-sidecallbacks, use the class inherited from SpxServerCallback.
An example of how to create OPC UA server:
...
uses SysUtils, Simplex.Server, Simplex.Types;
…
TSimplexServerTest =class(SpxServerCallback)
…
var OpcUaServer: TOpcUaServer;
ServerConfig: SpxServerConfig;
SimplexServerTest:TSimplexServerTest;
...
try
ServerConfig.EndpointUrl :='opc.tcp://localhost:4848';
ServerConfig.ApplicationInfo.ApplicationName := 'Simplex OPC UA ServerSDK';
ServerConfig.ApplicationInfo.ApplicationUri := 'urn:localhost:SimplexOPC UA:Server SDK';
ServerConfig.ApplicationInfo.ProductUri:= 'urn:Simplex OPC UA:Server SDK';
ServerConfig.ApplicationInfo.ManufacturerName := 'Simplex OPC UA';
ServerConfig.ApplicationInfo.SoftwareVersion := '1.0';
ServerConfig.ApplicationInfo.BuildNumber := '123';
ServerConfig.ApplicationInfo.BuildDate:= Now;
ServerConfig.TraceLevel := tlWarning;
ServerConfig.Callback :=SimplexServerTest;
OpcUaServer :=TOpcUaServer.Create(ServerConfig);
if (not OpcUaServer.Open()) then
begin
OpcUaServer.Free();
Writeln(Format('Error openOPC UA server, EndpointUrl=%s',
[ServerConfig.EndpointUrl]));
Exit;
end;
Writeln(Format('Open OPC UA server- OK, EndpointUrl=%s',
[ServerConfig.EndpointUrl]));
Writeln('Press Enter for close OPC UAserver ...');
Readln;
OpcUaServer.Free();
except
on E: Exception do
Writeln(E.ClassName, ': ',E.Message);
end;
Create namespace
Namespace is required to uniquely identify OPCUA server data. To create the namespace, use:
function TOpcUaServer.CreateNamespace(ANamespaceUri: SpxString): SpxUInt16;
An example of how to create namespace:
const Namespace ='http://www.simplexopcua.com/SimplexOpcUaServer';
var NamespaceIndex: Word;
…
NamespaceIndex := OpcUaServer.CreateNamespace(Namespace);
Create folder
Folders are necessary for hierarchicalorganization of data. To create the folder, use:
function TOpcUaServer.CreateFolder(ANodeId: SpxNodeId; ABrowseName: SpxString; ADisplayName,ADescription: SpxLocalizedText;AParentNodeId: SpxNodeId): SpxBoolean;
An example of how to create folder:
var FolderNodeId, ParentNodeId: SpxNodeId;
DisplayName, Description: SpxLocalizedText;
…
FolderNodeId.NamespaceIndex := NamespaceIndex;
FolderNodeId.IdentifierType := SpxIdentifierType_Numeric;
FolderNodeId.IdentifierString := 0;
ParentNodeId.NamespaceIndex := 0;
ParentNodeId.IdentifierType := SpxIdentifierType_Numeric;
ParentNodeId.IdentifierString := SpxNodeId_ObjectsFolder; // 85
DisplayName.Locale := 'en';
DisplayName.Text := 'MyFolder';
Description.Locale := 'en';
Description.Text := 'Folder for testing';
OpcUaServer.CreateFolder(FolderNodeId, 'MyFolder', DisplayName, Description, ParentNodeId);
Create variable ofinteger type
Variables provide real data. To create the variable, use:
function TOpcUaServer.CreateVariable(ANodeId:SpxNodeId; ABrowseName:SpxString;ADisplayName, ADescription: SpxLocalizedText;AParentNodeId: SpxNodeId; ADataType: SpxDataType;AAllowWrite,AAllowHistory: SpxBoolean): SpxBoolean;
An example of how to create variable ofinteger type:
var VarNodeId: SpxNodeId;
DisplayName, Description: SpxLocalizedText;
DataType: SpxDataType;
…
VarNodeId.NamespaceIndex := NamespaceIndex;
VarNodeId.IdentifierType := SpxIdentifierType_Numeric;
VarNodeId.IdentifierString := 1;
DisplayName.Locale := 'en';
DisplayName.Text := 'MyVarInt';
Description.Locale := 'en';
Description.Text := 'Integer variable for testing';
DataType.ValueRank := SpxValueRanks_Scalar;
DataType.BuiltInType := SpxType_Int32;
OpcUaServer.CreateVariable(VarNodeId,'MyVarInt', DisplayName,
Description, FolderNodeId,DataType, False, False);
To set the value of variable, use:
function TOpcUaServer.SetVariableValue(ANodeId: SpxNodeId; ADataValue: SpxDataValue): SpxBoolean;
An example of how to set the value ofvariable:
var DataValue: SpxDataValue;
…
DataValue.Value.ValueRank := SpxValueRanks_Scalar;
DataValue.Value.BuiltInType := SpxType_Int32;
DataValue.Value.AsInt32 := 12345;
DataValue.StatusCode := SpxStatusCode_Good;
DataValue.SourceTimestamp := Now;
DataValue.SourcePicoseconds := 0;
DataValue.ServerTimestamp := Now;
DataValue.ServerPicoseconds := 0;
OpcUaServer.SetVariableValue(VarNodeId, DataValue);
Create variable of string type
An example of how to create variable of string type:
var VarNodeId: SpxNodeId;
DisplayName, Description: SpxLocalizedText;
DataType: SpxDataType;
…
VarNodeId.NamespaceIndex := NamespaceIndex;
VarNodeId.IdentifierType := SpxIdentifierType_Numeric;
VarNodeId.IdentifierString := 2;
DisplayName.Locale := 'en';
DisplayName.Text := 'MyVarStr';
Description.Locale := 'en';
Description.Text := 'String variable for testing';
DataType.ValueRank := SpxValueRanks_Scalar;
DataType.BuiltInType := SpxType_String;
OpcUaServer.CreateVariable(VarNodeId,'MyVarStr',DisplayName,
Description, FolderNodeId,DataType, True,True);
An example of how to set the value of variable:
var DataValue: SpxDataValue;
…
DataValue.Value.ValueRank := SpxValueRanks_Scalar;
DataValue.Value.BuiltInType := SpxType_String;
DataValue.Value.AsString := 'value12345';
DataValue.StatusCode := SpxStatusCode_Good;
DataValue.SourceTimestamp := Now;
DataValue.SourcePicoseconds := 0;
DataValue.ServerTimestamp := Now;
DataValue.ServerPicoseconds := 0;
OpcUaServer.SetVariableValue(VarNodeId, DataValue);
Createvariable of enumeration type
An enumeration type provides an efficient way to define a set ofstrings that may be assigned to a variable.
An example of how to create an enumeration type:
vat TypeNodeId: SpxNodeId;
EnumStrings: SpxLocalizedTextArray;
DisplayName, Description: SpxLocalizedText;
i: integer;
…
TypeNodeId.NamespaceIndex := NamespaceIndex;
TypeNodeId.IdentifierType :=SpxIdentifierType_Numeric;
TypeNodeId.IdentifierString := 3;
SetLength(EnumStrings, 3);
for i := Low(EnumStrings) to High(EnumStrings) do
begin
EnumStrings[i].Locale := 'en';
EnumStrings[i].Text :=Format('Value%d', [i]);
end;
DisplayName.Locale:= 'en';
DisplayName.Text := 'MyEnumStringsType';
Description.Locale := 'en';
Description.Text := 'Enum strings type for testing';
OpcUaServer.CreateEnumVariableType(TypeNodeId, 'MyEnumStringsType', DisplayName,Description, EnumStrings);
An example of how to create variable of enumeration type:
var VarNodeId: SpxNodeId;
DataType: SpxDataType;
DisplayName, Description: SpxLocalizedText;
…
VarNodeId.NamespaceIndex := NamespaceIndex;
VarNodeId.IdentifierType :=SpxIdentifierType_Numeric;
VarNodeId.IdentifierString := 4;
DisplayName.Locale := 'en';
DisplayName.Text := 'MyEnumStrings';
Description.Locale := 'en';
Description.Text := 'Enumerated variable for testing';
DataType.ValueRank := SpxValueRanks_Scalar;
DataType.BuiltInType := SpxType_Enumeration;
DataType.EnumTypeNodeId := TypeNodeId;
OpcUaServer.CreateVariable(VarNodeId,'MyEnumStrings', DisplayName, Description, FolderNodeId, DataType, True,False);
Createvariable of enumeration type with values
An example of how to create an enumeration type with values:
var TypeNodeId: SpxNodeId;
EnumValues: SpxEnumValues;
DisplayName, Description: SpxLocalizedText;
i: integer;
…
TypeNodeId.NamespaceIndex := NamespaceIndex;
TypeNodeId.IdentifierType := SpxIdentifierType_Numeric;
TypeNodeId.IdentifierString := 5;
SetLength(EnumValues, 3);
for i := Low(EnumValues) to High(EnumValues) do
begin
EnumValues[i].Value := i * 2;
EnumValues[i].Name.Locale := 'en';
EnumValues[i].Name.Text :=Format('Value%d', [i]);
EnumValues[i].Description.Locale :='en';
EnumValues[i].Description.Text:= Format('Value%d', [i]);
end;
DisplayName.Locale := 'en';
DisplayName.Text := 'MyEnumValuesType';
Description.Locale := 'en';
Description.Text := 'Enum values type for testing';
OpcUaServer.CreateEnumVariableType(TypeNodeId, 'MyEnumValuesType', DisplayName, Description,EnumValues);
An example of how to create variable of enumeration type with values:
var VarNodeId: SpxNodeId;
DataType: SpxDataType;
DisplayName, Description: SpxLocalizedText;
...
VarNodeId.NamespaceIndex := NamespaceIndex;
VarNodeId.IdentifierType := SpxIdentifierType_Numeric;
VarNodeId.IdentifierString := 6;
DisplayName.Locale := 'en';
DisplayName.Text := 'MyEnumValues';
Description.Locale := 'en';
Description.Text := 'Enumerated variable with values for testing';
DataType.ValueRank := SpxValueRanks_Scalar;
DataType.BuiltInType := SpxType_Enumeration;
DataType.EnumTypeNodeId := TypeNodeId;
OpcUaServer.CreateVariable(VarNodeId,'MyEnumValues', DisplayName, Description,FolderNodeId,DataType, True, False);
Create method
Methods are “lightweight” functions, whosescope is bounded by an owning Object, similar to the methods of a class inobject-oriented programming or an owning ObjectType, similar to static methodsof a class. Methods are invoked by a client, proceed to completion on theServer and return the result to the client. The lifetime of the Method’sinvocation instance begins when the client calls the Method and ends when theresult is returned.
To create the method, use:
function TOpcUaServer.CreateMethod(ANodeId:SpxNodeId; ABrowseName: SpxString; ADisplayName, ADescription:SpxLocalizedText; AParentNodeId: SpxNodeId; AInputArguments, AOutputArguments:SpxArguments): SpxBoolean;
An example of how to create method:
var VarNodeId: SpxNodeId;
DisplayName, Description: SpxLocalizedText;
InputArguments, OutputArguments: SpxArguments;
…
VarNodeId.NamespaceIndex := NamespaceIndex;
VarNodeId.IdentifierType := SpxIdentifierType_Numeric;
VarNodeId.IdentifierString := 7;
DisplayName.Locale := 'en';
DisplayName.Text := 'MyMethod';
Description.Locale := 'en';
Description.Text := 'Method for testing';
SetLength(InputArguments, 2);
for i := 0 to Length(InputArguments)-1 do
begin
InputArguments[i].Name :=Format('Argument%d', [i]);
InputArguments[i].Description.Locale := 'en';
InputArguments[i].Description.Text :=Format('Argument %d for testing', [i]);
InputArguments[i].DataType.ValueRank:= SpxValueRanks_Scalar;
InputArguments[i].DataType.BuiltInType:= SpxType_String;
end;
SetLength(OutputArguments, 1);
OutputArguments[0].Name := 'OutArgument1';
OutputArguments[0].Description.Locale := 'en';
OutputArguments[0].Description.Text := 'Output argument fortesting';
OutputArguments[0].DataType.ValueRank := SpxValueRanks_Scalar;
OutputArguments[0].DataType.BuiltInType := SpxType_String;
OpcUaServer.CreateMethod(VarNodeId,'MyMethod', DisplayName, Description, FolderNodeId, InputArguments,OutputArguments);
Change node
The node can be changed. Youcan change the following properties: BrowseName, DisplayName,Description, DataType, AllowWrite, AllowHistory.
To change the node, use:
function TOpcUaServer.ChangeNode(ANodeId: SpxNodeId; AChangeNodeParams:SpxChangeNodeParams): SpxBoolean;
An example of how to change node:
var ChangeNodeParams: SpxChangeNodeParams;
...
ChangeNodeParams.ChangeType :=spxChange_DisplayName;
ChangeNodeParams.DisplayName.Locale := 'en';
ChangeNodeParams.DisplayName.Text :='MyMethod123';
OpcUaServer.ChangeNode(VarNodeId,ChangeNodeParams);
Delete node
The node can be deleted. To delete the node, use:
function TOpcUaServer.DeleteNode(ANodeId: SpxNodeId): SpxBoolean;
An example of how to delete node:
OpcUaServer.DeleteNode(VarNodeId);