Note
Reading an unfamiliar MQTT broker in a building
You have a hostname, a password and a claim about what is on it. MQTT gives you no directory, no timestamps and two ways to break the site while only reading.
- MQTT
- Integration
- Commissioning
There is no list of topics, and there never will be
MQTT has no directory service. A broker does not publish what topics exist,
because as far as the protocol is concerned a topic is not a thing that
exists — it is a string in a message that happened to be sent. A
client subscribed to # sees every message published from that
moment on, and that is the whole of its visibility.
Which means the first thing to be clear about with anyone waiting on your answer: what you can produce is an observation over a window, not an inventory. A device that publishes every hour is invisible in a five-minute look, and a device that has been unplugged for a month is invisible for good — unless it left something retained, which is the next section and the most useful thing on this page.
One exception, and it is a trap. A subscription to # does
not match topics beginning with $. Brokers
put their own diagnostics there — client counts, message totals,
uptime — and you have to ask for that tree by name to see any of it.
Many deployments disable or restrict it, so its absence tells you nothing
about the broker's health.
A second, smaller trap in the wildcard rules: a subscription to
site/# matches site itself, whereas
site/+ does not. And a single + matches an empty
level, so a//b — which is a legal topic with an empty
middle level — is matched by a/+/b. Topic trees built by
string concatenation produce empty levels more often than anyone
intends.
Retained messages, and the dead sensor they hide
A publisher can mark a message retained, and the broker then keeps exactly that one message per topic and hands it to every new subscriber the moment it subscribes. It is how a dashboard shows a value before the next reading arrives, and it is sensible design.
It is also how a value outlives the thing that measured it. A gateway retains a reading, the gateway is decommissioned, and the last number it ever sent is served to every new subscriber for as long as the broker lives. Every dashboard upstream shows it as current, because nothing in the message says otherwise.
Here is the part that makes it findable. The retain flag on a message as it is delivered is meaningful, and it is not the same flag the publisher set. When the broker sends a stored message to a client that has just subscribed, that flag is set. When it forwards a live message to a client that was already subscribed, the flag is cleared — even if the publisher marked it retained. So a client can tell, per message, "this is the broker's stored copy" from "this just happened". A topic that arrives with the flag set in the first instant and never speaks again is a candidate corpse, and one that keeps arriving with the flag clear is alive.
Two footnotes for anyone relying on that. Under MQTT 5 a subscription can ask for retain as published, which preserves the publisher's flag instead — useful for bridges, and it destroys exactly the distinction above, so a diagnostic client should not set it. And an empty payload published with the retain flag is not a broken message: it is the defined way to delete a retained value. A zero-byte payload in a tap is a tombstone, and seeing several usually means somebody has been cleaning up.
Nothing in the protocol tells you how old a value is
There is no timestamp in an MQTT message. Not in the fixed header, not in the variable header, nowhere. Any time you have ever seen against an MQTT value came from inside the payload, where the integrator chose to put it, or from the clock on the machine that received it.
MQTT 5 adds one genuine piece of age information, and it is worth knowing because it is the only one: a publisher can set a message expiry interval, and when the broker forwards a message it has been holding it must reduce that interval by however long it held it. So on a v5 broker a retained message can arrive announcing how much of its life is left, which is a lower bound on its age. Nobody in building automation sets it, but when it is there it is the only honest age in the system.
Everything else is inference: no update during the window, plus arriving retained. That is evidence. Confirm it against the device before telling anybody their sensor is dead, because the alternative explanation — a publisher on a long interval — looks identical.
The two ways a read-only client can still break something
A duplicate client identifier disconnects the other client.
Client IDs must be unique on a broker, and the specified behaviour when a
second connection arrives using an ID that is already in use is that the
broker drops the existing one. Connect a diagnostic tool as
gateway1 and you have just taken a gateway off the air, from a
client that never published a byte. This is the single most likely way to
cause an incident while "only reading", and the fix is trivial: a random,
obviously-diagnostic client ID, different on every run.
A persistent session leaves the broker holding a queue for
you. Connect with a session the broker is asked to keep, subscribe
to # at QoS 1, then close the laptop. The broker now
queues every message on the site for a subscriber that is not coming back,
until something fills. On a busy broker that is a disk, and the outage will
be blamed on the broker. Connect with a clean session and subscribe at
QoS 0 and there is nothing to store: at QoS 0 the broker forwards
and forgets, which is exactly what a diagnostic wants.
So "read-only" for a subscriber is three properties, not one: it does not publish, it does not take anyone's identity, and it leaves no session state behind.
What the tree tells you before you write any code
Payload shape first. MQTT 3.1.1 has no content type at all — the payload is bytes and the meaning is a convention between two parties who may both have left the company. MQTT 5 adds a content type and a payload format indicator, which are worth reading when present and absent more often than not. Everything else is inspection: JSON with which keys, a bare decimal, a fixed-width binary record, or one message carrying twenty sensors.
Then publish rate against topic design. A gateway republishing its entire state every second onto one topic per point is a different integration, costed differently, from one publishing a change of value onto a topic per device. Counts and rates per branch are how you tell, in a minute, without asking anyone.
Then the will message, if you catch a disconnection. A last-will topic is the integrator writing down what they thought failure looked like, and it is often the only design documentation that survived.
What to do with all that, on the Niagara side, has its own notes: the stock driver's limits in what the Niagara MQTT driver will and will not do, and decoding, topic design and buffering in bringing LoRaWAN and MQTT data into a Niagara station.
We publish a small read-only tap that does the observation described here — tree, counts, payload shapes, last values and retained topics that stopped updating: mqtt-tap. It is free, it never publishes, and the limits above are its limits too.
Related
Where this comes up in the work
Custom modules & drivers
Bespoke Niagara rt, wb and ux modules and drivers written against the Baja API: pure Java, signed, and stamped to install across a mixed estate.
Station engineering
JACE controller and Niagara station setup end to end: platform commissioning, TLS, users, roles, BACnet and Modbus, tagging, histories, alarms, backups.
More notes
Other things worth writing down
Bringing LoRaWAN and MQTT data into a Niagara station
Where abstractMqttDriver and jsonToolkit stop, and what LoRaWAN decoding, topic design, and store-and-forward buffering add on top.
- Integration
- LoRaWAN
- MQTT
What the Niagara MQTT driver will and will not do
It is licensed, it is capped below your licence, it is a client only, and its Discover button never contacts the broker.
- Integration
- MQTT
- Drivers
Getting data out of a Niagara station
REST, MQTT, a relational history database, file export or an HTTP client. Which suits which consumer, and what each one costs you to run.
- Integration
- Histories
- MQTT
Next step
Tell us the version, the hardware, and what it has to do.
You will get a written scope and a fixed price against it. If the honest answer is that you do not need us, you will get that instead.