Industrial IoT

Siemens S7 MQTT: Publishing S7-1200 and S7-1500 PLC Data to a Broker

Two proven ways to get data out of an S7-1200 or S7-1500 over MQTT: the PLC-native LMQTT library and an external Python gateway using python-snap7, with TLS, ISA-95 topics and report-by-exception.

Siemens S7-1500 PLC on a DIN rail sending tag values to a cloud broker, illustrating Siemens S7 MQTT connectivity
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

Siemens S7 MQTT integration lets an S7-1200 or S7-1500 publish its process data straight to dashboards, historians and cloud applications without a SCADA server in the middle. In this tutorial you will compare the two practical approaches, the PLC-native LMQTT library and an external gateway, then build a working Python gateway that reads a data block and publishes it to an MQTT broker over TLS. You will finish with a tested topic structure and a checklist for taking it to production.

Two Ways to Do Siemens S7 MQTT

S7 PLCs do not speak MQTT out of the box in the way they speak S7 communication, PROFINET or OPC UA. You have two realistic options.

Option 1: MQTT client inside the PLC. Siemens provides a free library for TIA Portal, usually referred to as LMQTT, that implements an MQTT 3.1.1 client on top of the open user communication blocks (TCON, TSEND, TRCV). The PLC itself opens a TCP or TLS connection to the broker and publishes. Variants of this approach also exist on communication processors and Siemens edge devices.

Option 2: External gateway. A small industrial PC, edge device or container reads tags from the PLC using S7 communication (PUT/GET) or the PLC's OPC UA server, and publishes them to MQTT. The PLC program does not change, or changes very little.

Criterion LMQTT in the PLC External gateway
Extra hardware None Industrial PC, edge device or VM
PLC program changes Yes: FB calls, buffers, JSON building None or minimal
PLC cycle time impact Small but real; string handling is costly None
TLS Supported on recent firmware with certificates in TIA Portal Handled by the gateway OS and library
Payload formatting Built in SCL, limited string tools Any format, easy JSON or Sparkplug
Store-and-forward Limited by PLC memory Disk buffer on the gateway
Who maintains it PLC programmer IT/OT or software team
Best for Few signals, no extra box allowed Many signals, many PLCs, richer logic

If you only need a few dozen values from one PLC and adding hardware is hard, LMQTT is attractive. If you are connecting a line or a plant, the gateway approach scales better and keeps the PLC focused on control. The architecture trade-offs are covered more broadly in PLC to cloud connectivity.

Option 1: The Native LMQTT Library

The workflow in TIA Portal looks like this:

  1. Download the LMQTT library and its documentation from Siemens Industry Online Support and add it to your project as a global library.
  2. Drag the client function block into your program and create an instance data block.
  3. Configure the connection parameters: broker hostname, port, client ID, username and password, keep alive.
  4. For TLS, import the broker's root CA certificate into the global certificate manager in TIA Portal and assign it to the PLC. A broker using a Let's Encrypt certificate needs the ISRG Root X1 certificate. Check the library documentation for minimum CPU firmware versions that support secure open user communication.
  5. Build the payload in SCL as a byte array or string, then trigger a publish on a rising edge with topic, QoS and retain flag.
  6. Monitor the status and error outputs; the block reports connection failures, timeouts and broker rejections.

A few lessons from the field:

  • Build JSON carefully. SCL string concatenation is verbose and easy to get wrong. Keep payloads small and use fixed formats, or publish plain numeric strings on separate topics.
  • Trigger on change, not every cycle. Publishing in every OB1 cycle will flood the broker and the PLC's communication resources. Use a timer or a deadband comparison.
  • Watch the client ID. Two PLCs with the same client ID will disconnect each other in a loop. On a managed broker that binds client IDs to credentials, each PLC needs its own credential set.
  • Use TLS from day one. Retrofitting certificates after commissioning means another download and another outage window.

Option 2: Python Gateway with python-snap7

The gateway approach uses python-snap7 to read a data block over S7 communication and paho-mqtt to publish. It runs on any Linux or Windows machine that can reach the PLC on TCP port 102.

Prepare the PLC in TIA Portal

S7-1200 and S7-1500 CPUs block external S7 reads by default. Make two changes and download:

  1. In the CPU properties, under Protection and Security, enable Permit access with PUT/GET communication from remote partner.
  2. In the properties of the data block you will read, untick Optimized block access so variables have fixed byte offsets.

Then create a data block, for example DB10, with this layout:

Offset Name Type
0.0 Temperature Real
4.0 Pressure Real
8.0 MotorSpeed Int
10.0 Running Bool

PUT/GET is unauthenticated, so only enable it on a segmented network where the gateway is the sole client. If that is not acceptable on your site, read the same data through the S7-1500's OPC UA server instead, as described in the OPC UA to MQTT gateway tutorial.

Install the libraries

python -m venv s7mqtt
source s7mqtt/bin/activate
pip install python-snap7 "paho-mqtt>=2.0"

The gateway script

This script reads DB10 every second, applies a deadband, and publishes only meaningful changes. It also maintains a retained status topic with a Last Will so consumers know when the gateway goes offline.

import json
import time
import uuid
from datetime import datetime, timezone

import snap7
from snap7.util import get_real, get_int, get_bool
import paho.mqtt.client as mqtt

PLC_IP = "192.168.0.10"
RACK, SLOT = 0, 1          # S7-1200 and S7-1500 CPUs use rack 0, slot 1
DB_NUMBER, DB_SIZE = 10, 12

# Test on the public broker first. Use a random prefix: the public area is readable by everyone.
BROKER = "broker.connectmq.com"
PORT = 1883
USE_TLS = False
USERNAME = None            # production: "YOUR_USERNAME"
PASSWORD = None            # production: "YOUR_PASSWORD"
CLIENT_ID = f"s7-gw-{uuid.uuid4().hex[:8]}"   # production: "YOUR_CLIENT_ID"
BASE = f"connectmq/demo/{uuid.uuid4().hex[:6]}/plant1/packaging/line2/filler"

DEADBANDS = {"temperature": 0.2, "pressure": 0.05, "motor_speed": 5}


def read_plc(plc):
    data = plc.db_read(DB_NUMBER, 0, DB_SIZE)
    return {
        "temperature": round(get_real(data, 0), 2),
        "pressure": round(get_real(data, 4), 3),
        "motor_speed": get_int(data, 8),
        "running": get_bool(data, 10, 0),
    }


def changed(name, new, last):
    if name not in last:
        return True
    if isinstance(new, bool):
        return new != last[name]
    return abs(new - last[name]) >= DEADBANDS.get(name, 0)


def on_connect(client, userdata, flags, reason_code, properties):
    print("MQTT connected:", reason_code)
    client.publish(f"{BASE}/status", "online", qos=1, retain=True)


def main():
    mq = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=CLIENT_ID)
    if USERNAME:
        mq.username_pw_set(USERNAME, PASSWORD)
    if USE_TLS:
        mq.tls_set()       # system CA store validates the Let's Encrypt certificate
    mq.will_set(f"{BASE}/status", "offline", qos=1, retain=True)
    mq.on_connect = on_connect
    mq.connect(BROKER, PORT, keepalive=30)
    mq.loop_start()

    plc = snap7.client.Client()
    last = {}
    last_full = 0.0
    print("Publishing under", BASE)

    while True:
        try:
            if not plc.get_connected():
                plc.connect(PLC_IP, RACK, SLOT)
            values = read_plc(plc)
            now = time.time()
            force = now - last_full > 300      # full refresh every 5 minutes
            ts = datetime.now(timezone.utc).isoformat(timespec="seconds")
            for name, value in values.items():
                if force or changed(name, value, last):
                    payload = json.dumps({"value": value, "ts": ts, "quality": "good"})
                    mq.publish(f"{BASE}/{name}", payload, qos=1)
                    last[name] = value
            if force:
                last_full = now
        except Exception as exc:              # PLC unreachable, wrong DB layout, etc.
            print("PLC read failed:", exc)
            mq.publish(f"{BASE}/quality", "bad", qos=1, retain=True)
            try:
                plc.disconnect()
            except Exception:
                pass
            time.sleep(5)
        time.sleep(1)


if __name__ == "__main__":
    main()

Watch the data arrive

Run the script, note the printed prefix and subscribe to it from another terminal:

mosquitto_sub -h broker.connectmq.com -p 1883 -i s7-watch-01 \
  -t 'connectmq/demo/+/plant1/packaging/line2/filler/#' -v

Change a value in the PLC watch table and the matching topic updates within a second. Values that move less than their deadband stay quiet, which is exactly the behavior you want on a busy plant network. The free public MQTT broker is fine for this test, but never send real production data there.

Moving to a Private Broker with TLS

For production, create a private broker and switch three settings: PORT = 8883, USE_TLS = True, and the username, password and client ID issued in the portal. Because ConnectMQ uses a Let's Encrypt certificate, tls_set() with the system CA store validates it without shipping a custom CA file. Drop the connectmq/demo/... prefix and use a clean ISA-95 path such as plant1/packaging/line2/filler/temperature; the ConnectMQ portal recognizes ISA-95 style topics and shows devices organized by enterprise, site, area and line.

If you are deciding between running your own broker next to the PLCs and using a hosted MQTT broker, consider who will patch it, renew certificates and watch connection limits at 3 a.m.

Production Checklist

  1. One credential set and one unique client ID per PLC or gateway.
  2. TLS on port 8883; no plain TCP outside the plant network.
  3. PUT/GET enabled only on a segmented network, or use OPC UA instead.
  4. Deadbands sized per signal with a periodic full refresh.
  5. Retained status topic with a Last Will for online and offline state.
  6. QoS 1 for measurements; QoS 0 only for high-rate data you can afford to lose.
  7. Gateway runs as a service with automatic restart and logging.
  8. Topic names follow an agreed ISA-95 hierarchy across all lines.

Troubleshooting Siemens S7 MQTT Connections

  • snap7 error "CLI : function refused by CPU". PUT/GET is not enabled, or the CPU has not been downloaded since you changed it.
  • "Address out of range". The DB is smaller than the bytes requested, or it is still optimized. Check the offsets column in TIA Portal.
  • Values look like garbage. Offsets are wrong. Remember Real is 4 bytes and Int is 2, and Bool packs into bits.
  • MQTT reconnect loop. Duplicate client ID, wrong credentials, or the gateway connects with TLS to port 1883.
  • LMQTT stuck in connecting. DNS is not configured on the CPU, or the CA certificate is missing from the PLC's certificate store.

For the rest of the industrial picture, including Sparkplug B, edge gateways and namespace design, read the industrial IoT with MQTT guide. Running Rockwell hardware too? The Allen-Bradley MQTT tutorial follows the same pattern with EtherNet/IP.

Connect Your Siemens PLCs to ConnectMQ

Your S7 gateway needs a secure MQTT broker in the cloud to publish into. Create a free Serverless broker at app.connectmq.com, no credit card required, copy the generated credentials into the script, and watch your PLC tags appear in the live topic explorer.

Frequently Asked Questions

Can an S7-1200 publish MQTT directly?

Yes. Using the Siemens LMQTT library, an S7-1200 or S7-1500 can act as an MQTT client. Check the library documentation for supported firmware versions, especially if you need TLS.

Does Siemens S7 MQTT support MQTT 5?

The PLC-native library implements MQTT 3.1.1. If you need MQTT 5 features such as message expiry, use an external gateway with a library like paho-mqtt.

Is PUT/GET access safe to enable?

PUT/GET has no authentication, so only enable it on a segmented network where the gateway is the only client. The PLC's OPC UA server with user authentication is the safer alternative on S7-1500.

Which QoS should PLC data use?

QoS 1 is a good default for measurements and status. Use retained messages for state topics so new subscribers immediately receive the current value.

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.