Alarms
This page explains how alarms work in the gateway: what an alarm is, how it is evaluated, what the states mean, and where the dashboard shows them. It is for engineers who define alarms and operators who work the alarm list. The REST routes are in the alarms API and the live frames in the /sync protocol.
An alarm belongs to one tag
An alarm is a condition on one tag. It is evaluated against every value the event backbone accepts for that tag, so it sees what subscribers see, in the same order. Evaluation runs on its own task, fed from a queue of 32,768 values, so a slow or failing evaluation can never delay or fail the publication of values. The cost of that separation is described under Restarts and the queue.
Alarms are defined in two places:
- On a tag directly, through Alarms in the tag's panel in the dashboard, or
POST /api/v1/tags/{tagIdOrPath}/alarms. These are the alarms an engineer edits one by one. - On a member of a tag type (UDT), once for every instance. See Alarm templates on tag types. Such an alarm is marked
inherited: truein the API and is edited on the type, not through the alarms API.
Creating, editing and deleting an alarm needs the engineer role. Acknowledging, shelving and unshelving need the operator role. Reading alarms needs the viewer role. See Security.
Definition
A definition is {name, severity, condition, setpoint, deadband, onDelayMs, enabled}.
| Field | Meaning |
|---|---|
name | What the alarm list shows. On a type member it may hold {Param}, {Description} and {Documentation} references |
severity | 1 to 1000, default 500. The dashboard groups it into Critical, High, Medium and Low labels and sorts outstanding alarms most severe first |
condition | One of the six conditions below |
setpoint | The limit the value is compared with. For bitSet and bitClear it is the bit number |
deadband | How far the value must move back past the setpoint before the alarm clears, so a value hovering on the limit cannot chatter |
onDelayMs | How long the condition must hold, uninterrupted, before the alarm goes active. Up to a day. It runs on the gateway's clock, not on the device's timestamps |
enabled | A disabled alarm is not evaluated and nothing of it is outstanding |
Timestamps in alarm payloads are Unix milliseconds, as on /sync.
Conditions
condition | Active when | Clears when |
|---|---|---|
greater | value > setpoint | value <= setpoint - deadband |
less | value < setpoint | value >= setpoint + deadband |
equal | value = setpoint, exactly | value is further than deadband from the setpoint |
notEqual | value is further than deadband from the setpoint | value is within deadband of the setpoint |
bitSet | bit number setpoint of the value is 1 | that bit is 0 |
bitClear | bit number setpoint of the value is 0 | that bit is 1 |
How values are read before the comparison:
- Booleans compare as 0 and 1.
- Text that parses as a number compares as that number (MQTT payloads often carry numbers as text).
- Anything else, and anything that is not a finite number (
null, NaN, infinity), is treated like a Bad quality value: see Quality.
The bit conditions are for status words. The setpoint must be a whole number from 0 to 63 (a 64-bit word); 0 is the lowest bit. The value must be a whole number too; a value with a fraction neither raises nor clears a bit alarm. A status word read as a signed integer keeps its bit pattern, so bit 31 of a negative 32-bit word still reads as 1. Deadband does not apply to the bit conditions.
States
state | Condition | Acknowledged | Outstanding |
|---|---|---|---|
normal | false | no | |
active | true | no | yes |
acknowledged | true | yes | yes |
cleared | false | no | yes |
"Outstanding" means someone still has something to look at. GET /api/v1/alarms/active and the live alarm.snapshot list every outstanding alarm, most severe first.
Transitions:
normaltoactive: the condition held foronDelayMson a value that may raise. The alarm gets a newoccurrenceIdandactivatedAt, and any earlier acknowledgement is forgotten.activetoacknowledged: someone acknowledged it.acknowledgedAt,acknowledgedByandacknowledgedByNamerecord who and when.activetocleared: the condition ended before anyone acknowledged. The alarm stays outstanding until it is acknowledged.acknowledgedtonormal: the condition ended on an alarm already acknowledged. There is nothing left to wait for, so it goes straight to normal.clearedtonormal: someone acknowledged the cleared alarm.clearedtoactive: the condition came back. This is a new occurrence with a newoccurrenceId, even though the old one was never acknowledged.
Occurrences and acknowledging
Each time an alarm goes active it gets a fresh occurrenceId. POST /api/v1/alarms/{id}/acknowledge takes an optional {occurrenceId}:
- Pass the
occurrenceIdyou were looking at. If the alarm has since cleared and fired again, the acknowledgement gets a409instead of landing on a firing nobody saw. - Acknowledging an alarm that is already
acknowledgedreturns it unchanged. - Acknowledging an alarm with nothing to acknowledge (
normal) answers409.
The dashboard's Acknowledge button sends the occurrence it shows.
Quality
A value nobody can trust must not make an alarm disappear. The quality of each value decides what it may do:
| Value | Can raise | Can clear | Otherwise |
|---|---|---|---|
| Good | yes | yes | |
| Uncertain | yes | no | An alarm it would have cleared stays in alarm and is marked stale |
| Bad, or Good but not a finite number | no | no | The state stays as it was, an outstanding alarm is marked stale, and a running on-delay restarts |
stale is a flag on the alarm, not a state. It clears on the next value that is allowed to confirm the alarm's state. A stale change on an outstanding alarm is sent to subscribers as alarm.updated; a normal alarm going stale is not announced, because viewers only track what is outstanding.
The on-delay restarts on a Bad value because the condition was not seen to hold without interruption.
Restarts and the queue
Alarm state is written to the database whenever it changes, so after a restart each alarm resumes where it was: same state, same occurrenceId, same acknowledgement. It is then re-checked against its tag's current value. A running on-delay keeps its original start, so an alarm whose delay passed during the downtime goes active at once if the condition still holds.
The queue between the backbone and the evaluator is in memory. A brief excursion that was still queued when the process died, or that was pushed out by a burst of more than 32,768 values, is not evaluated. The state still converges on the newest value, so what is lost is at most a short-lived event, never the current truth.
Changes to an alarm or its tag
- Editing a definition re-checks it against the tag's current value at once.
- Disabling an alarm, or the tag it belongs to, clears anything outstanding. The history event says why in its
reason. Deleting either one does the same, and the alarm is announced asalarm.removed. - Renames, tag disables and tag deletes are picked up within 5 seconds.
- History keeps its own copy of the tag path, alarm name, condition and setpoint, so it stays readable after they change.
Shelving
Shelving silences one alarm's presentation for a while, in the way Ignition's shelving does. Evaluation never stops: the state machine keeps running, history keeps recording, and when the time is up, or someone unshelves it, the alarm reappears by itself.
| Request | Role | Effect |
|---|---|---|
POST /api/v1/alarms/{id}/shelve {durationMs} | operator | Sets shelvedUntil to now plus the duration. The duration must be between 1 minute and 7 days, otherwise 400 |
POST /api/v1/alarms/{id}/unshelve | operator | Clears shelvedUntil. On an alarm that is not shelved it returns the alarm unchanged, so two operators reaching for the same alarm is harmless |
What a shelf does and does not do:
shelvedUntil(Unix milliseconds) is carried on every alarm payload while the shelf lasts. The SDK'sisShelved(alarm)compares it with the clock.- A shelf is recorded in history as a
shelvedevent that carriesshelvedUntil, and its end asunshelved(with reasonexpiredwhen the time ran out). Each is also sent live asalarm.shelvedandalarm.unshelved. - Alarm pipelines skip a shelved alarm's events: nothing is sent while the shelf lasts.
- In the dashboard a shelved alarm never counts towards the bell badge or the navigation badge, is hidden from the Alarm summary widget, and is listed under the Shelved filter on Active alarms with a Shelved pill and its end time. The Active alarms header counts it separately ("3 shelved").
- The dashboard offers 15 minutes, 1 hour and 8 hours; the API takes any duration within the limits.
Alarm templates on tag types
A tag type's member can carry alarms, a list of the same definitions. Each instance then gets those alarms, resolved when the alarm service reloads. Such an alarm shows inherited: true and is edited on the type (or in the member's overrides on the instance), not through PUT /api/v1/alarms/{id}.
The name, setpoint and deadband of a template may reference the instance's parameters as {Param}. The name may also say which instance it is about:
| Reference | Resolves to |
|---|---|
{Description} | The instance's description; its first line of notes when it has no description; its name when it has neither |
{Documentation} | The instance's notes |
{Param} | The instance's parameter of that name. A parameter named Description or Documentation wins over the built-in meaning |
So a type can define {Description}: Alarm frequentieregelaar, and each motor's alarm reads "C01 Uitlaatventilator: Alarm frequentieregelaar" with nothing to override per instance. Changing an instance's description renames its alarms on the next reload. See Tag types for how types, instances and overrides fit together.
Alarm history
Every lifecycle event is a row in TagAlarmEvent: active, acknowledged, cleared, shelved and unshelved. Each row copies the alarm's name, severity, condition and setpoint as they were, the tag path, the occurrenceId, the value and quality that caused it, who did it (principalId, principalName) and a reason when there is one (why an alarm was cleared by a disable or delete, how long a shelf was for).
GET /api/v1/alarms/history?alarmId&tagId&from&to&before&limit returns events newest first. tagId matches the tag's id or its path. limit is clamped to 1 to 1000 and defaults to 100. The answer is {events, nextBefore}; pass nextBefore as before for the next page.
History is kept for Alarms__EventRetention, a year by default. Older rows are removed by the alarm service. The retention also bounds how far back a replay can rebuild alarms.
Live frames on /sync
Send alarm.subscribe {} on an open /sync socket. The gateway answers with alarm.snapshot {alarms}, the outstanding alarms most severe first, then one frame per change. Every frame carries the whole alarm in its current state (the same shape as GET /api/v1/alarms/{id}). Send alarm.subscribe again after reconnecting.
| Frame | When |
|---|---|
alarm.snapshot | Right after alarm.subscribe: {alarms}, everything outstanding |
alarm.active | The alarm went active, with a new occurrenceId |
alarm.acknowledged | Someone acknowledged it; see acknowledgedBy and acknowledgedByName |
alarm.cleared | The condition ended. state says whether it still awaits an acknowledgement (cleared) or not (normal) |
alarm.shelved | It was shelved; shelvedUntil says until when |
alarm.unshelved | The shelf ended or was lifted |
alarm.updated | It went stale or recovered, or an outstanding alarm's definition changed |
alarm.removed | Its definition or tag was deleted |
A frame whose alarm has state: "normal" means the alarm is no longer outstanding. Because a slow client can lose frames (the gateway drops the oldest queued frames rather than slowing the runtime), anything that must stay exact should also re-read GET /api/v1/alarms/active now and then. The SDK's useAlarms hook does this. The protocol is described in full in the /sync protocol.
In the dashboard
Alarms are an area of their own in the navigation: Alarms with Active, History and, for admins, Pipelines. An alarm itself is defined on its tag, under Alarms in the tag's panel.
Active alarms
Active alarms lists what is outstanding from the live alarm.subscribe stream. The header reads "N active, M to acknowledge" and adds ", K shelved" when any are. Filters:
- Severity: All, Critical, High, Medium, Low.
- Status: Everything (all outstanding, not shelved), Active, Acknowledged, Cleared, Shelved.
- A search field over the alarm name and tag path.
Columns are Severity, Time, Source (the tag path), Message (the alarm name with its value and limit), Status (the state pill, Shelved beside it when shelved, and who acknowledged beneath) and the actions. Operators get Acknowledge, and Shelve with a duration menu or Unshelve. A row opens a detail with the alarm's fields, including Acknowledged with the time and name.
While the gateway link is down the page says the alarm state is unknown rather than showing an empty list, and it refreshes as soon as the link is back.
Alarm history
Alarm history reads GET /api/v1/alarms/history in pages of 100 with Load older events. Filters are Period (1 h, 24 h, 7 d, 30 d, All), an event type (All events, Went active, Acknowledged, Cleared) and an exact tag path. Columns are Severity, Time, Source, Message (the alarm name, then the value, limit and reason) and Event, with "by name" under an acknowledgement. Export CSV writes the loaded rows with the columns time, severity, source, alarm, event, value, quality, setpoint, by, reason.
The bell and the badges
The bell in the top bar and the badge on the Alarms area count the outstanding alarms that are not shelved. Alarms in state active always count, acknowledged ones count unless the person turns on the "silence acknowledged" option in the bell's menu, and the badge's color follows the highest severity among them. When only cleared alarms remain, the badge shows how many wait for an acknowledgement. The bell's menu lists the alarms with Acknowledge and a link to All alarms.
Alarms on screens
The Alarm summary widget puts the alarm list on a screen: the alarms that need attention, most severe first, with Acknowledge and Shelve for operators. It hides shelved alarms and cleared alarms that are already acknowledged, and can be limited to tags under a path prefix. See Widgets.
Notifications
Alarm pipelines send alarm events out of the gateway, for example to a webhook, and skip the events of a shelved alarm. They are configured under Alarms, Pipelines by an admin. See Alarm pipelines and the worked example Alarm to webhook.
Scripting
Scripts read and acknowledge alarms through system.alarm. See system.alarm.