Alarms & Commands
A device type declares two behavioural surfaces alongside its tags: the conditions that should raise an alarm, and the commands an operator can issue against an instance. Both are plain YAML inside the type package — no code — so they version, review, and ship with the type itself. See The Type System for how a package is laid out and Tags for the tag model these definitions bind against.
consystence.pump.centrifugal/├── manifest.yaml├── simulation.yaml├── alarms/│ └── alarms.yaml # ← alarm definitions├── commands/│ └── commands.yaml # ← command definitions└── components/Alarms
Section titled “Alarms”alarms.yaml is a list of alarm definitions. Each one names a condition over the
instance’s tag values — its live data points; when the condition holds, an active
alarm is raised against the instance.
| Field | Required | Notes |
|---|---|---|
id | yes | Stable identifier, unique within the type. |
name | yes | Human-readable label. |
condition | yes | Expression over bindings; raises the alarm when true. |
priority | yes | One of Low, Medium, High, Critical. |
category | yes | Free-form grouping string. The bundled types use equipment, process, instrumentation, and safety. |
message | yes | Template shown to operators; supports bindings. |
delaySeconds | no | On-delay: the condition must stay true this long before the alarm activates. Also accepted as delay: with an ISO-8601 duration (for example PT10S) — the form exported packages use. |
clearDelaySeconds | no | Off-delay: an active alarm clears only after its condition has stayed false this long, so a value bouncing at a limit does not flap the alarm. Also accepted as clearDelay: with an ISO-8601 duration. |
Conditions and messages use the same binding syntax as the rest of the type
package. The evaluated namespaces are {tags.X} for a tag value, {config.X}
for instance configuration, {instance.X} for instance metadata
({instance.name} for the label), and — inside commands — {params.X}.
Conditions support comparisons and boolean logic (>, &&, ==, !,
abs(...)).
Here are real definitions from consystence.pump.centrifugal — note the
categories, the priority ladder, the delaySeconds on-delay on the noisy
process and bearing readings, and the clearDelaySeconds off-delay on every
alarm:
- id: fault name: Pump Fault condition: "{tags.Fault}" priority: High category: equipment message: "{instance.name}: Fault detected (Code: {tags.FaultCode})" clearDelaySeconds: 10
- id: high-bearing-temp name: High Bearing Temperature condition: "{tags.BearingTemp} > 85" priority: High category: equipment message: "{instance.name}: Bearing temperature {tags.BearingTemp}°C exceeds limit" delaySeconds: 10 clearDelaySeconds: 10
- id: low-flow name: Low Flow condition: "{tags.Running} && {tags.FlowRate} < 5" priority: Medium category: process message: "{instance.name}: Flow rate {tags.FlowRate} m3/h below minimum" delaySeconds: 60 clearDelaySeconds: 30
- id: interlock-active name: Safety Interlock Active condition: "{tags.Interlock}" priority: Low category: safety message: "{instance.name}: Safety interlock preventing operation" clearDelaySeconds: 10Priority
Section titled “Priority”priority is an ordered enum: Low → Medium → High → Critical. Reserve
Critical for conditions that demand immediate intervention. The
consystence.tank.storage type uses it for the high-high and low-low trips:
- id: high-high-level name: Tank High-High Level condition: "{tags.HighHighLevel} == true" priority: Critical category: process message: "{instance.name}: High-high level alarm - overflow risk, shut down inlets" delaySeconds: 2 clearDelaySeconds: 30Lifecycle
Section titled “Lifecycle”An alarm activates once its condition has held for its delaySeconds, and
clears once the condition has stayed false for its clearDelaySeconds
(immediately when either is unset). There is no latching. Activation and
clearance both surface in the instance’s event log.
Operators can acknowledge an active alarm; the acknowledging user and
timestamp are recorded on the alarm (AcknowledgedBy, AcknowledgedAt).
Alarm and event timestamps are recorded and displayed in UTC.
Acknowledgement is an operator action, never an AI action — the AI may
explain an alarm, but it cannot acknowledge it.
Commands
Section titled “Commands”commands.yaml is a list of command definitions. A command is a named,
guard-railed action that, when executed, writes one or more tags on the
instance.
| Field | Required | Notes |
|---|---|---|
id | yes | Stable identifier, unique within the type. |
name | yes | Human-readable label. |
description | no | What the command does. |
class | yes, in practice | operate, mode, reset, maintenance, jog or defeat. Decides where the command may be offered, never whether it executes. operate, mode and reset are operator-faceplate classes: the web offers such a command as a control where it carries a control for that command id (the standard ids such as start, stop, reset-fault, open, close, enable-auto, disable-auto) and, when the type ships its own faceplate, where that faceplate places a button for it; another id is listed but not yet offered. A command that reuses a standard id must declare that id’s class. A reset must declare confirm: true, and is offered on a site server only, never from the hosted service. maintenance is listed on the engineering tab only; jog is never offered on the web. defeat declares a timed bypass of a protection or interface condition. It is offered on a site server only, runs only after a second person approves it, and is never available to an API key. It is not yet available in a published release. A command with no class is never a faceplate control, and a command that takes parameters is not yet offered. |
direction | stop-class only | Required on the stop-class command ids (stop, stop-rakes, stop-loadout, close, close-loadout, abort): safe or not-safe, declared by the type owner. Any other command must not declare it, even one with another stopping verb, and a safe stop takes no parameters; a type that breaks any of these rules does not load. |
confirm | no | If true, the web UI and the csy CLI ask the operator to confirm before execution. Reset and mode-change commands, and every command issued from the hosted service, always ask; a reset-class command must declare confirm: true. |
confirmMessage | no | Custom confirmation prompt (supports bindings). |
parameters | no | Operator-supplied inputs (see below). |
preconditions | no | Gates that must all pass before the writes are applied. |
tagWrites | yes | The tag writes performed on execution. |
audit | yes, in practice | Declare audit: true. Every command in the first-party libraries does, and each execution is recorded to the command audit log in the operational journal. |
Preconditions
Section titled “Preconditions”Each precondition pairs a condition expression with the message shown when it
fails. All preconditions must hold before any tag write is attempted; the
first failing one short-circuits with its message. A safe stop is the one
exception: Consystence evaluates none of its preconditions, and the controller’s
own logic decides whether it acts.
Precondition evaluation is fail-closed on tag quality: every {tags.X}
reference must resolve to a present, non-null, good-quality value taken from one
atomic snapshot of the instance’s authoritative tag values. If any referenced tag
is missing, or its value is uncertain, cached, stale or bad, the command is rejected as
precondition data unavailable — manifest defaults are never accepted as
evidence, and degraded data never lets a guarded command through. Simulated
devices attest good-quality provenance for the values they produce, so guarded
commands work normally in simulation. These are server-enforced operability
gates (“already running”, “in local mode”), surfaced to give the operator a
clear reason — they are still not a safety function, and not a substitute for
controller-side interlocking.
Parameters
Section titled “Parameters”parameters declares operator inputs. Each has a name, a dataType (Bool,
Int, DInt, Real, String), optional min/max/unit, and a
description. Reference a parameter inside a tag write with {params.<name>}.
# commands/commands.yaml — consystence.pump.centrifugal- id: start name: Start Pump class: operate description: Starts the pump at current speed setpoint confirm: true confirmMessage: "Start {instance.name}?" audit: true preconditions: - condition: "!{tags.Running}" message: Pump is already running - condition: "!{tags.Fault}" message: Clear fault before starting - condition: "!{tags.Interlock}" message: Safety interlock is active - condition: "!{tags.LocalMode}" message: Pump is in local mode tagWrites: # The command port, not the Running status tag (the controller drives that). - tagName: StartCmd value: "true"
- id: set-speed name: Set Speed class: operate description: Sets the speed setpoint confirm: false audit: true parameters: - name: speed dataType: Real min: 0 max: 3600 unit: rpm description: Target speed in RPM preconditions: - condition: "!{tags.LocalMode}" message: Pump is in local mode tagWrites: - tagName: SpeedSetpoint value: "{params.speed}"Tag writes
Section titled “Tag writes”Each tagWrites entry names a tagName and a value. The value is a literal
("true", "0", "100") or a binding ("{params.speed}", "{tags.Position}").
Point tagWrites only at the type’s command ports and operator
setpoints. A command port is a write-only tag (access: Write), such as the
pump’s StartCmd, which the controller logic consumes as a rising edge. An
operator setpoint is a ReadWrite Input tag, such as SpeedSetpoint. Never
write a controller-owned status tag such as Running: the controller drives it
every scan, so the write changes nothing. Type validation flags an
operator-faceplate command that writes a status, read-only or undeclared tag,
and the faceplate does not offer that command as a control. See
Tags for access and physicalRole.
Momentary (pulse) writes
Section titled “Momentary (pulse) writes”Add pulseSeconds (also accepted as pulse: with an ISO-8601 duration such as
PT1S — the form exported packages use) to hold a value for a fixed duration,
after which the tag resets to its inactive value — false for booleans, 0 for
numerics — the right shape for momentary resets and jogs. The consystence.sensor.flow type
uses it for a one-second totaliser reset pulse:
- id: reset-totalizer name: Reset Totalizer class: maintenance description: Resets the accumulated flow totalizer to zero confirm: true confirmMessage: "Reset totalizer for {instance.name}? This cannot be undone." audit: true tagWrites: - tagName: TotalizerReset value: "true" pulseSeconds: 1Execution flow and audit
Section titled “Execution flow and audit”Commands execute over the server-driven UI session, not a public HTTP endpoint.
When an operator executes a command, its preconditions (none, for a safe
stop) are evaluated against one atomic snapshot of good-quality tag values; if
any precondition fails, execution stops with that precondition’s message, and
if any referenced tag value is missing or degraded the command is rejected as
precondition data unavailable — the evaluation fails closed.
What happens next depends on where the device’s tags live. For a simulated
device, the tagWrites are applied in-process (pulse tags scheduled to reset).
For a device whose controller sits behind an edge, the command is dispatched
from the site to the edge over the edge’s command channel with an expiry: a
command that expires before dispatch is rejected, and a dispatched command that
is not acknowledged by its expiry is marked timed out — the outcome on the
PLC is unknown, and it is surfaced that way rather than assumed. Dispatch
through an edge has been demonstrated in our workshop; it is not yet used on any
plant controller. A command with no route to its device’s controller is refused
before anything is written. Every shipped command declares audit: true, and its
execution (its caller, and the individual tag writes with
their outcome and data source) is recorded to the command audit log, which you
can read on the web (the site’s Commands page) or with
csy instance commands and csy site commands.
flowchart TD
A[Operator issues command<br/>via the UI session] --> B{All preconditions true<br/>on one good-quality<br/>tag snapshot?}
B -->|no| R[Reject with the failing<br/>precondition or<br/>data-unavailable message]
B -->|yes| D{Where do the<br/>device tags live?}
D -->|simulated device| E[Apply tagWrites<br/>in-process]
D -->|controller behind an edge| X[Dispatch to edge command<br/>channel with expiry —<br/>workshop only so far]
D -->|no route| N[Refused before<br/>anything is written]
X --> K{Acknowledged<br/>before expiry?}
K -->|yes| E2[Edge applies writes<br/>to the controller]
K -->|no| T[Timed out —<br/>PLC outcome unknown]
E --> F[Pulse tags reset<br/>after pulseSeconds]
E2 --> F
E --> G[Write audit log<br/>subject id + tag writes + outcome]
E2 --> G
T --> G
The audited caller is the authenticated principal’s subject identifier: for
a person, the subject of their sign-in; for an operator API key (X-Api-Key,
prefix csk_), that key’s id, together with the person the key acts for. Email
is a verified attribute, not the identity, and never the audit key. See
Authenticating API Calls and
Authentication for how principals are resolved, and
Roles for org membership (owner, admin, member).
Executing a command requires an authenticated principal with command authority
(org membership as owner, admin or member, a commanding site role on a
site server, or an operator API key on its own site) and a site whose policy
admits Consystence commands. A read-only API key, the default, never runs a
command; an operator key covers one person and one native site for at most 30
days, and can issue commands and acknowledge alarms on that site (see
API keys). A site declared display-only, or one operated from
another SCADA, refuses every command, and a site with no declared policy is
treated as display-only. From the hosted service, a command reaches a site only
where remote operation has been enabled for it, and a fault reset is never
offered there: a reset needs someone present at the site. During the beta,
production control stays with the site’s existing control system.
Related pages
Section titled “Related pages”- The Type System — package structure and IDs.
- Creating Types — authoring a new type package.
- Tags — the data model commands write and alarms read.
- Controller Communication — how the edge reads and writes controller tags.
- API Reference — the rendered OpenAPI. It carries the operational reads (live tag values, trends, active alarms and alarm history, and the command audit log) and alarm acknowledgement, but no command execution endpoint: commands run over the server-driven UI session.