sam.donche@edge

// Notes

MQTT and Sparkplug B: why factories stopped polling.

2026-07-25 · 6 min read · Industrial architecture

Most plants already move data. The question is how, and the answer is almost always polling: something asks every device for every value on a fixed cycle, whether anything changed or not. It works. It also quietly sets the ceiling on everything you want to build afterwards.

MQTT and Sparkplug B are how that ceiling comes off. Not because publish/subscribe is fashionable, but because the direction of the conversation changes, and a surprising number of hard problems stop being problems when it does.

Polling, and where it runs out

Polling is the default because it is simple and because it is what the older protocols grew up doing. A SCADA server holds a list of tags, walks the list, asks each device for its current value, writes the answer down, and starts again. Scan class of one second, five seconds, whatever the network tolerates.

For one server talking to a hall of PLCs on the same network, that is completely fine. The trouble starts when the list gets long and the consumers multiply. Three things bite:

  • You pay for silence. Most tags do not change most cycles. A motor that has held 1450 rpm for an hour still costs you a read every second. Load scales with tag count, not with information.
  • Every new consumer is a new poller. MES wants the data. So does the historian, the OEE dashboard, the analytics pilot. Each one either polls the device again or asks the SCADA server for a copy. The floor gets busier every time someone new has a question.
  • Everything points inward. A poller has to reach the device, which means routes, firewall rules and inbound ports from the enterprise network into the plant. That is a conversation with IT you get to have once per project, forever.

None of this breaks on day one. It breaks on the fourth project, when you are the third system polling the same PLC and someone asks why the scan is slipping.

Report by exception: turn the arrow around

The fix is old and simple: instead of the centre asking, the edge tells. A device publishes a value when the value changes, and stays quiet when it does not. That is report by exception.

MQTT is the transport that makes it practical. Every participant connects outbound to a broker and either publishes to topics or subscribes to them. Publishers do not know who is listening. Subscribers do not know who is publishing. Nobody polls anybody. What falls out of that is the part people underestimate:

  • Traffic tracks change, not tag count. A stable process is a quiet network.
  • Adding a consumer costs the floor nothing. The fifth subscriber is the broker’s problem, not the PLC’s. New project, new subscription, no new load on the device.
  • All connections are outbound. Edge nodes dial out to the broker and so does the consuming host, so there are no inbound holes into the plant network. In my experience this is the argument that actually wins the room, and it is rarely the one on the slide.
  • It tolerates bad links. MQTT was designed for constrained, unreliable networks, which matters the moment a site sits on cellular or a shaky VPN.

But plain MQTT is not an architecture

This is where a lot of MQTT projects go sideways. MQTT is deliberately incurious about content. It moves bytes to topic strings and takes no view on what the bytes mean or how the topics are named. Left alone, that gives you:

  • Topic soup. Every integrator invents a naming scheme. Six months later plant1/line3/mixer/temp, Line_3/Mixer/Temperature and f1/l3/mx/t1 all describe the same sensor.
  • Payloads with no contract. Is that JSON, or a raw float? Which unit? Which data type? Whose clock stamped it?
  • No way to know what exists. A subscriber that connects now sees only what publishes next. There is nothing to ask “what tags does this device have.”
  • No way to know what is alive. A device that stopped publishing looks exactly like a device with nothing to say.

That last one matters most. Silence is ambiguous, and an architecture where you cannot tell stable from dead is not one you want underneath a control room.

Sparkplug B: the contract on top

Sparkplug is an open specification that adds the missing agreements to MQTT: how topics are named, how payloads are encoded, and how session state is handled. It came out of Cirrus Link and now lives at the Eclipse Foundation as Eclipse Sparkplug. The version you meet in the wild is Sparkplug B, which is why every topic starts with spBv1.0.

It is a thin layer. Start with the topic, which is structured rather than free-form:

spBv1.0namespace
/
plant1group id
/
DDATAmessage type
/
line3-edgeedge node
/
mixerdevice (optional)

Group, edge node and device are yours to name. The namespace and the message type belong to the spec. That single rule kills topic soup, because every topic in the estate has the same shape and the message type is machine-readable instead of a convention someone has to remember.

Birth and death certificates

This is the idea worth stealing even if you never run Sparkplug.

When an edge node connects, before it sends a single value, it publishes a birth certificate: NBIRTH for the node and DBIRTH for each device beneath it. The birth carries the full set of metrics with their names, data types and current values. Any consumer that joins later can request a rebirth and receive the whole picture. Discovery stops being a spreadsheet somebody maintains by hand.

After that the node publishes only what changes, as NDATA and DDATA. Small messages, no repeated metric names (the birth can assign each metric a numeric alias), and no traffic at all when nothing is happening. Commands travel the other way as NCMD and DCMD, on the same structured topics.

And when the node disappears, the broker announces it. At connect time the node registers an NDEATH message as its MQTT Last Will and Testament: a message the broker is told to publish on the node’s behalf if the connection drops. Nobody has to notice the silence and infer death, because the death gets published. That is the whole difference between a value that is stale and a value that is merely steady, and it is why data arriving over Sparkplug can carry a quality flag you actually trust.

The details that make it survive a plant

  • Typed, compact payloads. Sparkplug encodes with Google Protocol Buffers: small on the wire, explicitly typed, with a timestamp per metric. You are not reverse-engineering somebody’s JSON dialect two years later.
  • Sequence numbers. Every message in a session carries a rolling sequence number. A consumer that sees a gap knows it missed something and can ask for a rebirth, rather than quietly running on an incomplete picture.
  • Host state. The primary consuming application publishes its own STATE message, so edge nodes can tell whether anyone is actually listening. Implementations use that to buffer locally and forward when the host comes back, which is how a site survives a WAN outage without a hole in its history.

What it is not

It is not a replacement for device protocols. Something still has to talk to the PLC, over OPC UA, Modbus or a native driver, and that something is what publishes to the broker. Sparkplug starts at the edge node, not at the terminal block.

It is not for hard real-time closed-loop control either. Interlocks and safety stay in the PLC where they belong. MQTT moves data and supervisory commands; it does not offer you determinism.

And it is not a unified namespace, whatever the slide deck says. Sparkplug gives you a consistent, self-describing topic structure, which is an excellent foundation for a UNS and the reason the two get conflated. But deciding what the hierarchy means, in your company’s words for plant, area, line and cell, is a modelling exercise that no specification does for you.

Polling is not wrong either. One SCADA server on a flat network with a few hundred tags needs none of this. The point where the change pays for itself is when you have several consumers, several sites, a link you do not control, or a queue of data projects longer than one item.

Where it sits

In the layer model from the previous note, none of this replaces a layer. SCADA still supervises and controls. The historian still records. MES still orchestrates production. Sparkplug over MQTT is the plumbing that gets the same data to all three without each one drilling its own hole down to the PLC.

That is the real win, and it is not the protocol. It is that the next thing you want to build subscribes instead of integrates.

Weighing this up for your own plant, or halfway into an MQTT project that grew topic soup? That’s the kind of architecture I help manufacturers get right.

Get in touch

← all notes