Introduction

The Simplex OPC UA Server SDK implements the common elements of the OPC UA specification and provides APIs that allow users to add their own functionality.


Create OPC UA server

Class TOpcUaServer implements the functionality of the OPC UA server. The record  SpxServerConfig contains the OPC UA server parameters. For server-side callbacks, 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 Server SDK';
    ServerConfig.ApplicationInfo.ApplicationUri := 'urn:localhost:Simplex OPC 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 open OPC 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 UA server ...');
      Readln;

      OpcUaServer.Free();
  except
      on E: Exception do
          Writeln(E.ClassName, ': ', E.Message);
  end;


Create namespace

Namespace is required to uniquely identify OPC UA 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 hierarchical organization 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 of integer 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 of integer 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 of variable:

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);

 

Create variable of enumeration type

An enumeration type provides an efficient way to define a set of strings 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);

 

Create variable 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, whose scope is bounded by an owning Object, similar to the methods of a class in object-oriented programming or an owning ObjectType, similar to static methods of a class. Methods are invoked by a client, proceed to completion on the Server and return the result to the client. The lifetime of the Method’s invocation instance begins when the client calls the Method and ends when the result 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 for testing';
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. You can 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);