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