OPC UA Event Filters: Validate Select Clauses Before a Silent Alarm Subscription Ships

An EventFilter has two independent jobs: whereClause decides which ordinary Events qualify, and selectClauses define the ordered fields returned for each qualifying Event. A successful subscription or a nonempty event stream does not prove that the requested event types and fields are correct. Validate construction results, runtime field values and the client’s positional decoder separately.

This guide pins OPC UA Part 4, version 1.05.07, sections 7.7, 7.22.3 and 7.25.3, with Part 5, version 1.05.06, section 6.4.2 for BaseEventType fields. This is a source-derived qualification procedure. No event server, filter evaluator or alarm application was executed.

Start at the EventNotifier boundary

Create event monitoring against the EventNotifier Attribute of the intended node, using a supported EventFilter. Confirm that the chosen notifier exposes the events required by the product. Receiving unrelated events from a different notifier does not validate the intended source path.

Record server and SDK versions, notifier identity, monitoring mode, client handle and the full filter. Keep a known controlled event generator available in an isolated test model. Testing by waiting for an unpredictable real alarm makes a silent filter difficult to diagnose.

Begin with a broad supported filter and a small set of known base fields, then introduce restrictions one at a time. This separates “no event reaches this notifier” from “the predicate excluded it” and “the client decoded the wrong field slot.”

EventFilter construction validates select clauses and the where clause separately. At runtime the where clause gates ordinary Events, then the select clauses create a positional field array. Each field is decoded as a value, null or StatusCode using the same ordered selection contract. Queue-overflow control Events bypass the where clause.
Construction acceptance, event selection and field decoding are different diagnostic boundaries.

Make the selected-field order an interface

EventNotificationList returns each Event as an array of fields in exactly the order selected by the EventFilter, with a clientHandle identifying the MonitoredItem. Preserve that ordered schema beside the handle; do not search the returned array for values that merely resemble a timestamp or a severity.

Example slot Selected field Consumer contract
0 EventId ByteString event identity
1 EventType NodeId identifying the event type
2 ReceiveTime Server-side event receipt time
3 Severity Typed severity field
4 Example custom Pressure Value only for a supporting hypothetical event model

The first four names come from BaseEventType; Pressure is an invented test-model field, not a standard field guaranteed on every Event. A client that swaps slots two and three when modifying a filter can misinterpret a perfectly valid response.

Qualify filter-change handling with the SDK. Queued or in-flight delivery must remain associated with the selection contract that produced it. If the application cannot distinguish those boundaries reliably, use a documented drain or recreation procedure rather than replacing one global field-index table while callbacks are active.

Validate each SimpleAttributeOperand

A selection identifies an EventType, a browsePath expressed as QualifiedNames, an Attribute and optionally an indexRange. The path follows hierarchical declarations; it is not an arbitrary display-name search. Namespace identity in every QualifiedName matters.

For event fields, the server is required to support Value for Variable nodes and NodeId for Object nodes; profiles may require more. Object nodes in this context are available only for Events visible in the AddressSpace. Do not assume every imaginable Attribute is supported because its integer identifier is syntactically valid.

Selecting with BaseEventType has special behavior: the server evaluates the browsePath without considering the operand’s typeDefinitionId. Therefore a select clause is not a substitute for an explicit event-type predicate in whereClause.

Read filter results beyond the service status

The EventFilterResult contains selectClauseResults in the same order as the requested selections and a separate whereClauseResult. Inspect both after create or update. At least one valid selection is required.

Useful deliberately invalid tests include a non-EventType type identifier, a null BrowseName in the path, an unsupported Attribute and an index range against a field that is always scalar. The standard defines specific result categories such as Bad_TypeDefinitionInvalid, Bad_BrowseNameInvalid and Bad_TypeMismatch for these conditions.

Do not require every unknown path to fail immediately. An aggregating server may not know all possible EventTypes when the filter is installed. Construction validation reports errors true for all possible Events; failures dependent on a particular Event or runtime state can remain a delivery-time issue.

Distinguish null from a StatusCode field

A selected field absent from the particular Event, or rejected during selection validation, returns null in its corresponding position. The server does not remove the slot and shift later fields left.

A supported field that is unavailable at notification time instead carries a StatusCode explaining why. Examples include access denial. A Value Attribute with uncertain or bad status is represented by that StatusCode rather than its normal value. Preserve the Variant type and do not coerce these cases to numeric zero.

EventId, EventType and ReceiveTime are exceptions: they cannot contain a null or StatusCode under these rules. Treat a violation as a decoding or server-contract problem rather than a normal optional-field case.

Test the predicate independently

OfType matches the specified type and its subtypes. Use it deliberately when the required event family includes derived types. A comparison to one exact EventType identity expresses a different intention and can omit derived events.

Basic filter operators are allowed in whereClause; among the additional operators listed in Part 4’s complex-operator table, only OfType is permitted for EventFilter. AttributeOperand is not permitted there. Validate the expression’s structure and operand types instead of assuming that a generic query filter is interchangeable with an event filter.

Runtime operand failures use null during whereClause evaluation, which can prevent the intended predicate from qualifying an Event. Also account for EventQueueOverflowEventType control notifications: they bypass whereClause and should not be discarded merely because they do not match the application’s ordinary event predicate.

A release qualification worksheet

  1. Generate a known base-field event with a broad predicate and confirm each slot’s type and meaning.
  2. Add the hypothetical custom field; test an Event that has it and one that does not.
  3. Exercise unavailable or denied field access in an authorized test configuration and preserve the returned StatusCode.
  4. Add the type predicate and test the intended type, a subtype and an unrelated type.
  5. Submit deliberately invalid selection and predicate operands, then inspect all filter-result layers.
  6. Verify filter-change delivery mapping and handling of queue-overflow control Events.

Acceptance means the client can explain why an Event was admitted, which schema defines each returned slot and why a field is null or unavailable. This validates event-filter integration; it does not establish alarm completeness, operator response or a safety-system claim.

Similar Posts