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
Objectnode 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
$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 |
Fluent builder
$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) |
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.
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.
$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.
Modifying
Change sampling interval, queue size, client handle or discard policy 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 |
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:
$client->modifyMonitoredItems($sub->subscriptionId, [
[
'monitoredItemId' => $results[0]->monitoredItemId,
'clientHandle' => 1, // the handle it was created with
'samplingInterval' => 1000.0,
'queueSize' => 20,
'discardOldest' => true,
],
]);
discardOldest can only be chosen here: createMonitoredItems()
always creates items with 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.
$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.
What to read next
- Recipes · Subscribing to data changes — a complete worker-style example.
- Observability · Event reference — every dispatcher event the subscription path emits.