---
title: "OPC UA Connector"
description: "The LumiScan OPC UA Connector - LumiScan Keryx as an OPC UA address space for PLCs and SCADA systems: endpoint, node mapping, options, security, types, calling the three patterns, subscriptions and status codes."
product: "LumiScan Keryx"
component: "lumiscan-keryx"
version: "1.0.0"
display_version: "1.0.0.7"
latest_version: true
language: "en"
url: "https://docs.hdvisionsystems.com/en/lumiscan-keryx/1.0.0/opc-ua.html"
---

# OPC UA Connector – LumiScan Keryx

> [!NOTE]
> On ctrlX OS this connector is not used: a ctrlX PLC on the same device uses the nodes directly, see [Connecting a PLC](https://docs.hdvisionsystems.com/en/lumiscan-keryx/1.0.0/ctrlx-data-layer.html#connecting-a-plc).

The **LumiScan OPC UA Connector** (`lumiscan_opcua_connector`) shows the tree of LumiScan Keryx as an OPC UA address space. A PLC, a SCADA system or any OPC UA client reads, writes, calls and subscribes to the nodes of the apps without a Data Layer client of its own. The connector forwards every request to the Data Layer when it arrives; it stores no values of its own.

The address space is the Data Layer’s own tree, not an OPC UA companion specification such as OPC 40100 (Machine Vision).

## Endpoint and address space {#endpoint}

|   |   |
| --- | --- |
| Endpoint | `opc.tcp://<pc>:4840`, on every network interface of the PC |
| Security | security policy **None**, **anonymous** login, see [Security](https://docs.hdvisionsystems.com/en/lumiscan-keryx/1.0.0/opc-ua.html#security) |
| Namespace URI | `urn:hdvisionsystems:keryx` |
| NodeId | the Data Layer address as a string identifier in that namespace: `ns=<n>;s=hdvisionsystems/lumiscan-cam-driver/camera1/control/status/code` |
| BrowseName | the last segment of the address, for example `code` |
| Root | one object under `Objects`, called `Keryx`, that holds `hdvisionsystems` and the other top-level folders. Started with `--root hdvisionsystems` it is `hdvisionsystems`; the NodeIds stay the same |

**Find the namespace index `n` from the URI** in the server’s `NamespaceArray`. Do not write a fixed index into your program: another start can number it differently.

| Data Layer | OPC UA node |
| --- | --- |
| folder | Object (FolderType) |
| value | Variable (BaseDataVariableType), with the access the node allows |
| method | Method with **no input arguments** and one output argument `Result`, belonging to the object of its parent address |

The connector walks the tree at start and again every 2 seconds. An app that starts later, a module that is added and a node that disappears show up within about 2 seconds. There are no model change events: a client that cached its browse result must browse again. An app that stops keeps its nodes in the tree; reading them answers `BadTimeout`, then `BadNoCommunication`, until the app registers again.

## Starting the connector {#starting}

The installer adds a Start menu shortcut that starts the connector without options: port 4840, the whole Data Layer, anonymous, read and write.

**Start it after the apps.** The connector never starts a broker: without one it logs the reason and ends with exit code 1, and its window closes. Stop it with Ctrl+C. Like the apps it is protected with CodeMeter, see [LumiScan Licensing](https://docs.hdvisionsystems.com/en/lumiscan-licensing/1.0.4/index.html).

| Option | Meaning |
| --- | --- |
| `-p`, `--port <n>` | OPC UA port, default 4840 |
| `-r`, `--root <address>` | show only this subtree, for example `hdvisionsystems` |
| `--read-only` | refuse writes (`BadNotWritable`) and method calls (`BadNotExecutable`) |
| `--keryx-url <url>` | the broker, default `tcp://127.0.0.1:5555` |
| `--request-timeout-ms <ms>` | how long a read or write may take, default 2000 |
| `--method-timeout-ms <ms>` | how long a method call may take, default 60000 |
| `--method-workers <n>` | method calls that run at the same time, default 4 |
| `--min-publishing-ms <ms>` | the fastest a subscription sends notifications, default 10 |
| `--resync-ms <ms>` | how often the tree is walked again, default 2000 |
| `--sampling-ms <ms>` | sampled mode instead of event mode; not recommended |

`lumiscan_opcua_connector --help` lists all options.

## Security {#security}

**There is none.** The connector accepts any client, anonymous and unencrypted, and the client can write every writable node and call every method - including starting and stopping the camera and changing settings through `system/settings`. Treat it like an unprotected field-bus port:

- run it on a network you trust, such as the machine network between the PC and the PLC;
- open TCP 4840 in the PC’s firewall for the PLC’s address only;
- for a client that only observes, run a second instance read-only on its own port: `lumiscan_opcua_connector --root hdvisionsystems --port 4841 --read-only`.

Certificates, user names and encryption are not supported; a client that insists on a secure channel cannot connect.

## Reading, writing and types {#types}

**The type must be exactly the node’s.** The connector does not convert: a `Boolean` node takes a Boolean, not 0 or 1; a `UInt32` node takes UInt32, not Int32. Most trouble with a first connection is a type that is one size off.

| Node type | OPC UA type | IEC 61131-3 |
| --- | --- | --- |
| bool | Boolean | `BOOL` |
| int32 | Int32 | `DINT` |
| uint32 | UInt32 | `UDINT` |
| uint64 | UInt64 | `ULINT` |
| float32 | Float | `REAL` |
| float64 | Double | `LREAL` |
| string | String | `STRING` |
| arrays of these | the same type, one dimension | `ARRAY [..] OF …` |
| FlatBuffers result, image | ByteString | not usable without a decoder |

- A read waits up to 2 seconds. A node that did not answer is `BadNoCommunication` for the next 5 seconds.
- A write replaces the whole value and is never repeated. A write with a `NumericRange` is refused (`BadWriteNotSupported`).
- The timestamps of a value are the connector’s: the Data Layer carries no time of its own.
- Do not build PLC logic on FlatBuffers values. Use the plain nodes beside them.

## Calling the three patterns {#calls}

**Handshake**: only reads and writes, as in [Handshake](https://docs.hdvisionsystems.com/en/lumiscan-keryx/1.0.0/handshake.html). Poll at 50 to 100 ms.

**Execute**: write the method’s inputs - a method has no arguments, its inputs are separate nodes - then use the **Call** service with `objectId` = the parent address (for example `…/camera1/control/trigger`) and `methodId` = the method (`…/camera1/control/trigger/execute`). The call answers when the method has finished, after up to 60 seconds; set your client’s call timeout higher than your slowest method. The status of the call says whether the operation could run, see [Results of a method call](https://docs.hdvisionsystems.com/en/lumiscan-keryx/1.0.0/status-codes.html#method-results). Then read `control/status/code` and the outputs.

**Stream**: subscribe to the result node, see [Subscriptions](https://docs.hdvisionsystems.com/en/lumiscan-keryx/1.0.0/opc-ua.html#subscriptions).

## Subscriptions {#subscriptions}

Create a subscription and add a monitored item for the node:

| Setting | Value | Why |
| --- | --- | --- |
| Publishing interval | 10 ms or more | the server’s fastest |
| Sampling interval | **0** | reports every push as it arrives (event mode) |
| Queue size | 10 to 100 | with 1 only the newest push arrives |
| DataChange trigger | `StatusValueTimestamp` | otherwise two identical results count as one |
| DiscardOldest | true |   |

- A node reports a change when the app pushes it; streams do. A value too large to be pushed never reports in event mode: use a positive sampling interval for it.
- Large values cost: a 1.5 MB camera frame sampled every 10 ms is 150 MB/s for one item. Do not monitor `output/image`, `…/stream/frame` or `…/stream/result` unless you decode them. For coordinates, monitor Calibration’s `plain-points`.
- At start the connector checks that event mode works. If it does not, it logs that and samples every item on a timer (sampled mode). If your client gets fewer notifications than pushes, read the connector’s log first.

## OPC UA status codes {#status}

Beyond the results of a method call:

| Status | Meaning |
| --- | --- |
| `BadNodeIdUnknown` | wrong address, case or namespace index; the app is not running; the module is missing |
| `BadNoCommunication` | the app has stopped or hangs |
| `BadTimeout` | the app did not answer in 2 s (read, write) or 60 s (call) |
| `BadTypeMismatch` | the value is not of the node’s type |
| `BadWriteNotSupported` | a write with a `NumericRange` |
| `BadNotWritable` | an output, or the connector is read-only |
| `BadNotExecutable` | the connector is read-only |
| `BadMethodInvalid` | the node is no longer a method of the tree: browse again |

After an app has restarted, run your start-up sequence again: the camera is not connected and the Cam Driver’s stream is off. If a monitored item does not report again, delete and create it.
