Publishing JSON Files via MQTT Client FB on PLCnext

Daniel Price7 min read
Other ManufacturerSerial CommunicationTechnical Reference
Licensed PE Working through this on a live machine? A Maine-licensed engineer can take it from here — included with IMD hardware, by the hour for everything else. Book an engineer

Follow the packet. A JSON document leaves the controller as a byte array inside an MQTT PUBLISH packet, crosses TCP to the broker, and is fanned out to every subscriber matching the topic filter. The broker never parses it, never validates it, and never cares that the bytes happen to be JSON. That means the question is never "does MQTT support JSON" — it is "where in the path does the payload get truncated, mangled, or refused."

Can the MQTT client function blocks carry JSON?

Yes. The MQTT_Library_2 function blocks from the PLCnext Store publish and subscribe arbitrary payloads, and the JSON Utility Library handles construction and parsing on the controller side. The PLCnext IIOT_Library example project published on GitHub demonstrates both directions: building a JSON string, publishing it, subscribing to it, and parsing it back into structured variables.

The constraint is not the protocol and not the broker. It is the function block interface.STRING, so a JSON file has to be read into a single STRING variable before it can be published, and reassembled from a single STRING on the subscribe side. The maximum string length configured in PLCnext Engineer becomes the hard ceiling on file size. Everything below is a sequence of checks that locates which ceiling you actually hit.

Check 1 — Does the packet leave the controller?

Layer one first. Before debugging payload content, confirm the connect FB reaches CONNACK. Read the status and error outputs of the connect block; a client that never connects will still accept publish calls and silently discard or queue them depending on library behaviour.

Path segment Default port What to check
Controller → broker, plaintext 1883/TCP Route, VLAN, firewall rule between PLC subnet and broker
Controller → broker, TLS 8883/TCP CA certificate loaded into the controller trust store; broker hostname must match the certificate CN/SAN
MQTT over WebSockets Operator-defined, usually behind an HTTPS reverse proxy Proxy forwards the WebSocket upgrade; idle timeout longer than the MQTT keep-alive

Branch on the result:

  • No TCP handshake — stop here. Ping the broker from the controller's Linux shell, then confirm the port with a capture on the broker side. This is a network problem, not an MQTT problem.
  • Handshake but no CONNACK — duplicate client ID (two controllers with the same ID kick each other off in a loop), bad credentials, or TLS negotiation failure. The broker log names the reason; the FB error output usually only reports a generic connect failure.
  • CONNACK received, publish returns no error, subscriber sees nothing — topic mismatch or ACL. Subscribe to # with a desktop client against the same broker and credentials to see whether the message arrives at all.
  • Message arrives but is short or unparseable — go to Check 2.

Check 2 — Does the JSON fit in one STRING variable?

This is where most JSON-over-MQTT work on PLCnext stops. Read two numbers and compare them:

  1. The declared length of the payload variable in the PLCnext Engineer variable table. An unqualified STRING takes the project's default length; STRING[n] takes n. Read the actual declaration, do not assume.
  2. The declared length of the FB's payload input port. The effective ceiling is the smaller of the two — assignment into the port truncates at the port's limit even if your variable is longer.

Then measure the file.

Truncation is silent. The publisher clips the tail, the broker forwards a well-formed MQTT packet, and the subscriber gets JSON that fails with a parse error at or near the last byte. If the reported parse error is always at the end of the document and the error position roughly equals your string limit, you have found the fault.

Check 3 — Which branch when the file exceeds the string limit?

Four exits, in order of how often they are the right one:

Branch When to take it Cost
Build JSON in the controller instead of reading a file The file was generated by the PLC anyway None — the JSON Utility Library serialises from variables and the file step disappears
Shrink the payload File is marginally over the limit Strip pretty-print whitespace, shorten keys, publish deltas instead of full state
Split into multiple topics The document is a flat set of independent values Consumer reassembles; loses document atomicity
Chunk and reassemble The document must stay one unit and is genuinely large Publish fixed-size fragments with a sequence index and total count on a dedicated topic at QoS 1; subscriber buffers and concatenates. You now own ordering, timeout, and partial-message cleanup

A fifth exit is architectural: move the bulk transfer to a channel built for it — HTTPS, OPC UA, or a file service — and publish only a small JSON envelope over MQTT containing a URI and a checksum. MQTT is an event bus, not a file transfer protocol; chunking large files through it turns the broker into a reassembly queue you have to maintain.

What breaks between valid JSON and a parsed message?

  • Trailing bytes from the file read. A CRLF, a trailing NUL, or padding spaces left by a fixed-length read appended after the closing brace will fail strict parsers. Trim to the last } before publishing.
  • QoS 0 on a document you cannot lose. QoS 0 has no retransmission. If the TCP connection drops mid-publish the message is gone with no error at the application layer. Use QoS 1 for anything transactional and make the consumer idempotent, because QoS 1 can duplicate.
  • Retained flag left set. A retained JSON message is delivered to every new subscriber immediately, including stale process values after a controller restart. Set it deliberately or not at all.
  • Broker message size limit. Brokers commonly enforce a configurable maximum packet size and disconnect the client that exceeds it rather than returning an error. If the client drops at the moment of a large publish, read that limit in the broker configuration.
  • Keep-alive versus scan time. The MQTT client needs its cyclic call to run often enough to service PINGREQ within the keep-alive interval. A client parked in a slow task disconnects on the keep-alive timer and looks like a network fault.

Publishing and verifying the payload

  1. Install MQTT_Library_2 and the JSON Utility Library from the PLCnext Store and add both to the PLCnext Engineer project libraries.
  2. Declare the payload variable explicitly as STRING[n] with n sized above the largest expected document, and confirm the FB payload port accepts that length.
  3. Instantiate the connect FB with broker address, port, client ID, credentials, and keep-alive. Call it every cycle and latch its status output into a diagnostic variable.
  4. Populate the payload — either serialise from controller variables with the JSON Utility Library, or read the file into the single STRING and trim trailing bytes.
  5. Call the publish FB with topic, QoS, and retain flag. Gate the trigger on a rising edge; do not publish every scan.
  6. On the receiving side, subscribe to the topic, copy the received STRING, and parse it with the JSON Utility Library into structured variables.

Verify in this order. Subscribe from a separate desktop MQTT client on the same broker and confirm the message arrives on the expected topic. Compare the received byte count against the source file byte count — equal length proves nothing was truncated. Pipe the received payload through a JSON validator and confirm it parses without error. Then close the loop in the controller: parse the subscribed string with the JSON Utility Library and confirm the resulting variable values match the published source, field by field, with the FB parse status reading no error.

FAQ

Can I publish a JSON file directly from the PLCnext file system over MQTT?

Not as a file. Read the file contents into a single STRING variable and publish that string; the subscriber receives the string and writes it back to a file if needed. The transferable file size is capped by the maximum string length configured in PLCnext Engineer.

Does the broker limit how large a JSON payload can be?

Brokers enforce a configurable maximum packet size and typically disconnect the client rather than return an error when it is exceeded.STRING length is almost always the lower ceiling — check the variable and FB port declarations before touching broker configuration.

Can I split a large JSON document across multiple MQTT messages?

Yes, by publishing fixed-size fragments with a sequence index and total count on a dedicated topic at QoS 1 and reassembling on the subscriber. You take on ordering, reassembly timeout, and cleanup of partial messages, so prefer shrinking the payload or publishing a URI to a file served over HTTPS when the document is genuinely large.

Back to blog