Knowing how to build a unified namespace turns a buzzword into a working architecture: one MQTT broker where every machine, line and system publishes its current state under a predictable, hierarchy-based topic. In this tutorial you will model your plant, choose a broker, publish retained edge data with Python, add a consumer that reads the whole plant state, and put the governance in place that keeps the namespace usable as it grows.
What You Are Building
A unified namespace (UNS) is not a product. It is an agreement: all producers publish into one event-driven hub, organised by a shared structure, and all consumers subscribe to what they need instead of building point-to-point integrations. In practice that hub is an MQTT broker and the structure is usually the ISA-95 equipment hierarchy.
The finished architecture has four layers:
| Layer | Responsibility | Typical components |
|---|---|---|
| Edge | Read machines and publish state | PLC gateways, OPC UA or Modbus bridges, Sparkplug edge nodes |
| Hub | Route and hold current state | MQTT broker with retained messages |
| Structure | Make data findable | ISA-95 topic tree, payload conventions |
| Consumers | Use the data | Dashboards, historians, MES, analytics, alerting |
The key property is decoupling. The historian does not know the PLC exists, and the PLC gateway does not know who is listening. Each connects once, to the broker.
Step 1: Model Your Plant Hierarchy
Before writing any code, decide how the plant is organised in the namespace. The ISA-95 equipment hierarchy gives you a proven starting point: enterprise, site, area, line (or process cell), and cell or machine. Our ISA-95 equipment hierarchy guide explains each level with plant examples.
Work through a short list for a pilot area:
- List the sites in scope and give each a short, stable, lowercase identifier (
dallas,izmir). - Within one site, list the areas (
packaging,utilities,machining). - Within one area, list the lines and their machines (
line2/filler,line2/capper). - Decide what goes under each machine: one
telemetryobject, individual metric topics, or both. - Write the result down as a topic tree and get operations, engineering and IT to agree on it.
A first pilot tree might look like this:
acme/dallas/packaging/line2/filler/telemetry
acme/dallas/packaging/line2/filler/state
acme/dallas/packaging/line2/capper/telemetry
acme/dallas/utilities/compressors/comp1/telemetry
Spend time here. Renaming a topic after twenty consumers depend on it is painful. Our guides on ISA-95 MQTT topics and UNS topic structure contain ready-made trees and the pitfalls to avoid.
Step 2: Choose the Central Broker
The broker becomes the most important piece of plant software you run, so choose deliberately. It must support MQTT 3.1.1 for older gateways and MQTT 5 for newer clients, retained messages for current state, TLS with per-client credentials, and enough connections for every gateway and consumer you plan to add. For a full checklist see how to choose an IoT MQTT broker.
You can run the broker yourself on a server in the plant or use a cloud MQTT broker that someone else operates. Plants often begin with a hosted broker for the pilot because it removes server patching and monitoring from the critical path. ConnectMQ, for example, gives each broker MQTT 3.1.1 and 5.0, TLS on 8883, a live topic explorer, and a devices view that groups live devices by ISA-95 levels, which is exactly what you want to see while the namespace takes shape.
For this tutorial you can use the public test broker at broker.connectmq.com. It needs no account, but everything published there is readable by anyone, so we prefix topics with connectmq/demo/<random-id>/ and publish only simulated values. The public broker allows up to 8 topic levels, which fits connectmq/demo/k4p9/dallas/packaging/line2/filler/telemetry exactly.
Step 3: Publish Edge Data as Retained State
The edge layer reads machines and publishes their current state. Real deployments use OPC UA, Modbus or PLC drivers; here a Python script stands in for a gateway so you can see the publishing rules clearly. Install the client with pip install "paho-mqtt>=2.0".
import json
import random
import time
from datetime import datetime, timezone
import paho.mqtt.client as mqtt
BROKER = "broker.connectmq.com"
PREFIX = "connectmq/demo/k4p9" # replace k4p9 with your own random ID
MACHINES = [
("dallas", "packaging", "line2", "filler"),
("dallas", "packaging", "line2", "capper"),
]
def on_connect(client, userdata, flags, reason_code, properties):
print("gateway connected:", reason_code)
for site, area, line, machine in MACHINES:
state_topic = f"{PREFIX}/{site}/{area}/{line}/{machine}/state"
client.publish(state_topic, "online", qos=1, retain=True)
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="uns-gateway-k4p9")
client.on_connect = on_connect
# If the gateway dies, the broker marks the first machine offline for everyone
client.will_set(f"{PREFIX}/dallas/packaging/line2/filler/state", "offline", qos=1, retain=True)
client.connect(BROKER, 1883, keepalive=30)
client.loop_start()
counts = {m[3]: 0 for m in MACHINES}
try:
while True:
for site, area, line, machine in MACHINES:
counts[machine] += random.randint(4, 6)
payload = {
"timestamp": datetime.now(timezone.utc).isoformat(),
"speed_bpm": round(random.uniform(110, 125), 1),
"temperature_c": round(random.uniform(38, 44), 1),
"good_count": counts[machine],
}
topic = f"{PREFIX}/{site}/{area}/{line}/{machine}/telemetry"
client.publish(topic, json.dumps(payload), qos=1, retain=True)
time.sleep(5)
except KeyboardInterrupt:
client.loop_stop()
client.disconnect()
Three rules make this a UNS publisher rather than just a data sender. Every message is retained, so a new consumer gets the current value immediately. Payloads carry their own timestamp and units in the field names. And machine availability is explicit, with a will message that flips state to offline when the gateway disappears.
If your edge already speaks Sparkplug B, you do not have to rewrite it. ConnectMQ decodes Sparkplug B payloads and can republish them into ISA-95 topics, for example spBv1.0/factory1/DDATA/line1/cnc1 into connectmq/factory1/production/line1/cnc1/telemetry. That lets Sparkplug edge nodes and plain JSON publishers share one namespace. The trade-offs between the two are covered in MQTT, Sparkplug B and the unified namespace.
Step 4: Add Your First Consumers
A namespace earns its keep when consumers appear without anyone touching the edge. This subscriber builds an in-memory model of the whole plant from a single wildcard subscription:
import json
import paho.mqtt.client as mqtt
PREFIX = "connectmq/demo/k4p9"
plant = {}
def on_connect(client, userdata, flags, reason_code, properties):
client.subscribe(f"{PREFIX}/#", qos=1)
def on_message(client, userdata, msg):
levels = msg.topic[len(PREFIX) + 1:].split("/")
if len(levels) != 5:
return
site, area, line, machine, kind = levels
node = plant.setdefault(site, {}).setdefault(area, {}).setdefault(line, {}).setdefault(machine, {})
text = msg.payload.decode()
node[kind] = json.loads(text) if kind == "telemetry" else text
print(f"{site}/{area}/{line}/{machine} {kind}: {node[kind]}" + (" (retained)" if msg.retain else ""))
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="uns-viewer-k4p9")
client.on_connect = on_connect
client.on_message = on_message
client.connect("broker.connectmq.com", 1883, keepalive=60)
client.loop_forever()
Start it while the gateway runs and notice that the first messages are flagged as retained: the consumer had the full plant picture the moment it subscribed. Narrow the scope with wildcards after the prefix, for example connectmq/demo/k4p9/+/packaging/# for one area in every site or connectmq/demo/k4p9/+/+/+/filler/telemetry for every filler everywhere.
Typical next consumers are a dashboard, a historian and an alerting service. Each is just another subscriber. For storage, our MQTT historian guide shows Telegraf and Python subscribers feeding time-series databases; the namespace stays the source of current truth while storage holds history.
Step 5: Govern the Namespace
Without rules, a UNS decays into a topic swamp within months. Put these in place before the second area joins:
- Naming standard. Lowercase, hyphens instead of spaces, no personal names or ticket numbers in topics.
- Ownership. Each branch of the tree has an owner who approves new topics.
- Payload contract. A documented JSON schema per topic type, with units and timestamp rules.
- Credentials per publisher. One identity per gateway or application so you can see who publishes what and revoke access cleanly.
- Change process. New topics are added, old topics are deprecated with a sunset date, never silently renamed.
- Observability. Someone watches connection state, message rates and stale topics.
ConnectMQ's portal helps with the observability part: the live topic explorer shows the tree as it grows, the ISA-95 devices view shows which enterprise, site, area and line each live device belongs to, and threshold alert rules notify you when a value crosses a limit.
Common Mistakes When Building a UNS
| Mistake | Consequence | Better approach |
|---|---|---|
| Starting plant-wide | Months of modelling before any value | Pilot one line, then expand |
| Non-retained state | New consumers see nothing until values change | Retain current state topics |
| Technology in the topic path | opcua/ and modbus/ leak into consumers |
Model the plant, not the protocol |
| One shared broker login | No accountability, risky revocation | One credential per client |
| Using the UNS as a database | Broker holds history it was never meant to hold | Historian or data lake subscribes |
For the broader industrial context, see our industrial IoT MQTT guide.
Build Your Unified Namespace on ConnectMQ
A unified namespace needs a broker you can trust to be up and a clear view of the topic tree as it grows. ConnectMQ is a managed MQTT broker with MQTT 3.1.1 and 5.0, TLS, retained messages, Sparkplug B decoding, ISA-95 republishing and an ISA-95 devices view. Start your pilot on the free Serverless plan at app.connectmq.com, no credit card required, then move to a paid, dedicated or BYOC plan as more lines join.
Frequently Asked Questions
Do I need Sparkplug B to build a unified namespace?
No. Many namespaces use plain JSON over MQTT. Sparkplug B adds state management and typed metrics, and the two can coexist if the broker republishes Sparkplug data into readable topics.
Should the UNS broker run on-premise or in the cloud?
Both work. On-premise keeps traffic local; a hosted broker removes operations work and makes cross-site access easier. Many plants start hosted for the pilot and decide based on what they learn.
How big should the first UNS pilot be?
One line or one area with a handful of machines and two or three consumers is enough to prove the pattern and refine the naming standard.
Is a unified namespace a replacement for a historian?
No. The UNS holds current state and events; a historian or data lake subscribes to it and keeps long-term history.



