> ## Documentation Index
> Fetch the complete documentation index at: https://docs.coreflux.org/llms.txt
> Use this file to discover all available pages before exploring further.

# OPC UA Route

> Connect to OPC UA servers for cross-platform industrial communication with comprehensive security options

## OPC UA Overview

The `OPCUA` route enables communication with OPC UA servers, providing a standardized, cross-platform protocol for industrial automation. It supports multiple authentication modes, security policies, and both NodeId and BrowsePath addressing.

<Tip>
  OPC UA is vendor-neutral and widely supported by modern industrial equipment. Use it when you need secure, standardized communication across different manufacturer's devices.
</Tip>

## Basic Syntax

```lot theme={null}
DEFINE ROUTE OPCServer WITH TYPE OPCUA
    ADD OPCUA_CONFIG
        WITH ENDPOINT_URL "opc.tcp://192.168.1.100:4840"
        WITH AUTH_MODE 0
        WITH AUTO_ACCEPT_UNTRUSTED_CERTIFICATES "true"
    ADD MAPPING ProcessData
        WITH EVERY 1 SECOND
        ADD TAG Temperature
            WITH ADDRESS "ns=2;s=Channel1.Device1.Temperature"
            WITH DATA_TYPE "FLOAT"
            WITH SOURCE_TOPIC "opcua/temperature"
```

***

## Connection Configuration

### OPCUA\_CONFIG Parameters

<ParamField path="ENDPOINT_URL" type="string" required>
  OPC UA server endpoint URL (e.g., `opc.tcp://localhost:4840`).
</ParamField>

<ParamField path="AUTH_MODE" type="integer">
  Authentication mode:

  * `0` - Anonymous (no authentication)
  * `1` - Username/Password
  * `2` - Certificate

  Default: 0.
</ParamField>

<ParamField path="USERNAME" type="string">
  Username for authentication (required if AUTH\_MODE is 1).
</ParamField>

<ParamField path="PASSWORD" type="string">
  Password for authentication (required if AUTH\_MODE is 1).
</ParamField>

<ParamField path="USE_SECURITY" type="boolean">
  Enable security mode. Default: false.
</ParamField>

<ParamField path="SECURITY_POLICY" type="integer">
  Security policy level:

  * `0` - None
  * `1` - Basic128Rsa15
  * `2` - Basic256
  * `3` - Basic256Sha256
  * `4` - Aes128\_Sha256\_RsaOaep
  * `5` - Aes256\_Sha256\_RsaPss

  Default: 0.
</ParamField>

<ParamField path="MESSAGE_SECURITY" type="integer">
  Message security mode:

  * `0` - None
  * `1` - Sign
  * `2` - SignAndEncrypt

  Default: 0.
</ParamField>

<ParamField path="AUTO_ACCEPT_UNTRUSTED_CERTIFICATES" type="boolean">
  Automatically accept untrusted server certificates. Default: false.
</ParamField>

<ParamField path="SUPPRESS_NONCE_VALIDATION_ERRORS" type="boolean">
  Suppress nonce validation errors. Default: false.
</ParamField>

<ParamField path="TIMEOUT" type="integer">
  Connection timeout in milliseconds. Default: 90000.
</ParamField>

***

## Security Configuration

<Tabs>
  <Tab title="Anonymous (No Security)">
    For development or trusted networks:

    ```lot theme={null}
    ADD OPCUA_CONFIG
        WITH ENDPOINT_URL "opc.tcp://192.168.1.100:4840"
        WITH AUTH_MODE 0
        WITH USE_SECURITY "false"
        WITH AUTO_ACCEPT_UNTRUSTED_CERTIFICATES "true"
    ```
  </Tab>

  <Tab title="Username/Password">
    Basic authentication:

    ```lot theme={null}
    ADD OPCUA_CONFIG
        WITH ENDPOINT_URL "opc.tcp://192.168.1.100:4840"
        WITH AUTH_MODE 1
        WITH USERNAME "opcuser"
        WITH PASSWORD "secure_password"
        WITH USE_SECURITY "true"
        WITH SECURITY_POLICY 3
        WITH MESSAGE_SECURITY 2
    ```
  </Tab>

  <Tab title="Certificate Authentication">
    For high-security environments:

    ```lot theme={null}
    ADD OPCUA_CONFIG
        WITH ENDPOINT_URL "opc.tcp://192.168.1.100:4840"
        WITH AUTH_MODE 2
        WITH USE_SECURITY "true"
        WITH SECURITY_POLICY 5
        WITH MESSAGE_SECURITY 2
    ```

    <Note>
      Certificate-based authentication (Mode 2) is currently in development. Use Anonymous (Mode 0) or Username/Password (Mode 1) for production deployments.
    </Note>
  </Tab>
</Tabs>

***

## NodeId Addressing

OPC UA uses NodeIds to identify variables. The format is: `ns=<namespace>;s=<identifier>` or `ns=<namespace>;i=<numeric_id>`

| Format             | Example                                       | Description                          |
| ------------------ | --------------------------------------------- | ------------------------------------ |
| String identifier  | `ns=2;s=Channel1.Device1.Tag1`                | Most common, human-readable          |
| Numeric identifier | `ns=2;i=1234`                                 | More efficient, used by some servers |
| GUID identifier    | `ns=2;g=12345678-1234-1234-1234-123456789012` | Globally unique identifiers          |

### Finding NodeIds

Use an OPC UA browser tool (like UaExpert, Prosys OPC UA Browser, or similar) to explore the server's address space and find the correct NodeIds.

### BrowsePath Mode

For servers that support it, you can use symbolic paths instead of NodeIds:

<ParamField path="USE_BROWSE_PATH" type="boolean">
  Enable BrowsePath mode - treat all TAG addresses as browse paths instead of NodeIds.
</ParamField>

<ParamField path="BROWSE_ROOT_PATH" type="string">
  Root path for browsing when USE\_BROWSE\_PATH is enabled. Default: Objects.
</ParamField>

#### BrowsePath Example

```lot theme={null}
ADD OPCUA_CONFIG
    WITH ENDPOINT_URL "opc.tcp://192.168.1.100:4840"
    WITH USE_BROWSE_PATH "true"
    WITH BROWSE_ROOT_PATH "Objects"
ADD MAPPING Tags
    WITH EVERY 1 SECOND
    ADD TAG Temperature
        WITH ADDRESS "Aliases/MyDevice/Temperature"
        WITH DATA_TYPE "FLOAT"
        WITH SOURCE_TOPIC "opcua/temperature"
```

***

## Data Types

| Data Type                      | OPC UA Type | Description                                 |
| ------------------------------ | ----------- | ------------------------------------------- |
| `BOOLEAN` / `BOOL`             | Boolean     | True/False value                            |
| `SBYTE` / `SINT`               | SByte       | Signed 8-bit integer                        |
| `BYTE` / `USINT`               | Byte        | Unsigned 8-bit integer                      |
| `INT16` / `INT` / `WORD`       | Int16       | 16-bit integer                              |
| `UINT16` / `UINT`              | UInt16      | Unsigned 16-bit integer                     |
| `INT32` / `DINT`               | Int32       | Signed 32-bit integer                       |
| `UINT32` / `UDINT` / `DWORD`   | UInt32      | Unsigned 32-bit integer                     |
| `INT64` / `LINT`               | Int64       | Signed 64-bit integer                       |
| `UINT64` / `ULINT` / `LWORD`   | UInt64      | Unsigned 64-bit integer                     |
| `FLOAT` / `FLOAT32` / `REAL`   | Float       | 32-bit floating point                       |
| `DOUBLE` / `FLOAT64` / `LREAL` | Double      | 64-bit floating point                       |
| `CHAR`                         | Char        | Single character                            |
| `WCHAR`                        | WChar       | Wide character                              |
| `TIME`                         | Time        | Time duration                               |
| `DATE`                         | Date        | Date value                                  |
| `TOD`                          | TimeOfDay   | Time of day                                 |
| `STRING`                       | String      | Unicode string (configurable `STRING_SIZE`) |

***

## TAG Configuration

### Complete TAG Example

```lot theme={null}
ADD TAG ProcessTemperature
    WITH ADDRESS "ns=2;s=Process.Temperature"
    WITH DATA_TYPE "FLOAT"
    WITH SOURCE_TOPIC "opcua/process/temperature"
    WITH SCALING 1
    WITH OFFSET 0
    WITH UNIT "°C"
    WITH DECIMAL_PLACES 2
    WITH MIN_VALUE -50
    WITH MAX_VALUE 500
    WITH DEADBAND 0.5
    WITH PUBLISH_MODE "JSON"
    WITH WRITABLE "true"
    WITH DESTINATION_TOPIC "opcua/process/temperature/set"
    WITH IS_ARRAY "false"
    WITH DESCRIPTION "Main process temperature sensor"
```

### TAG Parameters

<AccordionGroup>
  <Accordion title="Address Configuration">
    <ParamField path="ADDRESS" type="string" required>
      OPC UA NodeId (e.g., `ns=2;s=MyVariable` or `ns=2;i=1234`) or BrowsePath if USE\_BROWSE\_PATH is enabled.
    </ParamField>

    <ParamField path="DATA_TYPE" type="string" required>
      OPC UA data type: `BOOLEAN`, `BYTE`, `INT16`, `UINT16`, `INT32`, `UINT32`, `INT64`, `UINT64`, `FLOAT`, `DOUBLE`, `STRING`.
    </ParamField>

    <ParamField path="IS_ARRAY" type="boolean">
      Indicates if the value is an array. Default: false.
    </ParamField>
  </Accordion>

  <Accordion title="Value Transformation">
    <ParamField path="SCALING" type="double">
      Multiplier for value transformation. Default: 1.0.
    </ParamField>

    <ParamField path="OFFSET" type="double">
      Offset added after scaling. Default: 0.0.
    </ParamField>

    <ParamField path="DECIMAL_PLACES" type="integer">
      Decimal places in output. Default: 2.
    </ParamField>
  </Accordion>

  <Accordion title="Filtering">
    <ParamField path="MIN_VALUE" type="double">
      Minimum allowed value.
    </ParamField>

    <ParamField path="MAX_VALUE" type="double">
      Maximum allowed value.
    </ParamField>

    <ParamField path="DEADBAND" type="double">
      Minimum change to trigger publish. Default: 0.0.
    </ParamField>
  </Accordion>

  <Accordion title="Publishing">
    <ParamField path="SOURCE_TOPIC" type="string">
      Topic where PLC values are published. Subscribe here to receive sensor data.
    </ParamField>

    <ParamField path="PUBLISH_MODE" type="string">
      Output format: `VALUE_ONLY` or `JSON`. Default: VALUE\_ONLY.
    </ParamField>

    <ParamField path="UNIT" type="string">
      Engineering unit for documentation.
    </ParamField>

    <ParamField path="DESCRIPTION" type="string">
      Human-readable description.
    </ParamField>
  </Accordion>

  <Accordion title="Write Configuration">
    <ParamField path="WRITABLE" type="boolean">
      Allow writing to this node. Default: false.
    </ParamField>

    <ParamField path="DESTINATION_TOPIC" type="string">
      Topic to send write commands. Publish a value here to write it to the PLC.
    </ParamField>
  </Accordion>
</AccordionGroup>

***

## Event-Based Operations

For on-demand OPC UA operations (not polling), use the EVENT syntax. Publish a message to SOURCE\_TOPIC to trigger the operation; the route executes it and publishes the result to DESTINATION\_TOPIC.

### Supported Operations

| Operation | Description                 | Query Parameters                |
| --------- | --------------------------- | ------------------------------- |
| `READ`    | Read a node value on demand | `node_id`, `data_type`          |
| `WRITE`   | Write a value to a node     | `node_id`, `data_type`, `value` |

### Query Parameters

| Parameter   | Description                       | Example                              |
| ----------- | --------------------------------- | ------------------------------------ |
| `operation` | Operation type: `READ` or `WRITE` | `READ`                               |
| `node_id`   | OPC UA NodeId (string or numeric) | `ns=2;i=2`, `ns=2;s=Process.Temp`    |
| `data_type` | OPC UA data type                  | `INT32`, `FLOAT`, `DOUBLE`, `STRING` |
| `value`     | Value to write (WRITE only)       | `42`, `23.5`, `"hello"`              |

### Read Example

Read a node value on demand:

```lot theme={null}
ADD EVENT ReadOnDemand
    WITH SOURCE_TOPIC "opcua/commands/read"
    WITH DESTINATION_TOPIC "opcua/responses/read"
    WITH QUERY "{operation: READ, node_id: ns=2;i=2, data_type: INT32}"
```

### Write Example

Write a FLOAT value to a node on demand:

```lot theme={null}
ADD EVENT WriteSetpoint
    WITH SOURCE_TOPIC "opcua/commands/write"
    WITH DESTINATION_TOPIC "opcua/responses/write"
    WITH QUERY "{operation: WRITE, node_id: ns=2;s=Process.Setpoint, data_type: FLOAT, value: 75.0}"
```

***

## Complete Examples

<Tabs>
  <Tab title="Basic Connection">
    Simple OPC UA connection with anonymous access:

    ```lot theme={null}
    DEFINE ROUTE OPCServer WITH TYPE OPCUA
        ADD OPCUA_CONFIG
            WITH ENDPOINT_URL "opc.tcp://192.168.1.100:4840"
            WITH AUTH_MODE 0
            WITH AUTO_ACCEPT_UNTRUSTED_CERTIFICATES "true"
        ADD MAPPING ProcessData
            WITH EVERY 1 SECOND
            ADD TAG Temperature
                WITH ADDRESS "ns=2;s=Channel1.Device1.Temperature"
                WITH DATA_TYPE "FLOAT"
                WITH SOURCE_TOPIC "opcua/temperature"
                WITH UNIT "°C"
            ADD TAG Pressure
                WITH ADDRESS "ns=2;s=Channel1.Device1.Pressure"
                WITH DATA_TYPE "FLOAT"
                WITH SOURCE_TOPIC "opcua/pressure"
                WITH UNIT "bar"
            ADD TAG Status
                WITH ADDRESS "ns=2;s=Channel1.Device1.Status"
                WITH DATA_TYPE "INT32"
                WITH SOURCE_TOPIC "opcua/status"
    ```
  </Tab>

  <Tab title="Secure Connection">
    Production setup with encryption:

    ```lot theme={null}
    DEFINE ROUTE SecureOPC WITH TYPE OPCUA
        ADD OPCUA_CONFIG
            WITH ENDPOINT_URL "opc.tcp://192.168.1.100:4840"
            WITH AUTH_MODE 1
            WITH USERNAME "operator"
            WITH PASSWORD "secure_password_here"
            WITH USE_SECURITY "true"
            WITH SECURITY_POLICY 3
            WITH MESSAGE_SECURITY 2
            WITH TIMEOUT 30000
        ADD MAPPING SecureData
            WITH EVERY 500 MILLISECONDS
            ADD TAG CriticalValue
                WITH ADDRESS "ns=2;s=Safety.CriticalValue"
                WITH DATA_TYPE "FLOAT"
                WITH SOURCE_TOPIC "secure/critical"
                WITH PUBLISH_MODE "JSON"
    ```
  </Tab>

  <Tab title="BrowsePath Mode">
    Using symbolic paths:

    ```lot theme={null}
    DEFINE ROUTE BrowsePathOPC WITH TYPE OPCUA
        ADD OPCUA_CONFIG
            WITH ENDPOINT_URL "opc.tcp://192.168.1.100:4840"
            WITH AUTH_MODE 0
            WITH USE_BROWSE_PATH "true"
            WITH BROWSE_ROOT_PATH "Objects"
            WITH AUTO_ACCEPT_UNTRUSTED_CERTIFICATES "true"
        ADD MAPPING ProcessTags
            WITH EVERY 1 SECOND
            ADD TAG Temperature
                WITH ADDRESS "DataAccess/AnalogItems/Temperature"
                WITH DATA_TYPE "DOUBLE"
                WITH SOURCE_TOPIC "opcua/temperature"
            ADD TAG Setpoint
                WITH ADDRESS "DataAccess/AnalogItems/Setpoint"
                WITH DATA_TYPE "DOUBLE"
                WITH SOURCE_TOPIC "opcua/setpoint"
                WITH WRITABLE "true"
                WITH DESTINATION_TOPIC "opcua/setpoint/write"
    ```
  </Tab>

  <Tab title="Array Values">
    Reading array data:

    ```lot theme={null}
    DEFINE ROUTE ArrayOPC WITH TYPE OPCUA
        ADD OPCUA_CONFIG
            WITH ENDPOINT_URL "opc.tcp://192.168.1.100:4840"
            WITH AUTH_MODE 0
            WITH AUTO_ACCEPT_UNTRUSTED_CERTIFICATES "true"
        ADD MAPPING ArrayData
            WITH EVERY 1 SECOND
            ADD TAG TemperatureArray
                WITH ADDRESS "ns=2;s=Process.TemperatureArray"
                WITH DATA_TYPE "FLOAT"
                WITH IS_ARRAY "true"
                WITH SOURCE_TOPIC "opcua/temperatures"
                WITH PUBLISH_MODE "JSON"
            ADD TAG StatusBits
                WITH ADDRESS "ns=2;s=Process.StatusBits"
                WITH DATA_TYPE "BOOLEAN"
                WITH IS_ARRAY "true"
                WITH SOURCE_TOPIC "opcua/status/bits"
    ```
  </Tab>

  <Tab title="Kepware Connection">
    Connecting to Kepware OPC UA server:

    ```lot theme={null}
    DEFINE ROUTE KepwareServer WITH TYPE OPCUA
        ADD OPCUA_CONFIG
            WITH ENDPOINT_URL "opc.tcp://192.168.1.50:49320"
            WITH AUTH_MODE 0
            WITH AUTO_ACCEPT_UNTRUSTED_CERTIFICATES "true"
        ADD MAPPING KepwareTags
            WITH EVERY 500 MILLISECONDS
            ADD TAG Motor1Speed
                WITH ADDRESS "ns=2;s=Channel1.Device1.Motor1_Speed"
                WITH DATA_TYPE "FLOAT"
                WITH SOURCE_TOPIC "kepware/motor1/speed"
                WITH UNIT "RPM"
            ADD TAG Motor1Current
                WITH ADDRESS "ns=2;s=Channel1.Device1.Motor1_Current"
                WITH DATA_TYPE "FLOAT"
                WITH SOURCE_TOPIC "kepware/motor1/current"
                WITH UNIT "A"
            ADD TAG Motor1Running
                WITH ADDRESS "ns=2;s=Channel1.Device1.Motor1_Running"
                WITH DATA_TYPE "BOOLEAN"
                WITH SOURCE_TOPIC "kepware/motor1/running"
    ```
  </Tab>

  <Tab title="Combined (Cyclic + On-Demand)">
    Continuous monitoring with on-demand read and write events in the same route:

    ```lot theme={null}
    DEFINE ROUTE FullOPCSetup WITH TYPE OPCUA
        ADD OPCUA_CONFIG
            WITH ENDPOINT_URL "opc.tcp://192.168.1.100:4840"
            WITH AUTH_MODE 0
            WITH AUTO_ACCEPT_UNTRUSTED_CERTIFICATES "true"
        
        ADD MAPPING ProcessData
            WITH EVERY 1 SECOND
            ADD TAG Temperature
                WITH ADDRESS "ns=2;s=Channel1.Device1.Temperature"
                WITH DATA_TYPE "FLOAT"
                WITH SOURCE_TOPIC "opcua/temperature"
                WITH UNIT "°C"
            ADD TAG Pressure
                WITH ADDRESS "ns=2;s=Channel1.Device1.Pressure"
                WITH DATA_TYPE "FLOAT"
                WITH SOURCE_TOPIC "opcua/pressure"
                WITH UNIT "bar"
        
        ADD EVENT ReadNode
            WITH SOURCE_TOPIC "opcua/commands/read"
            WITH DESTINATION_TOPIC "opcua/responses/read"
            WITH QUERY "{operation: READ, node_id: ns=2;s=Channel1.Device1.Status, data_type: INT32}"
        
        ADD EVENT WriteSetpoint
            WITH SOURCE_TOPIC "opcua/commands/write"
            WITH DESTINATION_TOPIC "opcua/responses/write"
            WITH QUERY "{operation: WRITE, node_id: ns=2;s=Channel1.Device1.Setpoint, data_type: FLOAT, value: 0}"
    ```

    The MAPPING continuously reads temperature and pressure. To trigger an on-demand status read, publish any message to `opcua/commands/read`. To write a setpoint, publish to `opcua/commands/write`.
  </Tab>
</Tabs>

***

## Security Best Practices

<AccordionGroup>
  <Accordion title="Use Encryption in Production">
    Always enable security for production deployments:

    ```lot theme={null}
    WITH USE_SECURITY "true"
    WITH SECURITY_POLICY 3  // Basic256Sha256
    WITH MESSAGE_SECURITY 2  // SignAndEncrypt
    ```
  </Accordion>

  <Accordion title="Don't Auto-Accept Certificates">
    In production, properly configure certificate trust:

    ```lot theme={null}
    WITH AUTO_ACCEPT_UNTRUSTED_CERTIFICATES "false"
    ```

    Instead, exchange certificates between client and server during commissioning.
  </Accordion>

  <Accordion title="Use Strong Authentication">
    Prefer username/password or certificate authentication over anonymous:

    ```lot theme={null}
    WITH AUTH_MODE 1  // or '2' for certificate
    WITH USERNAME "operator"
    WITH PASSWORD "strong_password_here"
    ```
  </Accordion>
</AccordionGroup>

***

## Troubleshooting

<AccordionGroup>
  <Accordion title="Connection Timeout">
    * Verify endpoint URL is correct
    * Check firewall allows TCP port (usually 4840)
    * Ensure server is running and accessible
    * Try increasing TIMEOUT value
  </Accordion>

  <Accordion title="Security Rejection">
    * Verify security policy matches server configuration
    * Check certificate trust (may need to accept in server)
    * For testing, try `WITH AUTO_ACCEPT_UNTRUSTED_CERTIFICATES "true"`
    * Ensure client certificates are properly configured
  </Accordion>

  <Accordion title="NodeId Not Found">
    * Use OPC UA browser to verify correct NodeId
    * Check namespace index (ns=) is correct
    * Verify node exists in server's address space
    * Try BrowsePath mode if NodeId is unclear
  </Accordion>

  <Accordion title="Authentication Failed">
    * Verify username and password
    * Check user has appropriate permissions
    * Ensure AUTH\_MODE matches server requirements
  </Accordion>

  <Accordion title="Incorrect Values">
    * Verify DATA\_TYPE matches server variable type
    * Check IS\_ARRAY setting for array values
    * Verify SCALING and OFFSET calculations
  </Accordion>
</AccordionGroup>

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Siemens S7" icon="microchip" href="./siemens-s7">
    Direct connection to Siemens PLCs.
  </Card>

  <Card title="ADS (Beckhoff)" icon="gear" href="./ads">
    Connect to TwinCAT systems.
  </Card>
</CardGroup>
