OPC UA Alarms & Conditions: Getting Retain, Acknowledge, and Reconnect Right in SCADA
Commissioning OPC UA Alarm & Condition subscriptions: event filters, the Retain flag, ConditionRefresh, and the failures that appear on reconnect.
The analog faceplates all update, so you sign off the OPC UA link and move on. Then a limit trips, the alarm summary stays empty — or worse, the alarm comes in, clears two seconds later, and disappears before the operator ever saw the row. A clean value subscription tells you nothing about whether alarms will actually arrive, stay on the list, and acknowledge.
That is because Alarm & Condition (OPC UA Part 9) is a different mechanism from data access (Part 4/8). Data access subscribes to value changes on a node. A&C subscribes the client to events on an event-notifier object, delivers condition state changes, and expects the client to call methods — Acknowledge, Confirm, Enable, Disable, Shelve, Unshelve. Importing alarm tags the same way you import analog tags is how you end up with an alarm summary nobody trusts. Give A&C its own test plan.
Confirm the server actually exposes events
Browse the server with a UA client that can read the EventNotifier attribute (UaExpert's attribute view does this). An object only delivers events if bit 0 (SubscribeToEvents) of its EventNotifier is set. Point at the exact node the SCADA runtime will subscribe to — the Server object, an area folder, or an equipment object — not a parent that looks close enough.
Record five things before you go further:
| Item | What to verify |
|---|---|
| Event source | The node whose EventNotifier has SubscribeToEvents set — Server object, area, equipment, or vendor folder |
| Condition types | AlarmConditionType, LimitAlarmType, OffNormalAlarmType, or a vendor subtype |
| Methods | Acknowledge, Confirm, Shelve, Unshelve, Enable, Disable — which ones you actually need |
| ConditionRefresh | The Server object exposes ConditionRefresh (you will need it after every reconnect — see below) |
| Security | The runtime account, not your engineering login, can receive events and call the alarm methods |
Browse from the same network segment and with the same credentials the SCADA runtime will use. Vendor screenshots prove nothing — I have seen an A&C browse work fine from the engineering laptop and return zero events from the runtime account because the role lacked the event permission.
Build the event filter deliberately
The event filter (a SelectClause list) decides which fields land in the client. Too narrow and the alarm row shows a message with no source, no active state, no severity. Too wide and you flood the summary with events that were never operator alarms.
The fields I always select:
EventId,EventType,SourceNode,SourceName,TimeMessage,Severity,ConditionName,ConditionClassId,ConditionClassNameActiveState,AckedState,ConfirmedState,EnabledState,RetainQualityandLastSeverityif the server populates themBranchIdwhen the server uses alarm branches
ActiveState, AckedState, and the rest are TwoStateVariableType — you want both the boolean Id and the human-readable text, so select the Id sub-field explicitly or your list shows "Active/Inactive" strings you cannot filter on.
Point the filter at a throwaway event view first. Missing fields are a five-minute fix before operators depend on the display and a change-control headache after.
Retain is the alarm-list gate, not ActiveState
This is where most alarm summaries go wrong. Retain tells the client whether a condition is still of interest to an operator. A condition can be inactive but still retained because it hasn't been acknowledged yet.
The classic bug: drop the row the instant ActiveState goes false. That erases every alarm that cleared before the operator got to it — exactly the fleeting alarms you most want to see. The opposite bug is keeping every event forever, which turns your alarm summary into an event journal.
Drive Retain (not ActiveState) as the "show this row" flag, and test all five transitions:
- Active, unacknowledged.
- Cleared before anyone acknowledged it (inactive, still Retain=true).
- Acknowledged while still active.
- Acknowledged after it cleared (Retain should finally go false).
- Requires Confirm after Acknowledge.
Whatever the site's alarm philosophy decides for row lifetime, every client must apply the same rule.
Prove the acknowledge path end to end
Acknowledge is a method call, not a write. The client sends the condition's current EventId plus an optional operator comment, and has to handle the server's return status. Things I check from the HMI itself:
- Operator role can acknowledge only its own areas.
- A denied acknowledge fails visibly — no silent swallow.
- The comment lands in the server audit trail or the SCADA event journal.
- The row updates without a client restart.
- An acknowledge from another client shows up here.
Watch out for servers that recycle EventId quickly: a stale row can become impossible to acknowledge because the EventId the client is holding no longer resolves. Test a long-standing alarm and one that flickers.
Don't wave the timestamps through
Alarm event time drives incident reviews, so a screen that merely "looks about right" isn't good enough. Line up four clocks for one event: the UA Time field, the SCADA receive time, the historian event time, and the operator workstation display. The usual offenders:
- Local time shown with no zone label.
- DST offset flipping on a long-running system.
- Clock drift between PLC, OPC UA server, SCADA server, and the domain time source (a couple hundred ms is enough to reorder a fast sequence).
- The list sorted by receive time instead of event time.
- Milliseconds truncated on the way into SQL.
Capture at least one alarm showing its raw UA timestamp next to the HMI display for the commissioning record.
The failures that wait for a reconnect
A&C mostly behaves until the system is under load or a link drops and comes back. The one that catches people every time: after a reconnect the client must call ConditionRefresh, or it never re-receives the currently-retained conditions and the alarm list silently goes stale. The server answers with a RefreshStartMOEvent, replays the retained conditions, and closes with RefreshEndMOEvent. If your client doesn't do this on reconnect, the summary looks calm while real alarms are standing.
Others I've hit:
- Client subscribed to a node with no events — zero alarms, no error.
- Filter omits
RetainorAckedState, so row management can't work. - Severity mapping inverted or crushed — remember OPC UA severity is 1–1000 (1 lowest, 1000 highest); don't compress it to three priorities and lose the ordering.
- Client only handles standard condition types and ignores the vendor subtype the alarms actually use.
- Shelving state visible on one client, not another.
- Method calls fail under the runtime service account that worked under the engineering account.
So put a cable pull or an OPC UA server restart in the test plan. A&C commissioning is not finished until retained alarms come back after the reconnect.
What to keep with the project file
A small evidence packet that pays for itself the first time someone asks whether a missed alarm was the PLC, the server, or the client:
- Export or screenshot of the event subscription source (with its EventNotifier value).
- The event filter field list.
- Alarm list screenshots for active, cleared-unacknowledged, acknowledged, and shelved.
- The user role used for the acknowledge and shelve tests.
- One raw event sample with
EventId,SourceName,Time,Message,Severity,Retain,ActiveState,AckedState. - The reconnect test result and how long retained alarms took to recover.