MQTT & Sparkplug B
One connection type covers both classic MQTT (you choose the topics and payload shape) and Sparkplug B (a self-describing convention with birth/death certificates and metric metadata). The payload format switch decides which.
Configuration
| Field | Description |
|---|---|
| Name | Connection identifier. |
| Broker | Hostname or IP. |
| Port | 1883 plain, 8883 TLS, 9001/443 for WebSocket transports. |
| Protocol | tcp, ssl/tls, ws, wss. |
| Client ID | Optional. Leave blank for a generated one. Must be unique on the broker. |
| Username / Password | Optional broker credentials. |
| Clean session | On: no persistent broker-side subscription state. Off: the broker queues messages for this client ID while it is away. |
| Keep alive | Seconds between pings. |
| QoS | 0 at most once, 1 at least once, 2 exactly once. |
| Payload format | mqtt (classic) or sparkplug_b. |
Sparkplug-only fields
| Field | Description |
|---|---|
| Group filter | Subscribe to spBv1.0/{group}/# instead of everything. Essential on a busy shared broker. |
| Primary host ID | If set, QUBIQ advertises spBv1.0/STATE/{id}, so edge nodes know a primary application is online. |
| Rebirth on sequence gap | auto (detect the edge node's scheme — default), on (always request rebirth), off (never). |
Classic MQTT
In classic mode, a tag binding names the topic and, for structured payloads, a path into it. The tag is subscribed to the topic and updates whenever the device publishes.
| Field | Notes |
|---|---|
| Address | The topic, e.g. plant/line1/motor1/speed. |
| Quality of Service (QoS) | Per-binding override of the connection default. 1 is the usual choice. |
| JSON Path | Optional. A dot path to the value inside a JSON payload, e.g. data.speed for {"data":{"speed":1480}}. No leading $.. Leave it empty to take the whole payload. |
| Retain Message | For writes: whether a value written to the tag is published retained. |
| Device time, quality and status | Optional. See below. 1.0.8 |
A JSON path that does not resolve, a payload that is not JSON when a path is set, a null, or a
value that does not fit the tag's data type all read Bad with the reason. The whole payload is
never substituted for a field that is missing.
Wildcards (+, #) are for subscription scope, not for tag addresses — a tag must resolve to one
value.
Several tags on one topic Changed in 1.0.8
Any number of tags can bind to the same topic — typically one per JSON field of a device's payload. Each receives its own field from every message, and each value is delivered once.
Before 1.0.8 the client kept one handler per topic, so of several tags on one topic only the one subscribed last received data; the others stayed silent. Deleting that tag left its handler in place, still publishing for a tag that no longer existed while the rest stayed dark. If you worked around this with one topic per tag, it is no longer necessary.
The device's own time and quality New in 1.0.8
MQTT carries no timestamp and no quality, so by default a message is stamped when it arrives and is
Good if it decodes. Many devices put both into their payload. The binding can read them:
| Field | What it does |
|---|---|
| Timestamp Path | Dot path to the time the device measured the value, e.g. ts or meta.time. Empty: the receive time is used. |
| Timestamp format | Auto-detect, ISO 8601 text, Unix seconds, Unix milliseconds, Unix microseconds, Unix nanoseconds. |
| Timezone for text without an offset | For ISO text with no zone. UTC by default. |
| Quality Path | Dot path to the device's own quality for the reading, e.g. q or status.quality. |
| Device quality codes | Optional, one code = Good, code = Uncertain or code = Bad per line. Consulted before the automatic reading. A line that cannot be read is flagged and blocks the save. |
The device's time becomes the event time. A readable, plausible device time is what the historian stores the value at, so a device that buffers or batches is no longer historised at the moment its batch arrived. Plausible means not before the year 2000 and not more than ten minutes ahead of the gateway's clock. A time that is missing, unreadable or implausible falls back to the receive time; the value keeps its quality and the status says why, for example timestamp "garbage" cannot be read (format epoch_ms); using receive time. → Event time in history
The device's quality grades the reading. Without codes of your own it is read automatically:
| Device reports | Read as |
|---|---|
good, ok, valid, normal | Good |
uncertain, questionable, stale, suspect | Uncertain |
bad, error, invalid, fault | Bad |
true / false | Good / Bad |
| A number 0–255 — an OPC DA quality byte | 192 and above Good, 64–191 Uncertain, below 64 Bad |
| A number above 255 — an OPC UA status code | By its severity bits |
| Anything else | Uncertain, with the code in the status |
The tag's quality is the worse of the payload check and the device's report. A reading the device
marks Bad keeps its value, stored with that quality. A configured quality field that is missing
from a message reads Uncertain, never Good.
0 means two things0 is the worst OPC DA quality byte and OPC UA's Good status code. It is read as the byte. A
device that sends OPC UA status codes needs the line 0 = Good.
These settings are part of the binding in a UDT member too, overridable per instance. → UDT overrides
Retained messages Changed in 1.0.8
On every subscribe and resubscribe the broker replays a topic's retained message, which may be hours
old. It used to be stamped now, Good, and stored as a fresh reading.
- With a device timestamp, a retained message is an ordinary reading at its true time. A repeat of a value already stored is absorbed by the historian.
- Without one, it is shown live as
Uncertain— retained message; original time unknown — and not historised, because there is no true time to store it at.
The device's status topic New in 1.0.8
A plain MQTT device that drops off the network used to leave its tags Good on their last value.
Most devices announce themselves on a status topic and leave a Last Will there, which the broker
publishes when they disconnect. A binding can listen to it:
| Field | Notes |
|---|---|
| Device status topic | The device's status topic, e.g. plant/pump1/status. Wildcards are refused: one device's status cannot come from a pattern. |
| Online payload / Offline payload | online and offline by default. |
| JSON Path | Optional, for a JSON status payload. |
When the status topic says offline, every tag naming it turns Bad at once — one row per outage,
Device offline (plant/pump1/status). When it says online, nothing is written: the tags stay
Bad until the device sends a fresh value, because the value may have changed while it was away.
A retained data message replayed while the device is offline does not clear the Bad; a live one
does. Any other payload on the status topic is ignored.
This is the device's Last Will. It is not the connection's own Last Will, which is QUBIQ's.
In a UDT, set it once on the type as {Device}/status and every instance listens to its own.
Subscribing at scale Changed in 1.0.8
At start-up, after a restart and after a reconnect, MQTT bindings are subscribed in batches — each distinct topic once, however many tags read it — rather than one tag at a time. A 10,000-tag plant used to take about fifty seconds to go live, and a 50,000-tag plant was still not fully subscribed after ten minutes while the broker held millions of messages for topics nobody had subscribed yet. Incoming messages are also decoded once per message rather than once per tag, and spread over several workers with each topic kept in order.
A broker reconnect no longer reloads live tags: the client re-subscribes its own topics. Reloading them used to drop values until every tag was subscribed again — about a quarter of a 10,000-tag plant's values after a single spurious disconnect.
A disabled MQTT connection registers no tags. It used to register them without subscribing them.
Sparkplug B
Sparkplug adds structure that QUBIQ uses automatically:
- Birth certificates (
NBIRTH/DBIRTH) declare every metric with its name, data type, engineering unit and properties. QUBIQ reads them, so discovered metrics arrive already typed. - Death certificates (
NDEATH/DDEATH) signal that an edge node or device has gone away. Bound tags go toBadquality immediately, instead of silently holding a stale value. - Sequence numbers detect lost or out-of-order messages. On a gap, QUBIQ requests a rebirth so state is resynchronised rather than drifting.
- State topic. With a primary host ID configured, QUBIQ publishes its own
STATE, which is what lets compliant edge nodes decide whether a primary application is listening.
Discovery
Sparkplug discovery in the connection's editor (needs View Connections) returns the groups, edge nodes, devices and metrics observed from birth certificates. Discovery is how you populate the namespace from a Sparkplug plant without typing a single topic.
A Sparkplug tag address follows the hierarchy:
{group}/{edge_node}/{device}/{metric}
The device segment is left out for a metric of the edge node itself. When binding a single tag, the browse button beside the address shows the same metric tree and writes this address for you. 1.0.8 → Address formats
Writes
Writing a tag bound to a Sparkplug metric sends a command to the edge node — an NCMD for a node
metric, a DCMD for a device metric — typed with the data type the metric's birth declared.
The value is converted to that type correctly now. 1.0.7 Two conversions were wrong without anything saying so:
- A write of an integer to a Boolean metric —
1, from a numeric input or a script — went out asfalse. Non-zero is nowtrue. - A write of a text timestamp (
2026-09-23T08:00:00Z) to a DateTime metric went out as 1 January 1970. It now carries the time it names.
JSON and byte values also go out as JSON text and as the text the bytes hold, rather than in an internal notation no edge node can read.
This page is the inbound half. To publish QUBIQ's own tags to a broker, as a Sparkplug edge node, see MQTT publishing.
Choosing between them
| Use classic MQTT when | Use Sparkplug B when |
|---|---|
| The publisher is not Sparkplug-aware | Edge devices already speak it |
| Payloads are your own JSON or scalars | You want typed, self-describing metrics |
| Topic structure is fixed and small | You want automatic discovery of a large plant |
| You do not need liveness semantics | You need death certificates to invalidate stale values |
If you control both ends and the deployment is more than a handful of tags, Sparkplug pays for itself in the metadata alone.
TLS
Set the protocol to ssl/tls (or wss) and use the TLS port. QUBIQ validates the broker's
certificate chain. For a private CA, ensure the CA is trusted by the host — QUBIQ uses the system
trust store.
Quality and liveness
| Condition | Tag quality |
|---|---|
| Message received and parsed | Good, or the device's own quality if a Quality Path is set |
| Broker connection lost | Bad after the connection is marked down |
Sparkplug DDEATH/NDEATH for the device | Bad |
| The device's status topic says offline 1.0.8 | Bad until a fresh value |
| Payload could not be parsed, or the JSON path did not resolve | Bad |
| Retained message replayed with no device time 1.0.8 | Uncertain, not historised |
| No message yet since subscribe | Unknown — the device has not reported a value yet |
When the connection drops, the value a tag keeps showing is its last Good one.
1.0.8 A Sparkplug null or a Bad metric used to replace it,
so the display went blank at the moment comms failed. A Bad Sparkplug metric also no longer
counts as proof that a disconnected connection is back; only a Good one does.
Because MQTT is push-only, a device that publishes on change sends nothing while its value holds steady. A device that publishes on a cycle can use stale after to make silence visible; a device with a Last Will is better served by its status topic.