Skip to content

Alarm Management

Operators respond to alarms in /hmiAlarms. The view lists every alarm in the current site, lets you filter by severity / type / source, drill into detail, acknowledge, shelve, and unshelve. Alarmed unit cards in the process-cell view also flag the condition with an amber border so the alarm is visible without leaving the cell, and each faceplate carries an inline Ack control for unacknowledged alarms on its control module.

This page documents each operator action. Engineering setup (defining which conditions raise an alarm) lives on the control-module page (see Control Modules → Alarm definitions). Worked patterns (valve mismatch, analog deviation, phase interlock) are in Alarms and Interlocks. For historical query, time-range filters, and severity post-processing across resolved events, use /dataAlarm History (see Historian).

Open the Alarms view

From the HMI sidebar, click Alarms. The view opens with the Active sub-tab selected and the current site's alarms in a table showing name, source, type, severity, condition (Active / Cleared), ack state, message, age, and per-row actions. A summary banner above the table totals counts by severity.

HMI → Alarms with the Active sub-tab selected, severity summary banner across the top, filter row beneath, and a table of active alarms with per-row state-gated actions (Ack on unacknowledged rows, and Shelve appears once an alarm is acknowledged)

Alarm states

Every alarm follows the ISA-18.2 four-state model. Two independent flags, condition (Active / Cleared) and acknowledgement (Unack'd / Ack'd), combine to give the four states the controller drives the alarm through:

stateDiagram-v2
    [*] --> ActiveUnacknowledged: Condition met
    ActiveUnacknowledged --> ActiveAcknowledged: Operator Ack
    ActiveUnacknowledged --> ClearedUnacknowledged: Condition cleared
    ActiveAcknowledged --> ClearedAcknowledged: Condition cleared
    ClearedUnacknowledged --> ClearedAcknowledged: Operator Ack
    ClearedAcknowledged --> [*]: Resting (hidden from Active)
    ClearedAcknowledged --> ActiveUnacknowledged: Condition re-fires
    ClearedUnacknowledged --> ActiveUnacknowledged: Condition re-fires

The condition flag is owned by the alarm generator (driven by the underlying tag value or source-state watch). The ack flag is owned by the operator. Both must reach their resting value (Cleared + Ack'd) before an alarm leaves the working set.

The two flags move independently, so a condition that returns re-annunciates from either cleared state. Flapping equipment that recovers before anyone acknowledges lands in ClearedUnacknowledged, and the next occurrence still drives the alarm back to ActiveUnacknowledged, relights the equipment cue, and republishes the MQTT alarm event. Every occurrence gets its own annunciation, whatever the operator did with the previous one.

Each state renders a distinct Condition + Ack badge pair in the alarms list, drives a different cue on equipment cards and faceplates, and gates which actions are offered:

State Condition Ack Equipment cue Actions If the condition returns
ActiveUnacknowledged red Active amber Unack'd amber border + nav icon lit Ack already active, no change
ActiveAcknowledged red Active gray Ack'd none (silenced while the condition stands) Shelve (Unshelve while shelved) already active, no change
ClearedUnacknowledged green Cleared amber Unack'd none (no condition to flag) Ack ActiveUnacknowledged
ClearedAcknowledged green Cleared gray Ack'd none (read-only) ActiveUnacknowledged

ActiveUnacknowledged is the loudest state. The unit card shows an amber border, the Alarms nav icon turns solid amber, and an open faceplate carries an inline ack strip. Acknowledging silences those cues immediately, even when the underlying condition is still present.

When an alarm is deleted

Deletion is not one of the four states. An alarm is deleted when the AlarmDefinition that owns it is removed (removal garbage-collects its alarms), or when an engineer cleans up an orphan whose definition is already gone.

Both paths require acknowledgement first. The gateway refuses to delete an alarm that is ActiveUnacknowledged or ClearedUnacknowledged, and it refuses to delete an AlarmDefinition while any alarm derived from it is in one of those states. An alarm nobody has acknowledged is a condition nobody has accepted, so deleting it erases the annunciation without that acceptance ever happening. Acknowledge the alarm and the deletion goes through, leaving status.acknowledgedBy on the record of who accepted the condition beforehand. Both refusals answer HTTP 409 and are written to the audit trail as a rejected deletion (ADR 0060).

Because deletion is not a transition, it has no alarm event of its own to ride, and the MQTT alarm event is retained. The alarm's last event would otherwise stand on its source's topic as the current truth for every consumer that connected afterwards. The alarm controller closes that: it clears the source's retained event and republishes the alarms that still exist on that source, so an annunciator, a SCADA bridge, or an HMI that connects a week later is never told about an alarm that no longer exists (ADR 0014).

Deleting an alarm is not a way to silence one. The generator recreates it on the next evaluation while its condition holds, and the operator tool for a nuisance alarm is shelving.

Reaction time

How quickly an AlarmDefinition fires after its condition first becomes true depends on whether the condition is state-driven or tag-driven, and on the debounceSeconds configured on the rule. Reaction time is part of the AlarmDefinition contract. It is documented here, and it is not a tunable. See ADR-0002 for the decision record and the alternatives that were considered, and ADR 0007 for the protection layering (device interlock / phase guard / alarm).

Path Reaction time (worst case) Determinism Use for
Device interlock — DO/AO ILCK input or interlockAddress (see Pattern 0) One FB scan, 100–200 ms; always-on, mode-independent, survives control-plane partition Deterministic; evaluated every scan on the edge Equipment interlocks. Forcing a hazardous output to its safe state whenever a trip condition is true.
Phase SFC transition guard at priority: -1 (see Pattern 3) One SFC scan cycle, 100–200 ms; only while the phase executes; requires the control plane Deterministic; re-evaluated every scan Procedural safe-state sequencing. Ordered multi-output responses that park the procedure in a resumable safe-hold.
AlarmDefinition with StateEquals condition < 1 s (watch-driven) Deterministic; fires within one reconcile of the source status update State-based annunciation (IOModule fault, Unit offline).
AlarmDefinition with any tag-based condition (TagHigh, TagLow, TagHighHigh, TagLowLow, TagDeviation, TagTrue, TagFalse) 10 s poll + debounceSeconds — typically 10–60 s end-to-end Polled; bounded by the controller's 10 s tagEvalInterval Process-value annunciation, audit trail, batch-level exceptionAction.
AlarmDefinition with DeviceHealth condition (ADR-0043) 30 s device-health poll + < 1 s watch-driven evaluation Watch-driven off the ControlModule's status.deviceHealth write; the 30 s floor is the control operator's poll cadence NE 107 instrument self-diagnosis annunciation. Which states alarm, and at what severity, is the definition's healthIn list — the platform mints no health alarm on its own.

The 10 s poll cadence is the floor for tag-based reaction time. The controller cannot fire a tag-based alarm faster than its next poll, no matter how short the debounce. If an equipment constraint needs an always-on stop (pump vs. closed valve), it is a device interlock: Pattern 0. If a process condition needs a sub-second sequenced response while a recipe runs (overpressure surge, runaway exotherm), implement it as a phase SFC transition guard at priority: -1. The worked example in Alarms and Interlocks → Pattern 3 shows the recommended layered pattern: the guard sequences the procedural safe-state, paired with a parallel AlarmDefinition at a slightly higher threshold that fires only when the safe-hold action did not recover. The device interlock protects the output. The guard sequences the procedure. The alarm is the audit record and the batch-level exceptionAction trigger.

BPCS-layer protection — an independent SIS is a PHA/LOPA decision

Even the phase-guard path is a BPCS-layer protection function. It is not an SIS function under IEC 61508 / IEC 61511. Under IEC 61511 Clause 9.2 it can be credited as an independent protection layer. Whether a given hazard (emergency shutdown, overpressure trip, LEL/combustible-gas trip, relief-valve integrity, burner management) also requires an independent SIS is a process-hazard-analysis (PHA/LOPA) decision made per process. An independent SIS here means a separate, independently certified safety PLC or hardwired trip system. See architecture.md for the full framing.

The All sub-tab is the only place every state is visible at once (Active hides ClearedAcknowledged and shelved rows). Use it when comparing badge cues or auditing recent alarm history. Use Active for live operator response.

Alarms list rendered with one row per ISA-18.2 state: ActiveUnacknowledged (red Active + amber Unack'd, Ack only), ActiveAcknowledged (red Active + gray Ack'd, Shelve only), ClearedUnacknowledged (green Cleared + amber Unack'd, Ack only), ClearedAcknowledged (green Cleared + gray Ack'd, no actions)

State is returned as the literal state field on each Alarm DTO (ActiveUnacknowledged, ActiveAcknowledged, ClearedUnacknowledged, ClearedAcknowledged). Filter the list endpoint by adding &state=ClearedUnacknowledged etc. The UI sub-tabs apply the same filter client-side.

Annunciate instrument health (NE 107)

A control module backed by a PA-DIM instrument mirrors the device's NE 107 self-diagnosis into its status (see Device health), and the platform mints no alarm from it on its own: which states page someone, and at what severity, is a site decision written as an AlarmDefinition with the DeviceHealth condition (ADR-0043).

On the control module's detail page, add a definition and pick Device Health (NE 107) as the condition. The condition is offered only when the source is a ControlModule. The state/tag inputs give way to the NE 107 state checkboxes: the alarm raises while the mirrored state is any of the ticked ones.

Alarm definition form with condition Device Health (NE 107) selected: the healthIn checkbox row lists the six NE 107 states with Failure and MaintenanceRequired ticked, severity High, and an operator-facing message

A typical policy alarms Failure at a high severity and MaintenanceRequired at a low one, mirroring the DI taxonomy without hard-coding it. Ticking Normal is legal but self-defeating. A lab skid that deliberately lives in MaintenanceRequired for a week simply leaves that box unticked. The created definition reads back as a reviewable line of alarm policy:

Alarm definitions list with the DeviceHealth row: the Condition cell reads Health in Failure, MaintenanceRequired

Reaction time follows the device-health row of the reaction-time table: the 30 s poll cadence is the floor, evaluation off the status write is watch-driven and sub-second.

A maintenance system consumes the same definition's output as a feed it can cut work orders from. What it matches on, and where it reads the current health of the instruments that are fine, is in Device health for a maintenance system.

Confirm an exception action reached the batch

An AlarmDefinition that carries exceptionAction: Hold, Stop or Abort commands the procedure of every running batch holding an affected unit. The rule reports what happened on its own status, under the ExceptionActionIssued condition.

A True condition means the action ran, and its message carries the count: Issued Hold to 2 procedure(s). A count of zero is a successful no-op, which is the normal reading when the alarm fires on equipment no running batch has allocated.

A False condition means the action could not run at all, and its message carries the reason. The alarm still annunciates, so the event reaches the operator either way. No batch was commanded, and the protection did not happen. The controller retries on every subsequent pass until it succeeds, so a False condition that persists is a standing failure worth escalating.

Read it with kubectl get alarmdefinition <name> -n site-<site> -o jsonpath='{.status.conditions[?(@.type=="ExceptionActionIssued")]}'.

Server alarms

Most alarms come from the plant. A smaller set comes from the servers themselves: the Kubernetes nodes running the operators, the gateway, the broker and the historian. The physical operator watches those nodes and raises the same kind of Alarm resource the plant rules raise, so server degradation reaches you through the paths you already watch: the Alarms nav cue, the topbar badge, the alarms list and history, and the MQTT alarm topic any external annunciator subscribes to. The decision record is ADR 0032.

Condition Severity Source
A control-plane node's Ready condition leaves True High Server/<node>
Any other node's Ready condition leaves True Medium Server/<node>
A node reports memory, disk or PID pressure Low Server/<node>
Ready control-plane nodes fall below etcd quorum Critical Cluster/etcd-quorum
A node maintenance is still open past its alarm shelve window Medium Server/<node>

A control-plane alarm carries the derived etcd margin in its message (2 of 3 members Ready, quorum size 2, margin 0), so a reboot that holds quorum still tells you how much margin is left. The quorum figure is derived from control-plane node readiness under the stacked-etcd assumption. The product does not query etcd directly. Losing quorum outright raises its own Critical alarm.

These alarms behave like every other alarm: acknowledge to silence the cue, shelve a nuisance for a bounded time, and read the history in /data. The condition clears on its own once the node recovers. Because the same servers host every site on the cluster, one server condition raises one alarm in each site, and each site acknowledges its own copy.

What a server alarm tells an operator

A server alarm annunciates on the HMI as well as in /system, and an operator has no server surface to look the condition up in. So the alarm carries its own interpretation, in a fixed order (ADR 0037):

  1. What happened, in terms of what the plant loses. This sentence leads, so a truncated row in the alarm list still reads.
  2. Which of this site's unit runtimes were on that server. Each site gets its own copy of the alarm, so each copy names that site's own units. A site with nothing on the server is told so, which is how you learn the alarm does not threaten your batch.
  3. What to do, which is to escalate to whoever maintains the control system hardware. An operator console corrects none of these conditions, and the HMI carries no infrastructure action by decision.
  4. The engineering detail, kept last: the readiness status, the kubelet reason and the quorum derivation.

Reading a control-plane alarm, for example:

Server plant-cp-2, which runs the control system's management services, has stopped reporting. Unit runtimes keep executing their control logic. One more control-plane server failing will stop batch commands and configuration changes taking effect. No unit runtimes in this site are hosted on that server. Escalate to whoever maintains the control system hardware. An operator console cannot correct a server fault. Node detail: Ready status False, reason KubeletNotReady. etcd quorum derived from control-plane readiness: 2 of 3 members Ready, quorum size 2, margin 0.

Alongside the alarm, the health indicator in the top bar of every screen grades the servers with the rest of the system. It reads degraded while any server is unhealthy and critical when the cluster has lost quorum, so the state of the hardware underneath is visible without opening anything.

Planned maintenance shelves what it causes

Draining a node and rebooting it takes it out of Ready, which is the alarm in the first row of the table. If every planned maintenance ended in a burst of alarms describing what you just asked for, you would stop reading the category, and the next real server fault would arrive in a channel nobody watches.

So a maintenance shelves the alarms it is expected to cause. From the moment a NodeMaintenance starts, the server alarms of the node it is servicing are raised shelved: still in the alarm list, still in the history, marked with their countdown, and annunciating nowhere. The suppression rides the same retained MQTT event any external annunciator already honours (ADR 0014), so an outside horn falls silent along with the HMI.

The shelve is deliberately narrow. Another server leaving Ready, a lost etcd quorum, and every equipment alarm in the plant annunciate normally, because a real fault that merely coincides with a maintenance window is still a real fault. A drain never evicts a running unit either: a node hosting live unit runtimes is refused until they are failed over, so there is no eviction burst to suppress.

It expires on its own two hours after the maintenance started, whether or not the node came back and whether or not anyone closed the object. A shelve that outlives its maintenance is itself a hazard, and the return path is exactly what fails when a maintenance goes wrong. Returning the node to service before then releases the shelve early.

A maintenance still open past that window raises the last row of the table against the node, naming the intent, the phase and when the work started, and the node's own conditions become audible again. A cordon leaves a node perfectly Ready, so without that rule a chassis could sit out of service for days with every indication green. Acknowledge it like any other alarm when the job legitimately runs long.

The maintenance object carries the same story in its AlarmsShelved condition, which names the instant the shelve expires while the window is open and says so plainly once it has. An operator's own shelve on a server alarm is left alone by all of this: maintenance releases only the shelves it applied. The decision record is ADR 0036.

The remedy is at the infrastructure layer. /systemServers carries the node detail behind the alarm: conditions, capacity, roles, and the node-bound volumes that decide whether the chassis can be serviced without moving data. See Web UI → Servers.

Servers stay outside the ISA-88 physical model, so a server alarm never names a unit or a control module as its source. That also means it cannot be authored or tuned as an AlarmDefinition. The rules above are fixed.

Switch between Active, All, and Shelved

The header above the table carries three sub-tabs. They filter the displayed list client-side. Switching does not re-query the gateway.

Active

Default selection. Hides shelved alarms (shelvedUntil in the future) and resolved alarms (ClearedAcknowledged). This is the working set operators react to in real time.

Active sub-tab selected: only ActiveUnacknowledged, ActiveAcknowledged, and ClearedUnacknowledged rows are shown

All

Every alarm in the site, regardless of state. Shelved rows render dimmed. Resolved rows are visible for context.

All sub-tab selected: full list including resolved and shelved rows, with shelved rows rendered at reduced opacity

Shelved

Only alarms whose shelvedUntil is still in the future. Use this view to audit what an operator has temporarily suppressed. Each row's action is Unshelve (see Unshelve an alarm).

Shelved sub-tab selected: list filtered to alarms with an active shelve window

Filter the list

The filter row sits between the summary banner and the table. Filters combine. Selecting Severity = Critical and Type = Equipment narrows to rows matching both. Clear Filters appears once any filter is set.

  • Severity drop-down: Low, Medium, High, Critical.
  • Type drop-down: Equipment, System.
  • Source free-text input: substring match against the alarm.dcs.io/source label (e.g. typing granulator matches granulator-ai and granulator-bowl).

Filter row with Severity = Critical and Type = Equipment selected, the table below showing only matching rows, and a Clear Filters button visible

Filters map directly to query parameters on the list endpoint:

GET /api/v1/sites/{site}/alarms?severity=Critical&type=Equipment&source=granulator

Add &state=ActiveUnacknowledged to filter on the ISA-18.2 state (the UI does this client-side when you switch sub-tabs). Permission: PermRead.

View alarm detail

Click any alarm name in the table. The detail panel replaces the list and shows source, condition, ack, type, severity, message, definition reference, setpoint, current value, and ack / cleared / shelved timestamps. ← Back to alarms returns to the list.

The detail panel header carries Acknowledge and Shelve buttons. Whether they're present depends on the alarm's current state (cleared+acknowledged alarms are read-only, and a shelved alarm offers Unshelve in Shelve's place).

Alarm detail panel: header with the alarm name and Acknowledge / Shelve buttons, body grid showing source, condition, ack, type, severity, message, setpoint, current value, and timestamps

GET /api/v1/sites/{site}/alarms/{name}

Returns the full Alarm DTO (same shape as the list elements). Permission: PermRead.

Acknowledge an alarm

Acknowledging records acknowledgedBy and acknowledgedAt on the alarm and transitions its state. ActiveUnacknowledged becomes ActiveAcknowledged, and ClearedUnacknowledged becomes ClearedAcknowledged. It does not clear the underlying condition. It only attests that an operator has seen it. The gateway writes a dcs.io/command=Acknowledge annotation. The alarm controller picks that up, updates status, and clears the annotation. Permission: PermOperate.

The UI offers three places to acknowledge. They all hit the same endpoint and produce the same audit record. Pick whichever is closest to where you noticed the alarm.

From the alarm row

The Alarms list carries an inline Ack button in the Actions column for every row whose state is ActiveUnacknowledged or ClearedUnacknowledged. Use this when triaging multiple alarms in sequence: you stay on the list and the next row is one click away.

Alarms list with the per-row Ack button highlighted in the Actions column on the first row

dcs --site newark-plant alarm ack granulator-1-bowl-overpressure

From the alarm detail panel

Click an alarm name in the list to open the detail panel, then hit Acknowledge in the panel header. The panel also shows the source, severity, message, setpoint, current value, and any existing ack/cleared/shelved timestamps. That context is often what you want in view before signing off.

What acknowledging does depends on the alarm's condition, and the detail panel is the clearest place to see the contrast. The walkthrough below acknowledges two alarms in turn, one whose condition has returned to normal and one still active:

Acknowledging an inactive alarm resolves it. Acknowledging an active alarm only silences it. The operator shelves to suppress the still-present condition and unshelves to restore annunciation early, all at /hmiAlarms from each alarm's detail panel.

Alarm detail panel with the Acknowledge button highlighted in the panel header

When the condition has already returned to normal (ClearedUnacknowledged), acknowledging is the last step the alarm needs. It becomes ClearedAcknowledged (green Cleared / gray Resolved, no remaining actions) and leaves the Active working set.

When the condition is still present (ActiveUnacknowledged), the panel re-renders without the Acknowledge button, the Ack badge flips to gray Ack'd, and new Acknowledged By + Acknowledged At rows appear. The Condition badge stays red Active, because the underlying signal hasn't cleared. Acknowledging silences the annunciation. To suppress the still-present condition you shelve it.

Alarm detail panel after acknowledging: Condition still red Active, Ack badge gray Ack'd, Acknowledged By + Acknowledged At rows populated, only the Shelve button remains in the panel header

Acknowledging is performed by setting an annotation on the existing Alarm. You don't apply a fresh manifest. The gateway and CLI use this same path internally:

kubectl annotate alarm -n site-newark-plant \
  granulator-1-bowl-overpressure \
  dcs.io/command=Acknowledge --overwrite

From the faceplate alarm strip

When a faceplate is open for a control module that has an unacknowledged alarm, an inline Unacknowledged Alarm strip appears at the top of the panel listing every active alarm on that module. Each strip row carries its own Ack button plus a View in Alarms link to jump to the global view. Use this when you're already focused on configuring or interlocking that module and don't want to break flow.

On the unit dashboard, each collapsed equip card whose control module has an unacknowledged active alarm carries its own amber border, so you can pick the alarming card out of the grid without expanding each one or switching to the canvas view. Click the amber-bordered card to expand its faceplate and see the strip.

HMI unit dashboard equip grid with one collapsed equip card (harvest-valve) highlighted by an amber alarmed border, while the other equip cards in the grid carry the default neutral border

ControlModule faceplate showing an amber alarmed border and an Unacknowledged Alarm strip at the top of the panel: the strip row shows the alarm name, message, an Ack button, and a View in Alarms link

The amber faceplate border clears the instant the alarm is acknowledged from anywhere (this strip, the alarm row, the detail panel, the CLI, or a direct API call), even if the underlying condition is still active. Shelving from this surface is not supported. Use the alarm row or detail panel for that.

The strip's whole surface on camera: per-row Ack (strip and border clear together, and the unit stays flagged by its siblings) and View in Alarms to the global view. Shelving is absent from this surface by design.

Shelve an alarm

Shelving temporarily suppresses annunciation of a noisy alarm for a chosen duration, useful during planned maintenance or when a fault is a known side-effect of another operation. It is the ISA-18.2 operator-grade suppression: temporary, time-limited, audited, and auto-returning, distinct from out-of-service (spec.enabled, engineering) and state-based suppression (armingGate).

Suppression is system-wide. The shelve rides the retained alarm event (shelved / shelvedUntil). Every annunciation consumer goes quiet for the duration: the HMI indicators (nav icon, unit-card border, faceplate strip) and any external annunciator/SCADA/notifier (ADR 0014). The alarm itself is not cleared. It stays in the list (visible under All and Shelved, hidden under Active). Once shelvedUntil passes, the controller auto-unshelves, and annunciation resumes if the condition is still active. An operator can also unshelve at any time to end the suppression early.

You must acknowledge an alarm before you can shelve it. Shelving is offered only for ActiveAcknowledged alarms. You cannot suppress an alarm nobody has registered as seen, and you cannot pre-shelve a cleared/idle one (the API rejects other states with 409 Conflict). Acknowledge and shelve stay two distinct, separately-audited operator decisions. Permission: PermOperate.

Acknowledge the alarm first. The Shelve control then appears. From a row, click Shelve to open a duration menu with quick presets (30m, 2h, 8h, 24h). From the detail panel, Shelve expands a duration field under the alarm header, pre-filled 2h and accepting any Go-style duration string (45m, 1h30m, 7d, …). The alarm stays on screen behind it, so the condition and acknowledgement you are shelving against are readable while you choose the window.

Alarms list row with the Shelve menu expanded showing 30m / 2h / 8h / 24h options below the button

Triage at speed, on camera: row Ack, the preset Shelve menu (the free-text duration field belongs to the detail panel), the dimmed shelved row on All, and detail-panel Unshelve.

dcs --site newark-plant alarm shelve \
  granulator-1-bowl-overpressure --duration 2h

Unshelve an alarm

Shelving always has an explicit return path (ISA-18.2). The controller auto-unshelves when shelvedUntil passes, and an operator can unshelve at any time to end the suppression early, for example when the maintenance that justified the shelve finishes ahead of schedule. Unshelving restores annunciation immediately. The alarm returns to the Active sub-tab, and every annunciation consumer lights back up if the condition is still active. It is a separately-audited operator action, like acknowledge and shelve. Permission: PermOperate. Unshelving an alarm that isn't shelved is rejected with 409 Conflict.

A shelved alarm never offers a second Shelve. Its row action (under All and Shelved) and its detail-panel action both become Unshelve for the life of the shelve window. To extend a window, unshelve and shelve again with the new duration.

Open the Shelved sub-tab and click Unshelve on the row, or open the alarm's detail panel. The panel shows the Shelved Until timestamp with Unshelve in its header.

Alarm detail panel for a shelved alarm: Shelved Until row populated in the body grid and an Unshelve button in the panel header

dcs --site newark-plant alarm unshelve \
  granulator-1-bowl-overpressure

See alarms in the process cell

Alarmed unit cards in the process-cell view (/hmi) carry a static amber border whenever the unit (or one of its child control modules) has an unacknowledged active alarm. The border clears the instant the alarm is acknowledged, even if the underlying condition is still active. The sidebar's Alarms icon also turns solid amber while any unacknowledged active alarm exists in the site.

Drilling into the alarmed unit paints an amber outline around the unit dashboard, and any faceplate open for an alarming control module carries an amber border plus an inline alarm strip at the top of the faceplate. The strip lists each unacknowledged alarm on that control module with a per-row Ack button and a View in Alarms link to the global view. Acknowledging from the strip uses the same API and audit trail as acknowledging from the Alarms view. To shelve, still use the Alarms view.

HMI process cell with one unit card highlighted by an amber alarmed border, and the sidebar showing the Alarms nav icon in solid amber

Review historical alarms

The live Alarms view shows what's currently in flight. Long-term history (resolved events, time-range queries, correlation with batches and trends) is served by the historian. Two entry points reach that data: the History sub-tab of the HMI alarms view (handy when you're already triaging live alarms and want to look back without leaving the sub-app), and the dedicated /dataAlarm History view (full filters, deep-link URL, suitable for post-incident review).

View alarm history

Open /hmiAlarms and pick the History sub-tab beside Active / All / Shelved. It lists the most recent 200 alarm events for the site selected above it, defaulting to the last hour. The address carries the tab, so the view survives a refresh and can be linked.

HMI Alarm History tab opened from the Alarms view: header with time-range buttons (15m / 1h / 6h / 24h / 7d), severity drop-down, and a table of historical alarm events with timestamp, severity, action, name, message, unit, and state columns

Pick Active to go back to the live list. The History tab is read-only. It doesn't expose Ack / Shelve actions, because those only make sense on alarms still in the working set.

The look-back without leaving triage: History beside the live sub-tabs, the last-hour table, a 24h re-query, the Critical severity filter, and the read-only return to the working set.

GET /api/v1/historian/alarms?namespace=site-{site}&start={RFC3339}&end={RFC3339}&limit=200

Returns historical alarm events. The History tab calls this endpoint directly. Permission: PermRead. See Historian for retention and DTO details.

Filter history by range or severity

The panel header carries time-range buttons (15m, 1h, 6h, 24h, 7d) and a severity drop-down. Both re-query the historian: a range button for its window, the severity drop-down with a severity filter on the same query.

HMI Alarm History tab: 24h range button selected (highlighted in the header), Severity drop-down set to Critical, table filtered to only critical events from the past day

The range buttons set start and end query parameters and the severity drop-down adds severity= to the same historian query. For arbitrary time bounds, query /dataAlarm History or hit the historian directly.

From the Data sub-app

/dataAlarm History is the full historian view: arbitrary time ranges, severity / source filters, deep-link URL, and a stable URL surface suitable for sharing in post-incident reviews. It's backed by the same historian endpoint but is not constrained to the HMI tab's 200-event ceiling.

Data → Alarm History: historical alarm events with severity, time-range, and source filters

For the underlying API and retention semantics, see Historian. The same data is reachable per-equipment on the Data tabs of any ControlModule or Unit detail page.

Annunciation latency

The alarm path is instrumented end to end on the generator side: the dcs_alarm_annunciation_latency_seconds histogram times each transition into ActiveUnacknowledged from the instant the generating reconciler observed the condition met to the broker accepting the retained AlarmEvent publish. That publish is the transport every annunciation consumer subscribes to, so the number is the system's own contribution to annunciation delay. Consumers add their transport on top: the HMI its alarm poll interval, an external SCADA or notifier its broker round trip. A configured activation debounce is excluded by construction. The window opens at the evaluation that fired. The first raw excursion sits earlier, and the debounce between the two is engineered intent counting as no part of system latency.

A published latency budget will be documented here once the #943 soak has produced measured numbers to stand behind. That soak reports the distribution per generator. hack/soak.sh report breaks the histogram out by origin and prints p50/p95/p99 over the window, so the budget recorded here comes from a trended 72-hour population. An individual spot check carries no weight in it.

histogram_quantile(0.99,
  sum by (le) (rate(dcs_alarm_annunciation_latency_seconds_bucket[5m])))
  • Control Modules → Alarm definitions — engineering setup for alarm rules.
  • Alarms and Interlocks — three worked patterns (valve MISMATCH, analog deviation, phase-level interlock).
  • API Reference — full schemas for Alarm and AlarmDefinition, plus the armingGate and exception-action fields.
  • Historian — long-term alarm storage, retention, and query semantics.
  • Monitoring and Metricsdcs_alarms_active, dcs_alarms_total, and dcs_alarm_annunciation_latency_seconds Prometheus series.
  • Web UI → Servers — the node inventory behind a server alarm.
  • ADR 0032 — why server degradation annunciates as an alarm in every site.
  • ADR 0036 — why planned maintenance shelves the server alarms it causes, and what it deliberately leaves annunciating.
  • ADR 0037 — why a server alarm carries its own consequence, impact and response, and why the HMI gains no server surface.