Tags
A tag is a named value with engineering metadata. This page is the complete property reference.
Tags hold configuration only. The live value lives in the runtime store; history lives in the historian.
General properties
| Property | Type | Description |
|---|---|---|
| Name | string | The leaf name. Combined with its ancestors it forms the tag path. |
| Enabled | bool | A disabled tag is not polled, not evaluated for alarms and not historised. Its configuration is kept. |
| Data type | enum | See data types. |
| Unit | string | Engineering unit — °C, bar, %, RPM. Used as a label by widgets, trends and exports. |
| Description | text | What this value means. Shown in pickers, tooltips and the AI assistant's context. Write it. |
| Writable | bool | Whether the tag accepts writes at all. Off by default. |
| Write level | 0–3 | Required operator write-security level. 0 = any writer, 3 = admin. Meaningful only when writable; enforced server-side. |
| Source | device | internal | expression | Device-backed (has a binding), a QUBIQ-owned memory tag, or computed from other tags. |
| Format string | string | Display format, e.g. #,##0.00. Applied consistently wherever the tag is shown. |
Data types
| Type | Range / notes |
|---|---|
boolean | true / false |
sbyte, byte | 8-bit signed / unsigned |
int16, uint16 | 16-bit |
int32, uint32 | 32-bit |
int64, uint64 | 64-bit |
float | 32-bit IEEE-754 |
double | 64-bit IEEE-754 |
string | Text |
datetime | Timestamp |
json | Structured payload |
array | Array, with dimensions carried from the source |
Match the tag's data type to the source. A mismatch surfaces as a conversion failure with Bad
quality — which is correct behaviour, and much better than a silently truncated number.
Scaling
Scaling converts the device's raw range into engineering units. It is applied after the protocol read and before history, alarms and screens — so everything downstream sees the same engineering value.
| Property | Description |
|---|---|
| Raw low / Raw high | The device's range, e.g. 0 – 27648, or 4 – 20 for a current loop. |
| Eng low / Eng high | The engineering range, e.g. 0 – 100 °C. |
| Invert scaling | Reverses the curve, for sources where raw-high means engineering-low. |
| Clamp scaled | Bound the result to the engineering range. On by default. |
All four range values must be set for scaling to apply.
Raw 4 – 20 (mA) → Eng 0 – 100 (°C)
raw 12 mA → 50 °C
Scaling in each widget means the historian stores raw counts, alarms compare against raw counts, and every new screen has to repeat the arithmetic. Do it here.
Quality and validation
| Property | Description |
|---|---|
| Deadband | On the History tab. Change threshold for what is stored and sent to brokers. See deadband. |
The tag record also has quality default, stale after and validation rule fields (the tag API accepts them), but in this release none of them is shown in the tag dialog and nothing enforces them at runtime.
Quality
Quality travels with every value, through bindings, expressions, alarms and charts.
| Quality | Meaning |
|---|---|
Good | The value is trustworthy. |
Uncertain | Readable but suspect — a stale value, a degraded source. |
Bad | Not trustworthy — connection down, read error, conversion failure. |
Unknown | The tag exists but has no value yet — see below. 1.0.7 |
NotFound | Nothing answers to that name: a read named a tag that does not exist, or a binding's address does not exist on the source. |
Widgets show bad quality rather than rendering a stale number as if it were current. Expressions propagate the worst quality of their inputs, so a computed value cannot look better than the data behind it.
A tag with no value yet Changed in 1.0.7
A read of a tag that exists but has never carried a value answers Unknown, with the tag's real
path and a sentence saying why. Until 1.0.7 it answered NotFound — the same word as a typo — and
sent operators hunting for a misspelled path when the tag was sitting right there.
| Tag | What the read says | What to do |
|---|---|---|
| Device, with an enabled binding | The device has not reported a value yet | Wait: it arrives on the next poll or subscription update. If it never does, diagnose the binding. |
| Device, with no enabled binding | No enabled protocol binding for this path | Nothing will ever fill it. Bind it, or change its source to internal. |
| Expression | The expression has not been evaluated yet | A value is coming; if it stays this way, the expression is not being evaluated. |
| Disabled | The tag is disabled | Enable it. Reading a disabled tag does not bring it to life. |
The reason reaches the AI assistant too, so it can tell you what to fix instead of reporting
"no live value". NotFound now means one thing only: nothing by that name exists.
An internal tag never reads Unknown — it always has a value. See
initial value.
Deadband
The single most effective control on history volume and broker traffic.
| Deadband | Effect |
|---|---|
0 | Every change is stored. Correct for discrete states and counters. |
| Small (0.1–0.5% of span) | Removes sensor noise; charts are visually unchanged. |
| Larger (1–2% of span) | Substantial storage saving; adequate for slow analogue values. |
A change smaller than the deadband is not stored and not sent by a broker publisher that publishes on change. It still reaches screens, alarms and expressions, which see every reading.
Stale after
Push protocols (MQTT, OPC-UA subscribe, TCP) only send on change, so a value that never changes is indistinguishable from a dead link. Stale after is not available in this release: it cannot be set in the tag dialog, and a value set by import is not enforced. Watch the connection's health instead.
Broker publishing New in 1.0.6
The tag's Publishing tab carries one more setting: How often this tag is sent to an external MQTT broker — follow the broker, only when it changes, or every reading. Cadence is a property of the signal rather than of the broker it goes to: a counter or a batch step has to arrive at its scan rate wherever it is sent, and one tag can be in scope of several publishers at once.
Changing it on an existing tag now saves. 1.0.7 In 1.0.6 only the choice made when the tag was created stuck; a later edit was accepted and then silently discarded, and the tag went on being sent at its old cadence.
It decides how often, never whether. Which tags leave the building is a publisher's fences, and nothing on this tab can widen them. → MQTT publishing
History
| Property | Description |
|---|---|
| Enable history | Stream this tag's values to the historian. |
| Store interval (ms) | Force a stored point at this interval even if nothing changed — proves the signal was alive. |
| Storage connection | Which store receives it. Normally the designated system historian. |
History respects the tag's deadband, so noise is filtered before it reaches storage.
Alarming
| Property | Description |
|---|---|
| Alarm enabled | Per-tag master switch. Alarm definitions are only evaluated when this is on. |
Individual alarms — mode, setpoints, priority, delays, deadband, latching — are configured per alarm
on the tag. One tag can carry many alarms (Hi, HiHi, Lo, LoLo, Fault).
Write security
Two independent gates protect device writes:
- Writable — off by default. A non-writable tag rejects every write.
- Write level (0–3) — the minimum runtime operator level required. Enforced server-side in the write gate, so a modified client cannot bypass it.
| Level | Typical use |
|---|---|
| 0 | Unrestricted for anyone with write capability — HMI setpoints of no consequence |
| 1 | Routine operator actions |
| 2 | Supervisor actions — recipe changes, mode switches |
| 3 | Administrator only — calibration, safety-adjacent parameters |
Copying a tag keeps its write level. 1.0.7 Before 1.0.7 a
copy was reset to level 0, so a copy of an administrator-only tag could be written by any
operator. A copy also keeps its source, publish mode, storage connection and format string. It does
not carry the tag's alarms, and so it does not carry Alarm enabled either — arming a tag
that has nothing to evaluate would only look configured.
Internal (memory) tags
Set source to internal for a value QUBIQ owns:
- Operator setpoints and targets
- Counters and accumulators
- Computed KPIs written by a script or pipeline
- Mode and state flags
Internal tags have no binding, are persisted without expiry, and are written from scripts
(system.tag.write), pipelines or screens. An initial value can be supplied at creation to seed
them.
Initial value Changed in 1.0.7
When you pick Internal as the source, the Initial Value box is filled in with the data type's default — the value the tag will actually start at. It used to open blank, with the default shown only as a faint hint, so you never saw what the tag was about to hold.
| Data type | Default |
|---|---|
boolean | false |
every integer type, float, double | 0 |
string, datetime | empty |
json | {} |
array | [] |
The value must fit the data type, and the field says so while you type:
- Changing the data type re-derives the value. Type
truefor a boolean, switch toint32, and the box no longer holdstrue. A value that is still valid for the new type is kept. - Integers are range-checked.
300in abytetag is refused, not wrapped round to44— a wrong value that looks like a real one. - JSON must parse, and an
arraytag needs a JSON array.
The server checks the same rules again before the tag is created, so a value that does not fit is
refused with a message naming the field rather than stored. Until 1.0.7 a typo in a number box
silently became 0, and invalid JSON was stored as a plain string in a json tag.
The initial value exists only at creation; it is not a property you can edit later. To change an internal tag's value afterwards, write to it.
Only internal tags take one. A device tag's value comes from an instrument, and a default would be a measurement nothing measured — an operator could not tell a stopped pump from one that never reported. An expression tag's value is computed, and a default would mask an expression that is not evaluating at all.
An internal tag that arrives by bulk import, or by copying, starts at its type's default too. 1.0.7 Before 1.0.7 imported internal tags showed blank until somebody wrote to them, and a copied internal tag came out as a device tag with no binding, which neither read nor accepted a write. The opening value is also historised now when the tag has Enable history on; it used to be dropped, so the series began at the first write, some time after the tag was created, with nothing to explain the gap.
Expression tags
Set source to expression for a value computed from other tags. The expression engine
recalculates it whenever an input changes, and the result behaves like any other tag: it can be
bound to a widget, trended, alarmed and read from a script.
Line1/Filler/Motor1/Power = Speed * Torque * 0.105
Line1/OEE = Availability * Performance * Quality
Line1/Filler/Motor1/Overspeed = Speed > 2800
An expression tag is a read-only projection. It has no protocol binding and rejects external writes — there is nowhere for a written value to go, because the next input change would overwrite it.
Settings
| Setting | Values | Purpose |
|---|---|---|
| Expression | text | The formula. Reads other tags by absolute path. |
| Evaluation mode | on_change (default) · interval | Recompute when an input changes, or on a fixed period. |
| Evaluation interval | ms | Required for interval mode. Also the tick period when the expression reads the clock. |
| Minimum interval | ms, 0 = unlimited | Rate-limits the output. A fast input does not have to mean a fast output. |
| Quality policy | worst_of_inputs (default) · always_good · explicit | How the result's quality is derived. |
Dependencies are worked out for you
You never list the inputs. They are extracted from the expression when you save it, and the engine indexes by them, so a tag recomputes only when something it actually reads changes.
That index answers the other direction too: what breaks if I delete this tag? is a question the system can answer before you delete it, rather than after.
Quality is not an afterthought
The default worst_of_inputs means an expression reading one Bad input produces a Bad result.
That is almost always what you want — a computed KPI built on a dead sensor should not look healthy.
Reach for always_good only when the expression genuinely does not depend on input quality (a
constant, or a pure clock reading), and explicit when the expression decides quality itself.
→ Expression functions for the built-in function reference.
Using the clock
An expression that reads the current time is recognised as such and subscribed to a periodic tick, so it keeps recomputing even when no input tag changes. Set the evaluation interval to control how often — a "minutes since last batch" tag does not need to tick every second.
When not to use one
| Arithmetic, unit conversion, bit unpacking, thresholds | An expression tag |
| Anything with a database round trip, an API call, or a loop | A pipeline |
| A value a human or a screen sets | An internal tag |
An expression that needs a comment to explain it has usually outgrown being an expression.
Reading and writing tags in scripts
result = system.tag.read("Line1/Filler/Motor1/Speed")
if result["quality"] == "Good" and result["value"] > 2800:
system.tag.write("Line1/Filler/Motor1/SpeedSetpoint", 2500)
const r = await system.tag.read("Line1/Filler/Motor1/Speed");
if (r.quality === "Good" && r.value > 2800) {
await system.tag.write("Line1/Filler/Motor1/SpeedSetpoint", 2500);
}
Always check quality before acting on a value. A Bad-quality read still returns a value — the
last known one — and acting on it is how a dead sensor drives a live process.
A tag that exists but has no value yet reads Unknown with no value, and error says why — see
a tag with no value yet. Only a name that matches no tag reads NotFound.
Batch where you can: system.tag.readAll([...]) is one round trip, a loop of read is N.
Permissions
Reading tags and their bindings needs View the namespace. Creating, editing, deleting and bulk-deleting tags all need Manage tags; changing a binding needs Bind a tag to a protocol.
Checklist for a well-formed tag
- Data type matches the source
- Unit set
- Description written in plain language
- Scaling configured if the device sends raw counts
- Deadband set for analogue values
- History enabled only where someone will look at it
- Writable off unless it needs to be on — and a write level if it is