MQTT Publishing New in 1.0.0
Everything else in this section is about getting data in. This page is the other direction: mirroring live namespace tags out to an MQTT broker QUBIQ does not host, so a cloud platform, an analytics stack or another SCADA system can subscribe to your plant.
It does not matter where a tag came from. An OPC-UA tag, a Modbus register, an expression tag and a tag QUBIQ computes itself all publish the same way, because a publisher reads the namespace, not a protocol.
Broker egress belongs to the MQTT Driver module. Without it you can still create, edit and turn publishers off — but none can be turned on, and the Publishing view says so by name rather than failing generically. → Licensing & modules
Where it lives
Publishing is part of the Namespace panel, not Settings — it is a fence over the tags that panel owns, and it belongs beside them.
| To… | Go to |
|---|---|
| See and manage every publisher | Namespace → MQTT Publishing (the toolbar toggle; it replaces the tree with the publisher list) |
| See where one tag goes | Edit the tag → Publishing tab |
| Publish a tag, a folder or a multi-selection | Right-click in the tree → Publishing |
Right-clicking a single tag lists the brokers themselves with a tick beside each, so publishing is one gesture. A folder or a multi-selection gets the two verbs — Publish to MQTT… and Stop Publishing… — and a dialog, because twelve tags across three brokers is a mixed state and a checkbox that quietly resolved it to "publish all" is the bulk accident worth not having.
One publisher per broker
A publisher is exactly one broker, one format, one fence. Sending the same tags to two brokers is two publishers, not a list inside one — they are independent by construction, with their own client, their own buffer and their own liveness, so a broker that is down or slow degrades only itself.
The publisher list answers four questions per row:
| Column | What it shows |
|---|---|
| Broker | The publisher's name, the connection it sends to, and a dot: green when enabled. |
| Sends | How much of the plant it reaches, then the format, QoS, and whether values are retained or buffered. |
| Status | What it is actually doing right now — published, dropped, failed, stopped. |
| On | The enable switch, plus edit and delete. |
Status comes from the running bridge service, not from the database. A saved publisher and a running one are different things, and telling them apart is the entire point of that column. If the bridge is not answering, the column says so — it does not render as "0 published", which would read as a publisher running and idle, a different problem with a different fix.
Creating a publisher
Add publisher asks for the following. Nothing publishes until you turn the publisher on afterwards — a new one is created disabled.
| Field | Default | Notes |
|---|---|---|
| Name | — | How the publisher is told apart in the list. |
| Broker | — | Any MQTT connection. |
| Format | Classic MQTT | Or Sparkplug B — see below. |
| QoS | 1 — at least once | 0 at most once · 1 at least once · 2 exactly once. |
| Group id / Edge node id | — | Sparkplug B only, and required for it. |
| Topic prefix | qubiq | Prepended to every tag's namespace path. A live preview under the field shows the topic a real tag would land on. |
| Tags → Publish | All tags | The scope fence. |
| Tags → Except | (nothing) | Subtracted from the scope. |
| Retain last value | on | The broker keeps the last message per topic, so a subscriber that connects later learns the current state instead of waiting for the next change. |
| Publish on change only | on | Report by exception. |
| Never miss a value | off | See Delivery. |
The two fences
Publish and Except sit side by side and are always visible, because how much of the plant a publisher sends is the riskiest fact about it and it should not be behind a click.
- Publish is the scope.
*means the whole plant, stated explicitly. Anything else is a list of namespace paths; a folder covers everything under it, including tags added later — which is what makes "all of Line 1" a rule rather than a snapshot. - Except is subtracted.
Line1in Publish andLine1/Diagnosticsin Except is the shape most real configurations take.
This is deliberate, on both sides of the wire. If an empty list meant "everything", then the riskiest
configuration in the product — every tag in the plant leaving for an outside broker — would be the
one you get from a dropped field. So "everything" is *, and it is never inferred.
The same rule makes excluding * a legitimate way to pause a publisher without losing its
configuration.
There is no per-tag publish flag. A fence does the same job with no per-tag rows, using the same picker for both halves, and it expresses what people actually want: everything except the diagnostics folder.
Topics
A tag's topic is the prefix followed by its namespace path — both already use /, so this is a join,
not a translation:
prefix: qubiq
tag path: Plant1/Line2/Oven1/Temperature
topic: qubiq/Plant1/Line2/Oven1/Temperature
Repeated separators collapse and the outer ones are trimmed, so a stray / in a prefix cannot
produce an empty topic level.
A prefix may not contain + or # — those belong to a topic filter, not a topic name, and the
usual way one arrives here is somebody pasting a subscription they tested in an MQTT client. It may
not begin with $ either; that namespace belongs to the broker.
Payload — classic MQTT
One topic per tag, carrying a small JSON envelope:
{ "v": 71.4, "q": "Good", "t": "2026-09-07T04:21:08.132Z", "u": "°C" }
| Key | Meaning |
|---|---|
v | The value. |
q | Quality, verbatim from the source. |
t | The source timestamp, RFC 3339. |
u | Engineering unit. Omitted when the tag has none. |
The keys are short on purpose: this is written once per tag change per broker, and on a plant with
tens of thousands of tags the difference between value and v is real bytes on the wire and real
storage in every retained message. The vocabulary is the one Sparkplug and most SCADA bridges already
use, so a subscriber needs no QUBIQ-specific documentation to read it.
Sparkplug B egress
Choosing Sparkplug B makes the publisher an edge node rather than a topic writer, and the group id and edge node id become part of every topic it sends.
| Message | When |
|---|---|
NBIRTH | On connect, and again on request. Declares the full metric set with aliases and datatypes. |
NDATA | Every subsequent value, numbered and carrying aliases only. |
NDEATH | Registered with the broker as the Will before the connection exists, so an ungraceful disconnect still announces the node as dead. |
Two details matter in practice:
bdSeqpairs a death with the birth it ends. TheNDEATHpublished as the Will carries the same birth/death sequence theNBIRTHannounced, so a stale death left over from a previous session cannot kill the current one.- A host can demand a rebirth.
Node Control/Rebirthon the node'sNCMDtopic makes the publisher re-announce its whole metric set — which is how a host that missed the birth resynchronises without restarting anything.
Sequence numbers wrap at 256 and aliases are fixed for the life of a session. Get either wrong and a compliant host discards the stream silently, because that is what the specification tells it to do — which is why the session state machine is a separate, exhaustively tested piece rather than something the publisher improvises.
Delivery: live, or buffered
Never miss a value is the one switch that changes what happens to a value while the broker is away, and it is a genuine trade rather than a quality setting.
| Off — live (default) | On — buffered | |
|---|---|---|
| How it publishes | Asynchronously, up to 256 un-acked messages in flight | One at a time, in order, blocking on each ack |
| When the broker cannot keep up | The value is dropped; the newest wins | The value waits in a durable buffer |
| Can it fall behind? | No — it stays live | Yes, and that is what the buffer is for |
| Right for | Dashboards and HMIs, where the current value is the whole point | A consumer doing arithmetic on every sample — totalisers, billing, batch records |
Live mode leans on Retain last value to cover the gap: a subscriber that connects after a drop still gets the current value from the broker's retained message.
Buffered mode is at-least-once, not exactly-once. A redelivery after an ack that was lost in flight republishes a value the broker already has, which for a tag stream is harmless — the same value on the same topic. Nothing here pretends otherwise.
Report by exception
Publish on change only is on by default, and it does real work: the internal stream carries the scan rate, not the change rate, so a polled protocol producing a reading every 200 ms would otherwise send 300 identical messages a minute to your broker.
It uses the tag's own deadband, so a tag already tuned for the historian is already tuned for the broker. A publisher can override that with an absolute deadband in engineering units through the API — absolute, never percent; the percentage form belongs to alarm hysteresis, which is a different concept on a different model.
Loop protection
Publishing tags to a broker QUBIQ also reads from is how a feedback loop starts: a value goes out, comes back in as an update, and goes out again. Four layers stand in the way, and the last one is the one that matters.
- Configuration. A cycle the configuration can prove is rejected before it runs.
- Origin exclusion. A value is never published back to the connection it came from. This kills self-echo outright, and the direct leg of an A→B→A pair. A value whose origin cannot be determined is dropped, not passed: an unattributable value is exactly the one that might be a loop, and dropping it costs one sample where publishing it risks a storm.
- Timestamp. A value that is not newer than the last one sent is collapsed. This works for Sparkplug sources; classic MQTT ingest re-stamps values with its own receive time, so a looped classic value always looks newer and this layer cannot fire for it — which is why there is a fourth.
- The storm breaker. Each tag is capped at 50 messages per second per broker by default. A tag that sustains more than that is a feedback loop, not a process — no physical measurement needs 50 updates a second on a broker.
The breaker is a token bucket, so a genuine process event that jumps and settles spends burst allowance and recovers; only a sustained rate trips it. And tripping is sticky: the tag is quarantined on that broker and stays stopped until somebody releases it. A rolling limiter would publish 50 messages a second forever, which is a slower storm rather than no storm, and would never present an operator with a fact to act on.
A quarantined tag shows in the Publishing view and on the tag's own Publishing tab, with a badge on the toolbar counting them. Releasing one needs Edit connections and is audited.
Permissions
Publishing reuses the connection vocabulary rather than inventing a second one — a publisher is a use of a connection, and anyone who may edit connections can already point one anywhere.
| Action | Permission |
|---|---|
| See publishers, their status and their coverage | View connections |
| Create a publisher | Create connections |
| Edit one, turn one on or off, release a quarantine | Edit connections |
| Delete one | Delete connections |
Turning a publisher on is what starts plant data leaving the building, so it is gated on edit rather than view, and it is audited on its own rather than as part of a save. → Audit journal
Troubleshooting
| Symptom | Check |
|---|---|
| Publisher is on, nothing arrives at the broker | Is a tag in the Publish fence also caught by Except? The exception wins. The bulk dialog says so before you save; the fences themselves do not. |
| "Nothing is published to a broker" and the switch will not turn on | The MQTT Driver module is not licensed. |
| Status shows nothing at all | The bridge service is not answering — check it under Administration → Services. |
| A tag stopped publishing on its own | The storm breaker quarantined it. Find the loop before releasing it, or it will trip again. |
| Values arrive but a Sparkplug host ignores them | A missed NBIRTH. Send Node Control/Rebirth, and check the group and edge node ids are unique on that broker. |
| A subscriber that joins late sees nothing until the next change | Retain last value is off. |
| Topics have an empty level in them | A stray separator in a namespace name — the join collapses repeats, so this is a name to fix rather than a prefix. |
See also
- MQTT & Sparkplug B connections — the inbound half
- Tags — deadband, quality and units, all of which travel with a published value
- Store and forward — the same durable-buffer idea, for database writes