opcua-client · v4.6.x
Docs · Operations

Monitored items

Monitored items live inside subscriptions. Each one watches a single attribute (usually Value) or an event source, with its own sampling rate, queue size, and trigger.

A monitored item is the unit of observation inside a subscription. There are two flavours:

  • Data-change monitored items — watch the Value (or another attribute) of a node and emit a notification when it crosses a configurable filter (deadband, sampling rate).
  • Event monitored items — watch an Object node that emits OPC UA events and emit a notification when one matches the event filter (severity, type, contents).

Both share the same CRUD operations on the client; the difference is in how the server reports back.

Creating data-change items

php array form
$sub = $client->createSubscription(publishingInterval: 250.0);

$results = $client->createMonitoredItems($sub->subscriptionId, [
    ['nodeId' => 'ns=2;s=PLC/Speed',    'samplingInterval' => 250.0, 'queueSize' => 10],
    ['nodeId' => 'ns=2;s=PLC/Mode',     'samplingInterval' => 1000.0],
    ['nodeId' => 'ns=2;s=PLC/Health',   'samplingInterval' => 1000.0],
]);

foreach ($results as $r) {
    if ($r->statusCode !== 0) {
        // BadNodeIdUnknown, BadAttributeIdInvalid, BadMonitoringModeInvalid …
    }
}

MonitoredItemResult:

Field Meaning
statusCode Per-item creation status
monitoredItemId Server handle — needed for modify / delete
revisedSamplingInterval Actual interval (may differ from requested)
revisedQueueSize Actual queue size
selectClauseResults Event items: status of each select clause, in order (empty when the server sends none)

Fluent builder

php fluent form
$results = $client->createMonitoredItems($sub->subscriptionId)
    ->add('ns=2;s=PLC/Speed')->samplingInterval(250.0)->queueSize(10)
    ->add('ns=2;s=PLC/Mode')->samplingInterval(1000.0)
    ->add('ns=2;s=PLC/Health')->samplingInterval(1000.0)
    ->execute();

Builder methods, accumulated against the most recent add():

Method Meaning
add(NodeId|string) Start a new item
samplingInterval(float) Target ms; 0 = server-default
queueSize(int) Server-side notification queue depth (default 1)
clientHandle(int) Caller-defined correlation handle
attributeId(int) Which attribute to monitor (default Value)
monitoringMode(int) 0 Disabled, 1 Sampling, 2 Reporting (default)
discardOldest(bool) Drop the oldest queued value when the queue is full (default true)
dataChangeFilter(int $trigger = 1, int $deadbandType = 0, float $deadbandValue = 0.0) Set a DataChangeFilter — see below
execute() Issue the call

Without queueSize an item gets a single-slot queue that keeps only the latest sample, so intermediate values are overwritten silently — see DataValue and Variant · Overflow and limit bits. Without clientHandle, the library assigns each item its position in the list plus one.

Data change filter

The filter key (or dataChangeFilter() on the builder) sets a DataChangeFilter, which decides which changes produce a notification:

Key Values Default
trigger 0 Status, 1 StatusValue, 2 StatusValueTimestamp 1
deadbandType 0 None, 1 Absolute, 2 Percent 0
deadbandValue Engineering units (Absolute) or a percentage of the variable's EURange (Percent) 0.0
php absolute deadband
$results = $client->createMonitoredItems($sub->subscriptionId, [
    [
        'nodeId'           => 'ns=2;s=Sensors/Temperature',
        'samplingInterval' => 250.0,
        'filter'           => ['deadbandType' => 1, 'deadbandValue' => 0.5],
    ],
]);

With an Absolute deadband, a value is reported only when it differs from the last reported value by more than deadbandValue. Against UA-.NETStandard, with a deadband of 5 on a value of 100, a write of 102 produces no notification and a following write of 110 does.

A Percent deadband needs an AnalogItemType variable with an EURange; on any other variable the server rejects the item with a Bad statusCode, which is why checking every MonitoredItemResult matters. Without filter no filter is sent, and the server reports every change of status or value.

Creating event items

Event monitoring is a single-item shortcut — attach a list of event fields to a single object (typically Server for global events, or a specific device emitting alarms). The $clientHandle is the caller-defined integer used to correlate incoming EventNotificationReceived events back to this item.

php example event monitoring
$result = $client->createEventMonitoredItem(
    subscriptionId: $sub->subscriptionId,
    nodeId:         'i=2253',          // Server object
    selectFields:   ['SourceName', 'Message', 'Severity', 'EventType'],
    clientHandle:   42,
);

Omitting $selectFields keeps the default set (EventId, EventType, SourceName, Time, Message, Severity). The method publishes a simple SelectClauses-only event filter; for a structured WhereClause filter, drop down to the underlying SubscriptionModule services. Refer to OPC UA Part 4 §7.22 for the formal event filter grammar.

Alarms

OPC UA alarms are events with extra fields. When the dispatcher receives an event notification whose payload exposes alarm-typed fields (AckedState, ActiveState, Severity, OffNormalState), the client auto-deduces and dispatches one of the alarm-specific events:

Event Trigger
AlarmEventReceived Any alarm-shaped event
AlarmActivated ActiveState transitioned to Active
AlarmDeactivated ActiveState transitioned to Inactive
AlarmAcknowledged AckedState transitioned to acknowledged
AlarmConfirmed ConfirmedState transitioned to confirmed
AlarmShelved Shelved/Unshelved transitions
AlarmSeverityChanged Severity changed
LimitAlarmExceeded LimitAlarmType variants
OffNormalAlarmTriggered OffNormalAlarmType variants

Wire a PSR-14 listener for the events you care about — there is no need to interpret the raw payload yourself for these cases. See Observability · Event reference.

Rejected select clauses

When the server rejects a select clause of an event item, it reports one status per clause in selectClauseResults, in the order of $selectFields. Against open62541, ['EventId', 'DoesNotExist', 'Severity'] rejects the item with BadNodeIdUnknown and reports [Good, BadNodeIdUnknown, Good]. UA-.NETStandard accepts unknown clauses with a Good item and no per-clause results; the field then arrives empty in every notification.

Modifying

Change sampling interval, queue size, client handle, discard policy or data change filter without deleting and recreating the item.

This is not a partial update. Every item is sent with all of its parameters, and a key you leave out is sent as a default — the server does not keep the previous value:

Omitted key Sent as Effect on the server
clientHandle 0 Notifications arrive with handle 0; a handle-to-node map no longer matches them
queueSize 0 Revised to a single-slot queue
samplingInterval -1 Samples at the subscription's publishing interval
discardOldest true The oldest value is dropped when the queue is full
filter none Any data change filter the item had is removed

Against UA-.NETStandard, modifying only the samplingInterval of an item created with clientHandle: 7 and queueSize: 10 returns Good with revisedQueueSize: 1, and every notification after it carries clientHandle 0. Always pass every parameter you want to keep:

php modify sampling rate
$client->modifyMonitoredItems($sub->subscriptionId, [
    [
        'monitoredItemId'  => $results[0]->monitoredItemId,
        'clientHandle'     => 1,        // the handle it was created with
        'samplingInterval' => 1000.0,
        'queueSize'        => 20,
        'discardOldest'    => true,
    ],
]);

Triggering

OPC UA's SetTriggering service links monitored items such that one item's notification causes another to also fire — useful when you want a "slow" diagnostic stream to spike to "fast" sampling on demand.

php link a triggering chain
$result = $client->setTriggering(
    subscriptionId:   $sub->subscriptionId,
    triggeringItemId: $alarmItem,
    linksToAdd:       [$slowDiagItem1, $slowDiagItem2],
);

SetTriggeringResult exposes addResults and removeResults arrays — one status code per link operation.

Deleting

Frees server-side resources for the items but keeps the subscription alive. Returns a parallel array of per-item status codes.

Warning

Deleting a monitored item does not drain the server's pending notification queue for that item. Late notifications can still arrive in the next publish() reply. Filter them by monitoredItemId on the client side if relevance is critical.