Skip to main content

OPC UA

opcua module implements communication over OPC UA protocol.

note

OPC UA client is available since Gateway version 2.0.2.

opcua.client()

-- @param url string OPC UA connection string
-- @return table OPC UA client
function opcua.client(url)
end

Creates a new OPC UA client instance with the given connection string.

The underlying TCP connection is established on-demand when the first request is initiated, so this method does not return any error.

Example

local client = opcua.client('opc.tcp://opcuademo.sterfive.com:26543')

Advanced client configuration

Since Gateway version 2.1.1 OPC UA client supports additional settings.

-- @param url string OPC UA connection string
-- @param cfg table connection settings
-- @return table, string OPC UA client and error string
function opcua.client(url, cfg)
end

Authentication methods

OPC UA client supports authentication either with a username or with a certificate. Only one authentication method can be used at a time.

Authentication with username

Authentication with a username requires username and password.

Example

local cfg = {
auth = {
username='user',
password='123456',
}
}

Authentication with certificate

Authentication with a certificate requires cert and key.

Example
local cfg = {
auth = {
cert='certificate',
key='private key',
}
}

Security

OPC UA client supports a configuration of a secure connection. It should either set mode and policy, set none for both or leave them empty. If mode and policy are set to not none, cert and key are required.

note

If Authentication with certificate is configured, the Security configuration should use the same cert/key pair.

mode supports next variables:

  • opcua.security_mode_none
  • opcua.security_mode_sign
  • opcua.security_mode_sign_and_encrypt

policy supports next variables:

  • opcua.security_policy_none
  • opcua.security_policy_basic128_rsa15
  • opcua.security_policy_basic256
  • opcua.security_policy_basic256_sha256
  • opcua.security_policy_aes128_sha256rsa_oaep
  • opcua.security_policy_aes256_sha256rsa_pss
Example
local cfg = {
security = {
mode=opcua.security_mode_sign,
policy=opcua.security_policy_basic256,
cert='certificate',
key='private key',
},
}

client Object

client:read()

-- @param request table Read request object
-- @return table, string Response object and error string
function client:read(request)
end

Performs a read request initiated with opcua.read_request() method. Returns two values: results and error. When the performed request failed (e.g. network timeout) error will contain non-nil string. If any response is obtained, error will be nil.

results is a list with results for every requested value. The number of results is equal to the number of values in the read request. Every result contain an error and value fields. error is nil if read succeeded or contains a string with error if it failed.

OPC UA types will be automatically converted to appropriate Lua types like number, string or table.

Example

-- Initiate request object that will read two values
local request = opcua.read_request({ 'ns=1;i=1678', 'ns=1;i=1348' })

-- Send request
local results, err = client:read(request)
if err then
enapter.log('read failed: '..err, 'error')
else
for i, r in ipairs(results) do
if r.error then
enapter.log('failed: '..r.error, 'error')
else
enapter.log('value #'..i..': '..tostring(r.value))
end
end
end

client:write()

-- @param request table Write request object
-- @return table, string Response object and error string
function client:write(request)
end

Performs a write request initiated with opcua.write_request() method. Returns two values: results and error. When the performed request failed (e.g. network timeout) error will contain non-nil string. If any response is obtained, error will be nil.

results is a list with results for every written value. The number of results is equal to the number of values in the write request. Every result contain an error field. error is nil if write succeeded or contains a string with error if it failed.

Example

-- Initiate request object that will write three values of different types
local request = opcua.write_request({
{node_id = 'ns=2;s=Some.Double', value = 12.5},
{node_id = 'ns=2;s=Some.String', value = 'test'},
{node_id = 'ns=2;s=Some.Number', value = 59},
})

-- Send request
local results, err = client:write(request)
if err then
enapter.log('write failed: '..err, 'error')
else
for i, r in ipairs(results) do
if r.error then
enapter.log('failed: '..r.error, 'error')
else
enapter.log('write #'..i..' succeeded')
end
end
end

client:call_method()

-- @param request table Method request object
-- @return table, string Return values and error string
function client:call_method(request)
end

Performs a method call request initiated with opcua.method_request() method. Returns two values: values (an array of values returned by method call) and error. When the performed request failed (e.g. network timeout) error will contain non-nil string. If any response is obtained, error will be nil.

Methods in OPC UA may return several values, thus returned values is always an array (even of one element). Since the method call may return a nil values, it's advisable to access return values using positional array access (e.g. values[1]) due to Lua specifics in working with nil values (iteration using ipairs will stop on the first nil value and will ignore the rest).

Example

-- Initiate request object object node, method node, and method arguments
local request = opcua.method_request(
'ns=2;s=Some',
'ns=2;s=Some.Multiply',
{2, 2}
)

local values, err = client:call_method(request)
if err then
enapter.log('method failed: '..err, 'error')
else
enapter.log('result: '..tostring(values[1]))
end

client:subscribe()

note

This function is available since Gateway version 2.1.1.

-- @param node_id string Node ID of node which value we want to subscribe to
-- @param interval integer defines how frequently the client sends update via callback
-- @param callback function call when update incoming
-- @return integer, string Return subscription id and error string
function client:subscribe(node_id, interval, callback)
end

Creates a subscription to get value updates for a specified node. Returns two values: subscription id (used for canceling subscription with client:unsubscribe() method) and error. When the subscribe command fails (e.g. network timeout), error will contain a non-nil string. If the subscribe command succeeds, error will be nil.

Example

local node_id = "ns=2;s=Write.String"
local interval = 1000

local sub_id, err = client:subscribe(node_id, interval, function(value)
enapter.log("Subscription callback value: "..tostring(value))
end)
if err then
enapter.log("Subscribe error: "..err, "error")
else
enapter.log("Subscribe success")
end

client:unsubscribe()

note

This function is available since Gateway version 2.1.1.

-- @param sub_id integer subscription id 
-- @return string Return error string
function client:unsubscribe(sub_id)
end

Cancels subscription to node value updates. Function returns error. When the unsubscribe command fails (e.g. network timeout), error will contain a non-nil string. If the unsubscribe command succeeds, error will be nil.

Example

sub_id, _ = client:subscribe(node_id_1, interval, function(value)  end)

err = client:unsubscribe(sub_id)
if err then
enapter.log("Unsubscribe error: "..err, "error")
else
enapter.log("Unsubscribe success")
end

client:node_attributes()

-- @param node_id string OPC UA node id
-- @return table, string Return object and error string
function client:node_attributes(node_id)
end

Performs getting node attributes initiated with node identifier string (e.g. ns=2;s=Read.StatusCode). Returns two values: node data and error. When the performed request failed (e.g. network timeout) error will contain non-nil string. If any response is obtained, error will be nil.

node data is a table of attributes for the node. Client supports next attributes returning:

OPC UA AttributeLua Table Field NameLua Table Field Type
NodeIDnode_idstring
NodeClassnode_classstring
BrowseNamebrowse_namestring
DisplayNamedisplay_namestring
Descriptiondescriptionstring
DataTypedata_typestring

A list of available attributes in node data depends on a node type.

data_type takes one of the following values:

  • Double
  • GUID
  • NodeID
  • Number
  • StatusCode
  • String
  • Argument

Or node identifier string (e.g. i=293) for unsupported types.

Example

local node_data, err = client:node_attributes("ns=2;s=Read.String")
if err then
enapter.log("Error get node attributes: "..err, "error")
else
enapter.log(
"String attributes\n"
.."node_class: "..node_data.node_class.."\n"
.."browse_name: "..node_data.browse_name.."\n"
.."display_name: "..node_data.display_name.."\n"
.."description: "..node_data.description.."\n"
.."data_type: "..node_data.data_type.."\n"
)
end

client:node_children()

-- @param node_id string OPC UA node id
-- @return table, string Return string array and error string
function client:node_children(node_id)
end

Performs get node children initiated with node identifier string (e.g. ns=2;s=Method.Multiply). Returns two values: node_ids and error. When the performed request failed (e.g. network timeout) error will contain non-nil string. If any response is obtained, error will be nil.

node_ids is a string table of child node ids.

Example

-- recursive method to get nodes tree
function browse_tree(node_id)
-- get attributes of parent node
local node_data, err = client:node_attributes(node_id)
if err then
return nil, "node attributes "..node_id..": "..err
end

node_data.references = {}

-- get children node ids
local children_nodes, err = client:node_children(node_data.node_id)
if err then
return nil, "ref node ids: "..err
end

-- get attributes of each child node
for _, child_node_id in ipairs(children_nodes) do
local ch_node_data, err = browse_tree(child_node_id)
if err then
return nil, "recursive browse tree: "..err
end
table.insert(node_data.references, ch_node_data)
end

return node_data, nil
end

local tree_data, err = browse_tree("ns=2;s=Method.Multiply")
if err then
enapter.log("Error browse tree: "..err, "error")
else
enapter.log("Browse tree: "..inspect(tree_data))
end
Output
Browse tree: {
browse_name = "Multiply",
description = "Multiply",
display_name = "Multiply",
node_class = "Method",
node_id = "ns=2;s=Method.Multiply",
references = { {
browse_name = "InputArguments",
data_type = "Argument",
description = "InputArguments",
display_name = "InputArguments",
node_class = "Variable",
node_id = "ns=2;i=10",
references = {}
}, {
browse_name = "OutputArguments",
data_type = "Argument",
description = "OutputArguments",
display_name = "OutputArguments",
node_class = "Variable",
node_id = "ns=2;i=11",
references = {}
} }
}

Request Objects

opcua.read_request()

-- @param node_ids table Node IDs to read
-- @return table Request object
function opcua.read_request(node_ids)
end

Creates a new read request instance with the given node IDs to read.

Example

local request = opcua.read_request({
'ns=1;i=1678',
'ns=2;s=Some.Value'
})

opcua.write_request()

-- @param write_pairs table ID-value pairs to write
-- @return table Request object
function opcua.write_request(write_pairs)
end

Creates a new write request instance. It accepts the write_pairs table where keys are node IDs and values are values to write.

Lua types are converted to appropriate OPC UA types according to type conversion logic.

Example

local request = opcua.write_request({
{node_id = 'ns=2;s=Some.Double', value = 12.5},
{node_id = 'ns=2;s=Some.String', value = 'test'},
{node_id = 'ns=2;s=Some.Number', value = 59},
{node_id = 'ns=2;s=Some.Guid', value = opcua.types.guid('5C97A069-F8A0-48AC-A66F-446475ABB704')},
{node_id = 'ns=2;s=Some.NodeId', value = opcua.types.node_id('ns=2;s=ServerStatus')},
{node_id = 'ns=2;s=Some.StatusCode', value = opcua.types.status_code(12)},
})

opcua.method_request()

-- @param object_id string Node ID of object that contains method
-- @param method_id string Node ID of method to call
-- @param args table Array of method arguments
-- @return table Request object
function opcua.method_request(object_id, method_id, args)
end

Creates a new method call request with object ID, method ID, and method arguments.

Lua types are converted to appropriate OPC UA types according to type conversion logic.

Example

local request = opcua.method_request(
'ns=2;s=Some', -- object that contains method
'ns=2;s=Some.Multiply', -- method node
{2, 2} -- an array with method arguments
)

Type Conversion

When performing write or method call requests some Lua types are automatically converted to appropriate OPC UA types, others should be explicitly given.

Supported node value types:

  • string Lua values are automatically converted to OPC UA String,
  • opcua.types.float() initiates OPC UA Float values,
  • opcua.types.double() initiates OPC UA Double values,
  • opcua.types.int64() initiates OPC UA Int64 values,
  • opcua.types.int32() initiates OPC UA Int32 values,
  • opcua.types.int16() initiates OPC UA Int16 values,
  • opcua.types.sbyte() initiates OPC UA SByte values,
  • opcua.types.uint64() initiates OPC UA UInt64 values,
  • opcua.types.uint32() initiates OPC UA UInt32 values,
  • opcua.types.uint16() initiates OPC UA UInt16 values,
  • opcua.types.byte() initiates OPC UA Byte values,
  • opcua.types.guid() initiates OPC UA GUID values,
  • opcua.types.status_code() initiates OPC UA StatusCode values,
  • opcua.types.node_id() initiates OPC UA NodeId values.
Hardware diversity is welcome. Integrate any device into a unified energy network.
© 2024 Enapter
Developer toolkit
DocumentationReference