Class OpcuaClient

Nested Relationships

Nested Types

Class Documentation

class OpcuaClient

RAII wrapper around open62541pp::Client with auto-reconnect.

Public Types

enum class WriteError

OPC-UA write error classification.

Values:

enumerator NotConnected
enumerator TypeMismatch
enumerator AccessDenied
enumerator NodeNotFound
enumerator TransportError
enum class MethodError

OPC-UA Method call error classification.

Values:

enumerator NotConnected
enumerator MethodNotFound
enumerator InvalidArgument
enumerator MethodTimeout
enumerator TransportError
using EventBrowsePath = std::vector<EventField>

Browse path for an event field, e.g. {{0, "EnabledState"}, {0, "Id"}}.

using EventCallback = std::function<void(const std::vector<opcua::Variant> &select_values, const opcua::NodeId &source_node, const opcua::NodeId &event_type, const opcua::NodeId &condition_id)>

Callback invoked when an OPC-UA event arrives on a monitored item.

Param select_values:

Values for caller-requested fields, in the order of select_specs passed to add_event_monitored_item.

Param source_node:

Always-included SourceNode (extracted from the event payload; null NodeId if the server omitted it).

Param event_type:

Always-included EventType (null NodeId if absent).

Param condition_id:

NodeId of the condition instance that emitted the event (Part 9 §5.5.2.13). Null NodeId for non-condition events.

Public Functions

OpcuaClient()
~OpcuaClient()
OpcuaClient(const OpcuaClient&) = delete
OpcuaClient &operator=(const OpcuaClient&) = delete
bool connect(const OpcuaClientConfig &config)

Connect to OPC-UA server

Returns:

true if connected successfully

void disconnect()

Disconnect and stop reconnect attempts.

bool is_connected() const

Check if currently connected.

std::string endpoint_url() const

Get the endpoint URL (for status reporting)

OpcuaClientConfig current_config() const

Get the current config (for reconnection)

std::vector<std::string> browse(const opcua::NodeId &parent_node)

Browse child nodes of a given node

Returns:

Vector of child node ID strings (e.g., “ns=1;s=TankLevel”)

ReadResult read_value(const opcua::NodeId &node_id)

Read a single value.

std::vector<ReadResult> read_values(const std::vector<opcua::NodeId> &node_ids)

Read multiple values.

tl::expected<void, WriteErrorInfo> write_value(const opcua::NodeId &node_id, const OpcuaValue &value, const std::string &data_type_hint = "")

Write a value to a node

Parameters:

data_type_hint – If non-empty, skip readValue type-probe and use this hint (“bool”, “int”, “float”, “string”) to select the write coercion directly. Halves mutex hold time by eliminating a round-trip to the server.

Returns:

void on success, WriteErrorInfo on failure with specific error code

uint32_t create_subscription(double publish_interval_ms, DataChangeCallback callback)

Create a subscription with data change notifications

Returns:

Subscription ID, or 0 on failure

bool add_monitored_item(uint32_t subscription_id, const opcua::NodeId &node_id)

Add a monitored item to a subscription

Returns:

true if item was added

void remove_subscriptions()

Remove all subscriptions.

uint64_t current_generation() const

Get the current subscription generation. Increments on every detected disconnect (clean disconnect() or transport-level drop). Used by the internal event trampoline to drop callbacks fired from defunct subscriptions.

void run_iterate(uint16_t timeout_ms = 100)

Run a single iteration of the open62541 client main loop. Required to dispatch incoming subscription notifications (events, data changes) to their callbacks. The poller calls this every iteration to keep AlarmCondition events flowing.

uint32_t add_event_monitored_item(uint32_t subscription_id, const opcua::NodeId &source_node, const std::vector<EventFieldSpec> &select_specs, EventCallback callback)

Add an event-based monitored item to an existing subscription.

Wraps UA_Client_MonitoredItems_createEvent from the open62541 C API because open62541pp v0.16 has no native EventFilter / event subscription support. EventType, SourceNode and a ConditionId SAO (empty BrowsePath, AttributeId=NodeId) are always prepended; they are extracted from the event payload and delivered as separate callback parameters, not in select_values.

Returns:

Server-assigned monitored item ID, or 0 on failure.

bool remove_event_monitored_item(uint32_t subscription_id, uint32_t mi_id)

Remove a previously-added event monitored item. The server is asked to delete the item synchronously; the callback context is freed only after the server ACK so in-flight C callbacks cannot dangle.

Returns:

true if the item was found and removed cleanly.

tl::expected<std::vector<opcua::Variant>, MethodErrorInfo> call_method(const opcua::NodeId &object_id, const opcua::NodeId &method_id, const std::vector<opcua::Variant> &input_args)

Synchronously call an OPC-UA Method on a target object. Used by ConditionRefresh, Acknowledge, and Confirm operations on AlarmConditionType nodes (issue #386).

Returns:

Output arguments on success, MethodErrorInfo on failure.

std::string server_description() const

Get server description string (for status endpoint)

Public Static Functions

static MethodErrorInfo status_to_method_error(uint32_t code, const std::string &message)

Map an OPC-UA StatusCode (from an attempted method call or a per-argument validation result) to a MethodError category. Exposed as a public static helper so the classification table is covered by unit tests without needing a live OPC-UA connection.

static tl::expected<void, MethodErrorInfo> classify_call_result(uint32_t overall_status_code, const std::vector<uint32_t> &arg_results)

Classify the full result of a Call service exchange per OPC-UA Part 4 §5.11.2: overall statusCode covers transport / method resolution; inputArgumentResults covers per-argument validation. Returns success when both are Good. The first non-Good code wins: overall statusCode takes precedence, then arg_results in order. AlarmConditionType.Acknowledge surfaces BadEventIdUnknown in arg_results[0] when the EventId we cached has been superseded. Exposed as a static for unit-test coverage of the per-arg branch.

struct EventField

One element of an OPC-UA SimpleAttributeOperand browse path.

Public Members

uint16_t namespace_index = {0}
std::string name
struct EventFieldSpec

Full SimpleAttributeOperand spec - every clause in an EventFilter must have typeDefinitionId set to the type that directly defines the browse path’s first segment (open62541 servers reject inherited lookups with BadNodeIdUnknown). ConditionId is the documented edge case (Part 9 §5.5.2.13): empty browse path + AttributeId=NodeId.

Public Members

opcua::NodeId type_definition_id
EventBrowsePath browse_path
uint32_t attribute_id = {13}
struct MethodErrorInfo

Detailed Method call error info.

Public Members

MethodError code
std::string message
struct WriteErrorInfo

Detailed write error info.

Public Members

WriteError code
std::string message