The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

OPCUA::Open62541 - Perl XS wrapper for open62541 OPC UA library

SYNOPSIS

  use OPCUA::Open62541;

  my $server = OPCUA::Open62541::Server->new();

  my $client = OPCUA::Open62541::Client->new();

DESCRIPTION

The open62541 is a library implementing an OPC UA client and server. This module provides access to the C functionality from Perl programs.

EXPORT

Refer to OPCUA::Open62541::Constant module about the exported values.

METHODS

Refer to the open62541 documentation for the semantic of classes and methods.

Variant

$variant = OPCUA::Open62541::Variant->new()
$boolean = $variant->isEmpty()
$boolean = $variant->isScalar()
$boolean = $variant->hasScalarType($data_type)
$boolean = $variant->hasArrayType($data_type)
$variant->setScalar($p, $data_type)
$data_type = $variant->getType()
$p = $variant->getScalar()

Server

$server = OPCUA::Open62541::Server->new()
$server_config = $server->getConfig()
$status_code = $server->run($server, $running)

$running should be TRUE at startup. When set to FALSE during method invocation, the server stops magically.

$status_code = $server->run_startup($server)
$wait_ms = $server->run_iterate($server, $wait_internal)
$status_code = $server->run_shutdown($server)
\%dataValue = $server->read(\%item, $timestamps)
$status_code = $server->readAccessLevel(\%nodeId, \$outByte)
$status_code = $server->readArrayDimensions(\%nodeId, \$outVariant)
$status_code = $server->readBrowseName(\%nodeId, \$outQualifiedName)
$status_code = $server->readContainsNoLoops(\%nodeId, \$outBoolean)
$status_code = $server->readDataType(\%nodeId, \$outDataType)
$status_code = $server->readDescription(\%nodeId, \$outLocalizedText)
$status_code = $server->readDisplayName(\%nodeId, \$outLocalizedText)
$status_code = $server->readEventNotifier(\%nodeId, \$outByte)
$status_code = $server->readExecutable(\%nodeId, \$outBoolean)
$status_code = $server->readHistorizing(\%nodeId, \$outBoolean)
$status_code = $server->readInverseName(\%nodeId, \$outLocalizedText)
$status_code = $server->readIsAbstract(\%nodeId, \$outBoolean)
$status_code = $server->readMinimumSamplingInterval(\%nodeId, \$outDouble)
$status_code = $server->readNodeClass(\%nodeId, \$outNodeClass)
$status_code = $server->readNodeId(\%nodeId, \$outNodeId)
$status_code = $server->readObjectProperty(\%nodeId, \%propertyName, \$outVariant)
$status_code = $server->readSymmetric(\%nodeId, \$outBoolean)
$status_code = $server->readValue(\%nodeId, \$outVariant)
$status_code = $server->readValueRank(\%nodeId, \$outInt32)
$status_code = $server->readWriteMask(\%nodeId, \$outUInt32)
$status_code = $server->write(\%value)
$status_code = $server->writeAccessLevel(\%nodeId, $newByte)
$status_code = $server->writeArrayDimensions(\%nodeId, \%newVariant)
$status_code = $server->writeDataType(\%nodeId, $newDataType)
$status_code = $server->writeDescription(\%nodeId, \%newLocalizedText)
$status_code = $server->writeDisplayName(\%nodeId, \%newLocalizedText)
$status_code = $server->writeEventNotifier(\%nodeId, $newByte)
$status_code = $server->writeExecutable(\%nodeId, $newBoolean)
$status_code = $server->writeHistorizing(\%nodeId, $newBoolean)
$status_code = $server->writeInverseName(\%nodeId, \%newLocalizedText)
$status_code = $server->writeIsAbstract(\%nodeId, $newBoolean)
$status_code = $server->writeMinimumSamplingInterval(\%nodeId, $newDouble)
$status_code = $server->writeObjectProperty(\%nodeId, \%propertyName, \%newVariant)
$status_code = $server->writeValue(\%nodeId, \%newVariant)
$status_code = $server->writeValueRank(\%nodeId, $newInt32)
$status_code = $server->writeWriteMask(\%nodeId, $newUInt32)
\%browseResult = $server->browse($maxReferences, \%browseDescription)
\%browseResult = $server->browseNext($releaseContinuationPoint, $continuationPoint)
$server->setAdminSessionContext($context)

This method is only available if open62541 library supports it.

$status_code = $server->addVariableNode(\%requestedNewNodeId, \%parentNodeId, \%referenceTypeId, \%browseName, \%typeDefinition, \%attr, $nodeContext, \%outNewNodeId)
$status_code = $server->addVariableTypeNode(\%requestedNewNodeId, \%parentNodeId, \%referenceTypeId, \%browseName, \%typeDefinition, \%attr, $nodeContext, \%outNewNodeId)
$status_code = $server->addObjectNode(\%requestedNewNodeId, \%parentNodeId, \%referenceTypeId, \%browseName, \%typeDefinition, \%attr, $nodeContext, \%outNewNodeId)
$status_code = $server->addObjectTypeNode(\%requestedNewNodeId, \%parentNodeId, \%referenceTypeId, \%browseName, \%attr, $nodeContext, \%outNewNodeId)
$status_code = $server->addViewNode(\%requestedNewNodeId, \%parentNodeId, \%referenceTypeId, \%browseName, \%attr, $nodeContext, \%outNewNodeId)
$status_code = $server->addReferenceTypeNode(\%requestedNewNodeId, \%parentNodeId, \%referenceTypeId, \%browseName, \%attr, $nodeContext, \%outNewNodeId)
$status_code = $server->addDataTypeNode(\%requestedNewNodeId, \%parentNodeId, \%referenceTypeId, \%browseName, \%attr, $nodeContext, \%outNewNodeId)
$status_code = $server->deleteNode(\%nodeId, $deleteReferences)
$status_code = $server->addReference(\%sourceId, \%refTypeId, \%targetId, $isForward)
$status_code = $server->deleteReference(\%sourceNodeId, \%referenceTypeId, $isForward, \%targetNodeId, $deleteBidirectional)
$namespace_index = $server->addNamespace($namespace_name)

ServerConfig

$status_code = $server_config->setDefault()
$status_code = $server_config->setMinimal($port, $certificate)
$server_config->setCustomHostname($custom_hostname)
$server_config->setGlobalNodeLifecycle(\%lifecycle)
$lifecycle{GlobalNodeLifecycle_constructor} = sub { my ($server, $sessionId, $sessionContext, $nodeId, \$nodeContext) = @_ }
$lifecycle{GlobalNodeLifecycle_destructor} = sub { my ($server, $sessionId, $sessionContext, $nodeId, $nodeContext) = @_ }
$lifecycle{GlobalNodeLifecycle_createOptionalChild} = sub { my ($server, $sessionId, $sessionContext, $sourceNodeId, $targetParentNodeId, $referenceTypeId) = @_ }
$lifecycle{GlobalNodeLifecycle_generateChildNodeId} = sub { my ($server, $sessionId, $sessionContext, $sourceNodeId, $targetParentNodeId, $referenceTypeId, \%targetNodeId) = @_ }

Call $server->setAdminSessionContext() to set $server and $sessionContext in the callback.

$logger = $server_config->getLogger()
$buildinfo = $server_config->getBuildInfo()
$server_config->setBuildInfo(\%buildInfo)
$limit = $server_config->getMaxSecureChannels()
$server_config->setMaxSecureChannels($maxSecureChannels)
$limit = $server_config->getMaxSessions()
$server_config->setMaxSessions($maxSessions)
$limit = $server_config->getMaxSessionTimeout()
$server_config->setMaxSessionTimeout($maxSessionTimeout)
$limit = $server_config->getMaxNodesPerRead()
$server_config->setMaxNodesPerRead($maxNodesPerRead)
$limit = $server_config->getMaxNodesPerWrite()
$server_config->setMaxNodesPerWrite($maxNodesPerWrite)
$limit = $server_config->getMaxNodesPerMethodCall()
$server_config->setMaxNodesPerMethodCall($maxNodesPerMethodCall)
$limit = $server_config->getMaxNodesPerBrowse()
$server_config->setMaxNodesPerBrowse($maxNodesPerBrowse)
$limit = $server_config->getMaxNodesPerRegisterNodes()
$server_config->setMaxNodesPerRegisterNodes($maxNodesPerRegisterNodes)
$limit = $server_config->getMaxNodesPerTranslateBrowsePathsToNodeIds()
$server_config->setMaxNodesPerTranslateBrowsePathsToNodeIds($maxNodesPerTranslateBrowsePathsToNodeIds)
$limit = $server_config->getMaxNodesPerNodeManagement()
$server_config->setMaxNodesPerNodeManagement($maxNodesPerNodeManagement)
$limit = $server_config->getMaxMonitoredItemsPerCall()
$server_config->setMaxMonitoredItemsPerCall($maxMonitoredItemsPerCall)
$server_config->setUserRightsMaskReadonly($readonly)

If $readonly is set to true, only reading of attributes is allowed. If set to false, no additional restrictions on the UserWriteMask are made and attributes will also be writable (this is the default behaviour). Values of variable nodes are excluded from the UserWriteMask and are handled by the AccessLevel instead (see setUserAccessLevelReadonly()).

$server_config->setUserAccessLevelReadonly($readonly)

If $readonly is set to true, only reading of variable values is allowed (including reading historical data of values). If set to false, no additional restrictions on the AccessLevel are made and values will also be writable (this is the default behaviour).

$server_config->disableUserExecutable($disable)

If $disable is set to true, method nodes will not be shown as executable for users (UserExecutable attribute of the method node). If set to false, no addtional restrictions are made on the UserExecutable attribute of method nodes (this is the default).

$server_config->disableUserExecutableOnObject($disable)

If $disable is set to true, methods can not be executed. If set to false, no addtional restrictions are made on the execution of methods (this is the default).

$server_config->disableAddNode($disable)

If $disable is set to true, nodes can not be added. If set to false, nodes can be added (this is the default).

$server_config->disableAddReference($disable)

If $disable is set to true, references can not be added. If set to false, references can be added (this is the default).

$server_config->disableDeleteNode($disable)

If $disable is set to true, nodes can not be deleted. If set to false, nodes can be deleted (this is the default).

$server_config->disableDeleteReference($disable)

If $disable is set to true, references can not be deleted. If set to false, references can be deleted (this is the default).

$server_config->disableHistoryUpdateUpdateData($disable)

If $disable is set to true, historical data may not be inserted, replaced or updated. If set to false, no addtional restrictions are made on the modification of historical data (this is the default).

$server_config->disableHistoryUpdateDeleteRawModified($disable)

If $disable is set to true, historical data may not be deleted. If set to false, historical data can be deleted (this is the default).

Client

$client = OPCUA::Open62541::Client->new()
$client_config = $client->getConfig()
$status_code = $client->connect($url)
$status_code = $client->connect_async($endpointUrl, $callback, $userdata)
$callback = sub { my ($client, $userdata, $requestId, $status_code) = @_ }

There should be an interval of 100ms between the call to connect_async() and run_iterate() or open62541 may try to operate on a non existent socket.

$status_code = $client->run_iterate($timeout)
$status_code = $client->disconnect()
$status_code = $client->disconnect_async(\$requestId)
$client_state = $client->getState()
$status_code = $client->sendAsyncBrowseRequest(\%request, \&callback, $data, \$reqId)
$callback = sub { my ($client, $userdata, $requestId, \%response) = @_ }
$status_code = $client->sendAsyncBrowseNextRequest(\%request, \&callback, $data, \$reqId)
$callback = sub { my ($client, $userdata, $requestId, \%response) = @_ }
$response = $client->Service_browse(\%request)
$status_code = $client->readAccessLevelAttribute(\%nodeId, \$outByte)
$status_code = $client->readBrowseNameAttribute(\%nodeId, \$outQualifiedName)
$status_code = $client->readContainsNoLoopsAttribute(\%nodeId, \$outBoolean)
$status_code = $client->readDataTypeAttribute(\%nodeId, \$outDataType)
$status_code = $client->readDescriptionAttribute(\%nodeId, \$outLocalizedText)
$status_code = $client->readDisplayNameAttribute(\%nodeId, \$outLocalizedText)
$status_code = $client->readEventNotifierAttribute(\%nodeId, \$outByte)
$status_code = $client->readExecutableAttribute(\%nodeId, \$outBoolean)
$status_code = $client->readHistorizingAttribute(\%nodeId, \$outBoolean)
$status_code = $client->readInverseNameAttribute(\%nodeId, \$outLocalizedText)
$status_code = $client->readIsAbstractAttribute(\%nodeId, \$outBoolean)
$status_code = $client->readMinimumSamplingIntervalAttribute(\%nodeId, \$outDouble)
$status_code = $client->readNodeClassAttribute(\%nodeId, \$outNodeClass)
$status_code = $client->readNodeIdAttribute(\%nodeId, \$outNodeId)
$status_code = $client->readSymmetricAttribute(\%nodeId, \$outBoolean)
$status_code = $client->readUserAccessLevelAttribute(\%nodeId, \$outByte)
$status_code = $client->readUserExecutableAttribute(\%nodeId, \$outBoolean)
$status_code = $client->readUserWriteMaskAttribute(\%nodeId, \$outUInt32)
$status_code = $client->readValueAttribute(\%nodeId, \$outVariant)
$status_code = $client->readValueRankAttribute(\%nodeId, \$outInt32)
$status_code = $client->readWriteMaskAttribute(\%nodeId, \$outUInt32)
$status_code = $client->sendAsyncReadRequest(\%request, \&callback, \$data, \$reqId)
$callback = sub { my ($client, $userdata, $requestId, \%response) = @_ }
$status_code = $client->readAccessLevelAttribute_async(\%nodeId, \&callback, \$data, \$reqId)
$callback = sub { my ($client, $userdata, $requestId, $byte) = @_ }
$status_code = $client->readBrowseNameAttribute_async(\%nodeId, \&callback, \$data, \$reqId)
$callback = sub { my ($client, $userdata, $requestId, \%qualifiedName) = @_ }
$status_code = $client->readContainsNoLoopsAttribute_async(\%nodeId, \&callback, \$data, \$reqId)
$callback = sub { my ($client, $userdata, $requestId, $boolean) = @_ }
$status_code = $client->readDataTypeAttribute_async(\%nodeId, \&callback, \$data, \$reqId)
$callback = sub { my ($client, $userdata, $requestId, $dataType) = @_ }
$status_code = $client->readDescriptionAttribute_async(\%nodeId, \&callback, \$data, \$reqId)
$callback = sub { my ($client, $userdata, $requestId, \%localizedText) = @_ }
$status_code = $client->readDisplayNameAttribute_async(\%nodeId, \&callback, \$data, \$reqId)
$callback = sub { my ($client, $userdata, $requestId, \%localizedText) = @_ }
$status_code = $client->readEventNotifierAttribute_async(\%nodeId, \&callback, \$data, \$reqId)
$callback = sub { my ($client, $userdata, $requestId, $byte) = @_ }
$status_code = $client->readExecutableAttribute_async(\%nodeId, \&callback, \$data, \$reqId)
$callback = sub { my ($client, $userdata, $requestId, $boolean) = @_ }
$status_code = $client->readHistorizingAttribute_async(\%nodeId, \&callback, \$data, \$reqId)
$callback = sub { my ($client, $userdata, $requestId, $boolean) = @_ }
$status_code = $client->readInverseNameAttribute_async(\%nodeId, \&callback, \$data, \$reqId)
$callback = sub { my ($client, $userdata, $requestId, \%localizedText) = @_ }
$status_code = $client->readIsAbstractAttribute_async(\%nodeId, \&callback, \$data, \$reqId)
$callback = sub { my ($client, $userdata, $requestId, $boolean) = @_ }
$status_code = $client->readMinimumSamplingIntervalAttribute_async(\%nodeId, \&callback, \$data, \$reqId)
$callback = sub { my ($client, $userdata, $requestId, $double) = @_ }
$status_code = $client->readNodeClassAttribute_async(\%nodeId, \&callback, \$data, \$reqId)
$callback = sub { my ($client, $userdata, $requestId, $nodeClass) = @_ }
$status_code = $client->readNodeIdAttribute_async(\%nodeId, \&callback, \$data, \$reqId)
$callback = sub { my ($client, $userdata, $requestId, \%nodeId) = @_ }
$status_code = $client->readSymmetricAttribute_async(\%nodeId, \&callback, \$data, \$reqId)
$callback = sub { my ($client, $userdata, $requestId, $boolean) = @_ }
$status_code = $client->readUserAccessLevelAttribute_async(\%nodeId, \&callback, \$data, \$reqId)
$callback = sub { my ($client, $userdata, $requestId, $byte) = @_ }
$status_code = $client->readUserExecutableAttribute_async(\%nodeId, \&callback, \$data, \$reqId)
$callback = sub { my ($client, $userdata, $requestId, $boolean) = @_ }
$status_code = $client->readUserWriteMaskAttribute_async(\%nodeId, \&callback, \$data, \$reqId)
$callback = sub { my ($client, $userdata, $requestId, $uint32) = @_ }
$status_code = $client->readValueAttribute_async(\%nodeId, \&callback, \$data, \$reqId)
$callback = sub { my ($client, $userdata, $requestId, \%variant) = @_ }
$status_code = $client->readValueRankAttribute_async(\%nodeId, \&callback, \$data, \$reqId)
$callback = sub { my ($client, $userdata, $requestId, $int32) = @_ }
$status_code = $client->readWriteMaskAttribute_async(\%nodeId, \&callback, \$data, \$reqId)
$callback = sub { my ($client, $userdata, $requestId, $uint32) = @_ }
$status_code = $client->writeAccessLevelAttribute(\%nodeId, $newByte)
$status_code = $client->writeBrowseNameAttribute(\%nodeId, \%newQualifiedName)
$status_code = $client->writeContainsNoLoopsAttribute(\%nodeId, $outBoolean)
$status_code = $client->writeDataTypeAttribute(\%nodeId, $newDataType)
$status_code = $client->writeDescriptionAttribute(\%nodeId, \%newLocalizedText)
$status_code = $client->writeDisplayNameAttribute(\%nodeId, \%newLocalizedText)
$status_code = $client->writeEventNotifierAttribute(\%nodeId, $newByte)
$status_code = $client->writeExecutableAttribute(\%nodeId, $newBoolean)
$status_code = $client->writeHistorizingAttribute(\%nodeId, $newBoolean)
$status_code = $client->writeInverseNameAttribute(\%nodeId, \%newLocalizedText)
$status_code = $client->writeIsAbstractAttribute(\%nodeId, $newBoolean)
$status_code = $client->writeMinimumSamplingIntervalAttribute(\%nodeId, $newDouble)
$status_code = $client->writeNodeClassAttribute(\%nodeId, $newNodeClass)
$status_code = $client->writeNodeIdAttribute(\%nodeId, \%newNodeId)
$status_code = $client->writeSymmetricAttribute(\%nodeId, $newBoolean)
$status_code = $client->writeUserAccessLevelAttribute(\%nodeId, $newByte)
$status_code = $client->writeUserExecutableAttribute(\%nodeId, $newBoolean)
$status_code = $client->writeUserWriteMaskAttribute(\%nodeId, $newUInt32)
$status_code = $client->writeValueAttribute(\%nodeId, \%newVariant)
$status_code = $client->writeValueRankAttribute(\%nodeId, $newInt32)
$status_code = $client->writeWriteMaskAttribute(\%nodeId, $newUInt32)

ClientConfig

$status_code = $client_config->setDefault()
$context = $client_config->getClientContext()
$client_config->setClientContext($context)
$client_config->setStateCallback($callback)
$logger = $client_config->getLogger()

Logger

The Logger uses the embedded logger of a client or server config. The scope of the logger object may extend the lifetime of the client or sever object. It contains Perl callbacks to the log and clear functions. The log functions are exported to Perl.

$logger->setCallback($log, $context, $clear);
$log = sub { my ($context, $level, $category, $message) = @_ }
$clear = sub { my ($context) = @_ }
$logger->logTrace($category, $msg, ...);
$logger->logDebug($category, $msg, ...);
$logger->logInfo($category, $msg, ...);
$logger->logWarning($category, $msg, ...);
$logger->logError($category, $msg, ...);
$logger->logFatal($category, $msg, ...);

SEE ALSO

OPC UA library, https://open62541.org/

OPC Foundation, https://opcfoundation.org/

OPCUA::Open62541::Constant

AUTHORS

Alexander Bluhm <bluhm@genua.de>, Anton Borowka, Arne Becker, Marvin Knoblauch <mknob@genua.de>,

CAVEATS

This interface is far from complete.

The C types UA_Int64 and UA_UInt64 are implemented as Perl integers IV and UV respectively. This only works for Perl that is compiled on a 64 bit platform. 32 bit platforms are currently not supported.

COPYRIGHT AND LICENSE

Copyright (c) 2020 Alexander Bluhm

Copyright (c) 2020 Anton Borowka

Copyright (c) 2020 Arne Becker

Copyright (c) 2020 Marvin Knoblauch

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.

Thanks to genua GmbH, https://www.genua.de/ for sponsoring this work.