MQTT

MQTT connects Niagara to the world outside the building – cloud analytics, IoT sensors, and enterprise platforms that speak publish/subscribe rather than BACnet. Software Pile builds MQTT integrations that treat the broker as production infrastructure: authenticated, resilient, and observable.

Two Directions, Different Problems

Publishing station data outward – to cloud platforms, analytics pipelines, or a corporate broker – is about topic design, payload schemas (plain JSON, Sparkplug B, or your platform’s format), QoS choices that match what the data is worth, and TLS with proper certificate handling on the station.

Subscribing to external data – wireless sensors, LoRaWAN gateways, third-party feeds – is about turning loosely structured payloads into typed Niagara points with histories and alarms, and deciding what happens when the feed goes quiet.

Reliability Details That Matter

  • Reconnect and session behavior when the WAN drops – and what the station does with stale values meanwhile
  • Last-will messages so the other side knows the station went away
  • Buffering strategy for histories during outages
  • Broker authentication: credentials, client certificates, and rotation without site visits

Start the Conversation

Tell us what should flow where: which points, toward which platform or broker, at what rate, and your Niagara version. If a custom payload format is involved, a sample message tells us most of what we need.

Who Owns the Topic Namespace?

On a single site nobody asks. Across a portfolio it becomes the question that determines whether the cloud side is maintainable. If each site invents its own topic structure, the receiving team writes a parser per site and maintains all of them forever.

Agreeing a hierarchy up front, aligned with equipment and point naming and ideally with Project Haystack tagging, lets subscribers reason about data they have never seen before. Renaming topics later breaks every consumer downstream, which effectively means the first structure is the one you keep. Settle it before the first message is published.

Payload Schemas Outlive the Project

The message format agreed in a kickoff meeting will still be parsed by something years after everyone involved has moved on. Include a version field from the first message. Add fields additively so existing consumers keep working. Write the schema down somewhere both sides can find it.

Sparkplug B is worth considering where it fits, since it defines metric structure along with birth and death semantics, so a subscriber knows what a device publishes and when it went away. A plain JSON payload gives more freedom and puts the whole burden of documentation and discipline on you.

Publish Rate Is a Design Decision

Every analog point publishing on a fixed interval generates traffic whether or not anything changed. Change-of-value publishing with a deadband removes the messages that carry no new information, which matters most for slow-moving values. How much traffic that actually saves depends on the points and the deadband you choose, so measure it against your own data before quoting a figure to whoever owns the link. Fast-moving points may need interval publishing, and that is a per-point decision.

Where the link is cellular, shared with tenants, or metered, publish rate stops being a technical detail and becomes a constraint the design has to respect. History backfill after an outage deserves particular thought, since a station reconnecting and flushing a buffered backlog at full speed can saturate exactly the link that just recovered.

Control Over MQTT Deserves a Deliberate Decision

Publishing telemetry outward and accepting commands inward are entirely different security propositions. The first exposes data. The second gives whatever can publish to a topic the ability to influence a building.

If commands are in scope, that path needs designing: a command topic separate from telemetry, authorization on who may publish to it, acknowledgment so the sender knows what happened, and station-side limits that reject values outside a sane range regardless of what was received. Publishing outward only and keeping control local is a defensible architecture, and one to consider before anyone assumes two-way is required.

Where the Broker Lives and Who Watches It

A broker on the corporate network, a managed cloud broker, and a broker owned by an analytics vendor each imply a different support arrangement when something stops working on a Saturday.

The questions to settle early: who is responsible for broker availability, who is notified when it goes down, what the station does with data while it is unreachable, and how long that buffer lasts before the oldest data is discarded. Last-will messages let subscribers know the station disconnected, and that only helps if somebody is listening for them. The Platforms page sets out which layer of the Niagara stack a given problem belongs to, and how cloud destinations and enterprise systems attach to it.

QoS, Retained, and Session State Are Three Different Settings

These three are easy to conflate, and each one solves a different problem. Quality of service governs the delivery of a single message: QoS 0 hands it to TCP and forgets it, QoS 1 retries until the broker acknowledges it and therefore delivers duplicates after a reconnect, and QoS 2 adds a four packet handshake so the message arrives once, at the cost of extra round trips and state held on both ends. The level that actually applies is the lower of the two ends. Publishing at QoS 2 to a subscriber that subscribed at QoS 0 delivers at QoS 0, so a QoS decision made only on the publishing side can be undone by the consumer without anyone being told.

Session state governs what the broker remembers about a client that is not connected. Clean start, called clean session in MQTT 3.1.1, decides whether subscriptions and queued QoS 1 and QoS 2 messages survive a disconnect, and that state is keyed to the client ID. A station that reconnects with a different client ID gets an empty session and leaves the queued messages attached to an identifier nothing will ever claim. Two clients sharing one ID is the opposite failure: the broker disconnects the first when the second connects, and if both keep retrying the result is a reconnect loop that looks like a flapping WAN. In MQTT 5 the session expiry interval sets how long the broker holds that state; in 3.1.1 it holds until a client connects with clean session set.

A retained message is the broker keeping the most recent message published on a topic with the retain flag and handing it to every new subscriber at the moment it subscribes. There is exactly one per topic, a later retained publish replaces it, and a zero length payload published with the retain flag clears it. This matters because MQTT has no way to read a topic on demand: without a retained value, a dashboard that connects between publishes sees nothing until the next one. A retained value also carries no indication of its own age, so unless the payload includes a timestamp a subscriber cannot tell a current reading from one left behind by a station that went offline last month. All three settings are chosen per class of data rather than once for the whole station:

  • Alarms and events a person will act on: QoS 1, with a handler that tolerates seeing the same message twice.
  • Command topics: QoS 1 and never retained, since a retained command replays itself at every new subscriber connection and at every broker restart.
  • Fast changing analog telemetry: QoS 0, where a lost sample is replaced by the next one seconds later and the retry machinery buys nothing.
  • Setpoints, modes, and status that a dashboard reads on connect: retained, so a subscriber arriving between publishes is not blank.
  • Anything counted or totalized downstream: QoS 1 with an identifier the consumer can deduplicate on, or QoS 2 where the consumer has no way to deduplicate.

TLS Failures Do Not Look Like TLS Failures

Port 8883 is the convention for MQTT over TLS and 1883 for plaintext, and where egress policy permits only 443 the usual answer is MQTT over WebSocket on 443. The handshake itself is where a first connection commonly fails. The station validates the broker's certificate chain against its own trust store, and the hostname it was configured to connect to has to appear in that certificate's subject alternative name. Connecting by IP address to a broker whose certificate names a host is a validation failure, not a shortcut around DNS.

The station clock deserves suspicion before the certificate does. Certificate validity is a comparison against local time, so a controller with no NTP source, or one that came back from a long outage with a dead real time clock, will reject a perfectly good certificate and report a handshake error that reads like a network problem. Checking the station's time takes seconds and rules out a whole class of confusing failures.

Chains and expiry dates are the other recurring source. A broker that presents only its leaf certificate leaves the station unable to build a path to the root it trusts, even though the root is installed, and the fix is on the broker rather than on the station. Where the broker uses a self signed certificate, that certificate is imported into the station trust store directly, so rebuilding the broker with a new certificate breaks every station that trusted the old one until each is updated. If mutual TLS is in use, the client certificate on the station carries its own expiry date on its own calendar, which will not line up with the broker's.

The Protocol Has No Concept of Stale

MQTT delivers messages and says nothing about whether a value is current. There is no quality flag on the wire, no age, and no signal that a publisher has stopped publishing. A subscriber that maps a payload straight onto a point will display the last value it received indefinitely, and logic and alarms downstream will treat that number as live. Staleness is something the subscribing side imposes: a watchdog per feed or per point that puts the point into fault or down when nothing has arrived within a multiple of the expected publish interval, so the point status reflects the state of the feed rather than the last thing it said.

Last will helps less here than it appears. The broker publishes a client's will when it decides the client is gone, which happens after roughly one and a half keep alive intervals with no packet from it, and it does not publish the will at all when the client disconnects cleanly with a DISCONNECT packet. A planned station restart therefore produces silence rather than a death notice, and an unplanned drop produces one only once the keep alive timer expires. Payload timestamps are the other half of the picture, and they are only as trustworthy as the publisher's clock, which argues for comparing arrival time against payload time rather than believing either alone.

Parsing failures tend to appear in production rather than at commissioning, because the payloads seen during commissioning are the well formed ones. A value that arrives as a string where a number was expected, a null, or a boolean encoded as ON rather than true will throw inside a message handler, and that handler needs to fail for the one message rather than stall the subscription behind it. Wildcards deserve the same caution: + matches exactly one topic level, # matches all remaining levels and must be the last character in the filter, and a wide wildcard subscription on a shared broker will also deliver topics somebody adds next year. Subscribing to named topics keeps that from becoming the station's problem.

Failure Modes and the Test That Separates Them

An MQTT integration that is not working is rarely failing at the MQTT layer. Underneath it sit TCP reachability to the broker port, the TLS handshake, the CONNECT and its authentication, the subscription and whatever ACL the broker applies to it, and only then the application. Those layers fail for different reasons and can be separated in order.

Three patterns are worth recognizing on sight, because each has a different cause. A client that connects and drops in a cycle points at two clients sharing a client ID, or at a firewall or NAT device dropping an idle connection before the keep alive refreshes it. A client that stays connected while no data reaches the subscriber points at a topic mismatch or at an ACL that denies the publish, which in MQTT 3.1.1 tells the publisher nothing at all, since a QoS 0 publish is never acknowledged and a denied publish looks identical to a delivered one from the station's side. Data that arrives late or in bursts points at buffering, backfill, or broker side rate limiting rather than at connectivity. Working from the bottom of the stack up:

Confirm the station can reach the broker's port from the station's own network, not from a laptop on a different VLAN with different firewall rules.

  • Test the TLS handshake separately from MQTT. openssl s_client -connect host:8883 -servername host prints the chain the broker presents and the validity dates, which settles the certificate questions before any MQTT client is involved.
  • Connect with a generic client using the station's own credentials, mosquitto_pub or mosquitto_sub from the same network, to establish whether the credential or the driver configuration is at fault.
  • Subscribe with a wildcard on the broker side and watch whether the message arrives and under which topic. A topic that is close but not identical produces a publisher that looks healthy and a consumer that sees nothing.
  • Read the broker log. CONNACK return codes distinguish bad credentials from a rejected client ID, and disconnect entries name the reason. MQTT 5 returns the same information to the client as reason codes, which is the strongest practical argument for using it.

When a Broker Is More Than the Job Needs

A broker is another service to install, patch, and keep running, and another component sitting in the path between the station and whatever finally reads the data. Where the pattern calls for it, that cost is bought back several times over. Where it does not, the same data usually moves with fewer parts.

If exactly one system needs the data and it exposes an HTTP endpoint, a REST client on the station or an oBIX export moves the same points with one fewer service in the path. If the consumer sits on the same network and already speaks BACnet/IP, exposing the points as BACnet objects is less work than standing a message bus between two systems that can address each other directly. If what is actually wanted is an hourly or nightly file for a reporting team, a scheduled history export is easier to verify than a stream nobody is watching, because a missing file is obvious and a stopped publisher is not.

The signals that point toward a broker:

  • More than one consumer wants the same data, and the list of consumers is expected to change without the station being reconfigured each time.
  • The receiving platform defines its own MQTT ingest path, topic structure and payload shape included, and accepts nothing else.
  • Data has to move as it changes rather than on a schedule, and the consumers should not be polling the station directly to get it.
  • Many sites report to one destination, where point to point integrations would multiply with every site added.

Frequently Asked Questions

Is MQTT a replacement for BACnet or Modbus?

No. MQTT is a transport with no data model: it moves bytes on named topics and defines nothing about what those bytes mean. BACnet defines objects, properties, priority arrays, and alarm and trend services; Modbus defines registers and function codes to read them. Neither role disappears when MQTT is added, and the station keeps speaking the field protocol to the equipment while MQTT carries the result outward. Sparkplug B layers a thin model on top of MQTT, and even that stops well short of what a field protocol specifies.

Does a Niagara station need a broker, or can it be one?

It needs one. A station acts as an MQTT client, and MQTT clients never exchange messages with each other directly, so every message passes through a broker even when the publisher and the subscriber are both stations in the same building. The broker is separate software such as Mosquitto, HiveMQ, or EMQX, or a managed service such as AWS IoT Core or Azure IoT Hub. Station to station transport over MQTT is perfectly workable, but it is still a broker in the middle rather than a direct link.

Does the MQTT version matter for this kind of integration?

Mostly for diagnostics and session control. Brokers generally accept both 3.1.1 and 5.0, and a 5.0 feature only exists when both ends implement it, so the effective version is whatever the station driver supports. MQTT 5 adds reason codes on CONNACK, PUBACK, and DISCONNECT, which convert several silent failures into stated ones, along with the session expiry interval, message expiry, shared subscriptions, and user properties for metadata that does not belong inside the payload. A 3.1.1 integration works; it just gives you less to look at when it does not.

What network access does the site actually need?

Outbound TCP from the station to the broker's port, and nothing inbound. The station opens the connection, so no port forward or inbound firewall rule at the site is required, which is why this pattern suits sites behind NAT or a carrier connection with no fixed address. The port is 8883 for TLS, 1883 for plaintext, or 443 where MQTT over WebSocket is used because egress policy allows nothing else. DNS resolution for the broker hostname belongs on the list too, since connecting by name rather than by address is what allows certificate validation to succeed.

What has to exist before the first message can be published?

A broker the station can reach, an identity for the station on it with publish rights on the topics it will use, a client ID that is unique on that broker and stable across restarts, the agreed topic structure and payload schema, and a subscriber that is actually consuming. That last item is easy to assume: a station publishing correctly into a broker with nothing subscribed on the other side produces a healthy looking integration and no data anywhere. Where TLS is used, the CA certificate that signs the broker's certificate has to be in the station's trust store before the first connection attempt, not after it fails.

Who provides the broker details, and what exactly is needed?

Whoever owns the broker, which may be the customer's IT group, the analytics platform, or a third party running it on their behalf. The specifics are the hostname and port, whether TLS is required and which CA signed the broker certificate, and any topic prefix or tenant identifier the platform requires ahead of the site's own topics. Ask as well who can change an ACL and how long that takes, because an identity that authenticates correctly but lacks publish rights on the target topic produces a connected station and no data, with nothing on the station side to say why.

Can one station publish to more than one broker?

Yes. A station can hold several client connections, each with its own credentials, TLS configuration, and topic map, which is the usual answer when a corporate broker and an analytics platform both want the same points. The cost is duplicated traffic across the same WAN link and two sets of configuration that have to stay in step as points are added or renamed. The alternative is broker to broker bridging, where one broker forwards selected topics to another and the station keeps a single connection, which moves the fan out to infrastructure that is easier to change than a station.