Industrial IoT

CODESYS MQTT Client: Publishing PLC Variables to a Broker

Configure the CODESYS IIoT MQTT Client library to publish PLC variables as JSON, verify them on broker.connectmq.com, then move to a private broker with credentials and TLS.

CODESYS development environment with a structured text program publishing PLC variables to a cloud broker, illustrating CODESYS MQTT
Run this on your own MQTT brokerGet a private, managed MQTT broker on the Free plan and start from ready-made code samples.
Try it free Code samples No card required

CODESYS MQTT support turns any CODESYS-based controller, from a vendor PLC to a Raspberry Pi running the CODESYS runtime, into a direct publisher of plant data. In this tutorial you will add the CODESYS IIoT MQTT Client library to a project, publish PLC variables as JSON with structured text, verify them on a public broker, and then secure the connection with credentials and TLS. Along the way you will see the pitfalls that typically cost a commissioning day.

Why CODESYS MQTT Is Worth Doing

CODESYS is the runtime behind a large share of the world's PLCs and industrial controllers, sold under many vendor brands. That means one integration approach covers a lot of hardware. Publishing directly from the controller has clear benefits:

  • No extra gateway hardware or software to maintain for small installations.
  • Data leaves the controller in exactly the format and at the moment the PLC programmer decides.
  • Report-by-exception logic lives next to the process, where deadbands and states are understood best.

The trade-off is that the PLC programmer now owns network code. If you are connecting many controllers from different vendors, compare this with gateway-based designs in PLC to cloud connectivity before committing.

Prerequisites

Item Notes
CODESYS Development System V3.5 A recent service pack; install the IIoT Libraries SL package via the CODESYS Installer
A CODESYS runtime A vendor PLC, CODESYS Control Win for testing, or CODESYS Control for Raspberry Pi
License IIoT Libraries SL is a licensed add-on; it runs in demo mode for a limited time without one
Network Outbound TCP 1883 for testing, TCP 8883 for TLS, and DNS configured on the controller
Test tools mosquitto_sub, or any MQTT desktop client

The MQTT Client SL library is part of the IIoT Libraries SL package, alongside JSON and web client libraries. Exact function block pin names can differ slightly between library versions, so keep the library documentation open in the Library Manager while you work.

Step 1: Add the MQTT Library

  1. Open the Library Manager in your application and choose Add Library.
  2. Search for MQTT Client SL and add it. The library's namespace is MQTT.
  3. If you plan to build JSON with library helpers, add JSON Utilities SL as well. This tutorial builds the JSON by hand to keep dependencies minimal.
  4. Build the project once to confirm the library resolves without errors.

Step 2: Declare the Variables

Create a program, for example PRG_Mqtt, called from a task with a cycle of 20 to 100 ms. Network function blocks need to be called every cycle so they can progress their internal state machines.

PROGRAM PRG_Mqtt
VAR
    // Process values (in a real project these come from your control logic)
    rTemperature   : REAL := 21.5;
    rPressure      : REAL := 1.82;
    xPumpRunning   : BOOL := TRUE;

    // MQTT client and publisher
    mqttClient     : MQTT.MQTTClient;
    mqttPublish    : MQTT.MQTTPublish;

    sHost          : STRING := 'broker.connectmq.com';
    uiPort         : UINT := 1883;
    sClientId      : STRING := 'codesys-demo-k8q2x7';   // must be non-empty and unique
    wsTopic        : WSTRING(255) := "connectmq/demo/k8q2x7/plant1/utilities/pumpstation1/telemetry";

    sPayload       : STRING(512);
    tonPublish     : TON;
    xTrigger       : BOOL;
    rLastTemp      : REAL;
    xLastRunning   : BOOL;
END_VAR

Two details matter here. First, the client ID must be non-empty and unique; two controllers sharing one ID will knock each other off the broker repeatedly. Second, the default STRING length in CODESYS is 80 characters, which is too short for most JSON payloads, so declare an explicit length.

Step 3: Connect and Publish with Structured Text

The program enables the client, builds a JSON payload, and publishes either every 10 seconds or immediately when the temperature moves by more than 0.5 degrees or the pump state changes.

// 1. Keep the client running every cycle
mqttClient(
    xEnable      := TRUE,
    sHostname    := sHost,
    uiPort       := uiPort,
    eMQTTVersion := MQTT.MQTT_VERSION.V3_1_1,
    sClientId    := sClientId,
    uiKeepAlive  := 30
);

// 2. Decide when to publish: periodic heartbeat or report by exception
tonPublish(IN := NOT tonPublish.Q, PT := T#10S);
IF tonPublish.Q
   OR ABS(rTemperature - rLastTemp) > 0.5
   OR xPumpRunning <> xLastRunning THEN
    xTrigger := TRUE;
END_IF

// 3. Build the JSON payload
IF xTrigger AND NOT mqttPublish.xBusy THEN
    sPayload := CONCAT('{"temperature":', REAL_TO_STRING(rTemperature));
    sPayload := CONCAT(sPayload, ',"pressure":');
    sPayload := CONCAT(sPayload, REAL_TO_STRING(rPressure));
    sPayload := CONCAT(sPayload, ',"pump_running":');
    IF xPumpRunning THEN
        sPayload := CONCAT(sPayload, 'true}');
    ELSE
        sPayload := CONCAT(sPayload, 'false}');
    END_IF
    rLastTemp := rTemperature;
    xLastRunning := xPumpRunning;
END_IF

// 4. Publish on a rising edge of xExecute
mqttPublish(
    xExecute       := xTrigger AND mqttClient.xConnectedToBroker,
    mqttClient     := mqttClient,
    wsTopicName    := wsTopic,
    pbPayload      := ADR(sPayload),
    udiPayloadSize := TO_UDINT(LEN(sPayload)),
    eQoS           := MQTT.QoS.AtLeastOnce,
    xRetain        := FALSE
);

IF mqttPublish.xDone OR mqttPublish.xError THEN
    xTrigger := FALSE;   // drop xExecute so the next trigger creates a new rising edge
END_IF

The pattern to remember is the execute/done handshake. MQTTPublish starts on a rising edge of xExecute and reports xDone or xError some cycles later. If you never drop xExecute, nothing publishes a second time. If you raise it every cycle, you flood the broker.

Step 4: Verify on the Public Test Broker

Download the application, start it, and subscribe from a PC:

mosquitto_sub -h broker.connectmq.com -p 1883 -i codesys-watch-k8q2x7 \
  -t 'connectmq/demo/k8q2x7/#' -v

You should see a message every 10 seconds, plus extra messages when you write a new temperature or toggle xPumpRunning from the online view:

{"temperature":21.5,"pressure":1.82,"pump_running":true}

The public MQTT test broker is ideal for this bring-up phase: anonymous, no setup, and fast feedback. It is readable by anyone, so use a random topic prefix and no real process data. It also limits each client to 10 messages per second and 64 KB per message, which is a useful guard rail while you tune your triggers.

Step 5: Move to a Private Broker with TLS

For production, connect to your own broker with credentials and encryption:

  1. Create a broker in the ConnectMQ portal and note the generated username, password and client ID.
  2. On the controller, open the Security Screen in CODESYS and import the root CA of the broker's certificate into the trusted certificates store. Brokers with Let's Encrypt certificates chain to ISRG Root X1.
  3. Set uiPort := 8883, enable TLS on the client function block and reference the TLS context as described in the library documentation.
  4. Set sClientId := 'YOUR_CLIENT_ID' and pass YOUR_USERNAME and YOUR_PASSWORD to the client's credential inputs.
  5. Change the topic to your production hierarchy, such as plant1/utilities/pumpstation1/telemetry.

With ConnectMQ, client IDs are bound to the issued credentials, so a copied project on a second controller with the same ID will be refused rather than silently stealing the session. Give each controller its own credentials. The broker's live topic explorer shows your messages the moment the TLS handshake succeeds.

If running and patching a broker yourself is not where you want to spend time, a managed MQTT broker takes certificates, upgrades and monitoring off your plate.

Troubleshooting CODESYS MQTT

  1. Client never connects. Check DNS and the default gateway on the controller. Test with an IP literal to isolate name resolution problems.
  2. TLS handshake fails. The CA certificate is missing from the controller's trusted store, or the controller clock is wrong and the certificate looks not yet valid. Configure NTP.
  3. Publishes only once. xExecute is never reset; see the handshake in step 3.
  4. Payload truncated. The STRING is too short, or udiPayloadSize was computed from a different variable.
  5. Connection drops every few seconds. Another device uses the same client ID, or the task cycle is so slow that keep alive packets are late.
  6. Demo mode stops after a while. The IIoT Libraries SL license is not activated on the target.

Production Checklist

  • Unique client ID and credentials per controller.
  • TLS on port 8883 with a trusted CA and NTP time sync.
  • Payload builder protected against string overflow.
  • Report-by-exception plus a periodic heartbeat.
  • A status topic with Last Will so consumers can tell offline from idle.
  • Topics follow the plant's ISA-95 naming convention.

Beckhoff controllers use a different library for the same job; see Beckhoff TwinCAT MQTT for the comparison, or the Siemens S7 MQTT tutorial for TIA Portal. For the bigger architectural picture, start with the industrial IoT with MQTT guide.

Publish Your CODESYS Data to ConnectMQ

When your controller is ready to leave the test broker, give it a secure MQTT broker in the cloud. Create a free Serverless broker at app.connectmq.com, no credit card needed, and paste the generated credentials into your CODESYS project.

Frequently Asked Questions

Is the CODESYS MQTT library free?

The MQTT Client SL library is part of the IIoT Libraries SL package, which is licensed. It can be tested in demo mode, which stops after a limited runtime until a license is activated.

Does CODESYS MQTT support TLS?

Yes. Import the broker's root CA into the controller's certificate store via the Security Screen, enable TLS on the client and connect to port 8883.

Can CODESYS subscribe to MQTT topics as well?

Yes, the library includes a subscribe function block. Validate every received value carefully before it influences control logic.

Which MQTT version does the CODESYS client use?

The library supports MQTT 3.1.1, and recent versions add MQTT 5; check the documentation of your installed version. Start with 3.1.1 for maximum compatibility.

Related articles

IIoT Edge Gateway: What It Does and How to Choose One

An IIoT edge gateway connects machines that speak Modbus, OPC UA or proprietary protocols to MQTT and the cloud. Learn its core roles, common architectures and how to choose the right one.

7 min read

All articles →

Your private MQTT broker is a few clicks away

Create an account, get your broker credentials and connect your first device — no servers to install, patch or scale.