Client - Getting Started

An OPC UA client is a network client that interacts with an OPC UA server via a collection of abstract Remote Procedure Calls (RPC), which is a request/response protocol. An RPC is initiated by the client, which sends a request message to the server. The OPC UA server then sends a response to the client, and the application continues its process. While the OPC UA server is processing the call, the OPC UA client is blocked (it waits until the server has finished processing before resuming execution), unless the OPC UA client operates in asynchronous callback mode.

The OPC UA client can operate in standard blocking socket call (default) or nonblocking cosocket mode. Blocking sockets must run in the context of a native thread, such as a thread running an LSP page. See Asynchronous Cosocket Mode for details.

Connecting to Server

A client is created by first loading the OPC-UA stack and then creating a client as follows:

local ua = require("opcua.api")

local config = {
  applicationName = 'RealTimeLogic example',
  applicationUri = "urn:opcua-lua:example",
  productUri = "urn:opcua-lua:example",
  securePolicies = {
    { -- #1
      securityPolicyUri = ua.Types.SecurityPolicy.None
    }
  },
}

local client = ua.newClient(config)

Full source

Next, connect to the server, open an OPC-UA channel and finally create an OPC-UA session:

local resp, err
local endpointUrl = "opc.tcp://localhost:4841"
client:connect(endpointUrl, connectCallback)
resp, err = client:openSecureChannel(120000, ua.Types.SecurityPolicy.None, ua.Types.MessageSecurityMode.None)
resp, err = client:createSession("test_session", 3600000)
resp, err = client:activateSession()

Full source

You can start browsing the address space as soon as a session has been established.

Browsing Address Space

Call the’ browse’ method to browse the server’s address space.

local RootFolder = "i=84"
local BaseDataVariableType = "i=63"
local FolderType = "i=61"
local ObjectsFolder = "i=85"
local Organizes = "i=35"
local UInt32 = "i=24"
local HierarchicalReferences = "i=33"
local TypesFolder = "i=86"


-- Browse one node by ID.
resp, err = client:browse(RootFolder)

-- Browse array of Node IDs.
resp, err = client:browse({RootFolder, TypesFolder})
if err ~= nil then
  return
end

for _,res in ipairs(resp.Results) do
  if res.StatusCode ~= ua.StatusCode.Good then
    trace(string.format("Cannot browse node: 0x%X", res.StatusCode))
  else
    trace("References:")
    for i,ref in ipairs(res.References) do
      trace(string.format("%d: NodeId=%s Name=%s", i, ref.NodeId, ref.DisplayName.Text))
    end
  end
end

Full source

The Address Space Browsing user guide has a detailed overview of all parameters.

Reading Node Attributes

local ua = require("opcua.api")

local config = {
local ObjectsFolder = "i=85"
local TypesFolder = "i=86"

-- Read all possible attributes of the any node
-- For part of attributes will be returned a valus
-- and for part of attributes will be returned a status code BadAttributeIdInvalid
resp,err = client:read(ObjectsFolder)
for i,result in ipairs(resp.Results) do
  if result.StatusCode == 0 then
    ua.Tools.printTable("result", result.Value)
  else
    trace(string.format("Read attributes error: 0x%X", result.StatusCode))
  end
end

-- Read all possible attributes of several nodes
-- For part of attributes will be returned a valus
-- and for part of attributes will be returned a status code BadAttributeIdInvalid
resp,err = client:read({ObjectsFolder, TypesFolder})

Full source

See Reading and Writing Data for parameters and detailed information.

Closing Server Connection

When finished using the server, close the server connection as follows:

resp, err = client:closeSession()
client:disconnect()

Full source

Asynchronous Cosocket Mode

Clients, by default, use blocking sockets. However, a client can be configured to operate in cosocket mode, a lightweight Lua coroutine socket thread. All client methods can accept a callback that will be called when the corresponding request completes. The OPC UA methods can also be called without providing a callback when running in cosocket mode if the caller is running in the context of another cosocket. When another cosocket calls an OPC UA client in cosocket mode without providing a callback, the calling cosocket will block. Not having to provide a callback when operating in cosocket mode makes designing OPC UA clients easier.

We recommend reading the Barracuda App Server’s Socket Design User Guide for an introduction to cosockets and for details on the various socket modes.

The cosocket mode is set in the configuration table with the flag ‘cosocketMode’.

local ua = require("opcua.api")

local config = {
  applicationName = 'RealTimeLogic example',
  applicationUri = "urn:opcua-lua:example",
  productUri = "urn:opcua-lua:example",
  securePolicies = {
    { -- #1
      securityPolicyUri = ua.Types.SecurityPolicy.None
    }
  },
  cosocketMode = true, -- Start socket read loop in separate cosocket
}
local client = ua.newClient(config)

Full source

All callbacks, except for the connect method must accept two arguments. The connect method receives one argument as shown in the two examples below.

  local endpointUrl = "opc.tcp://localhost:4841"
  client:connect(endpointUrl, connectCallback)

Full source

The connect method’s error argument is nil if the connection succeeded.

local function connectCallback(err)
  if err ~= nil then
    trace("connection error: "..err)
    return
  end

  trace("Opening secure channel")
  local secureChannelTimeout = 60000 -- ms
  client:openSecureChannel(secureChannelTimeout, ua.Types.SecurityPolicy.None, ua.Types.MessageSecurityMode.None, nil, onChannelOpened)
end

Full source

All other callbacks receive two arguments: the response and an error code. This corresponds to the two return values returned when operating in blocking mode (when not providing a callback). The methods return response,nil on success and nil,error on failure.

local function onChannelOpened(resp, err)
  if err ~= nil then
    trace("Secure channel error: "..tostring(err))
    return
  end
  ua.Tools.printTable("SecureChannel", resp)

  trace("Disconnecting from server")
  pcall(client.disconnect, client)
end

Full source