Skip to content

Publish readings over MQTT

Connect to the Logable broker over TLS with a device token and publish readings on the device's own topic.

MQTT suits gateways and hardware that holds one connection open instead of opening a new request per reading. The payload is the same JSON body the HTTP endpoint takes.

Connect#

Broker connection
SettingValueRequiredDescription
Hostmqtt.logable.appYesThe public broker.
Port8883YesMQTT over TLS. This is the recommended transport.
WebSocketwss://mqtt.logable.app/mqttNoUse this where a firewall blocks port 8883, or from a browser tool.
Username<DEVICE_ID>YesThe device's UUID.
Password<DEVICE_TOKEN>YesThe same token the HTTP endpoint accepts as a bearer credential.
Client IDlogable-<DEVICE_ID>NoRecommended. Any id is accepted, but it must be unique per connection.

Most TLS stacks validate the broker certificate with the roots your operating system already trusts, and need nothing extra. Some gateways ask you to upload a CA file by hand. Give them the ISRG Root X1 certificate from letsencrypt.org. Upload the root, never the server certificate, which rotates.

Publish#

Publish the reading to the device's own topic at QoS 1.

Topic
devices/<DEVICE_ID>/data

The message body is the same JSON the HTTP endpoint takes:

{
  "timestamp": "2026-07-01T10:00:00.000Z",
  "status": "online",
  "data": {
    "weight": 18750.5,
    "status": "filling"
  }
}

Streams publish to streams/<STREAM_ID>/data with a stream token, and their body carries no status field.

A message is at most 1 MB.

What a device is allowed to do#

The broker checks permission on every publish and every subscribe, not only when the connection opens. A device may publish and subscribe only under its own namespace, devices/<its own id>/. It cannot subscribe to another device's data, and a wildcard subscription across devices is refused.

Logable clears the broker's cached decision when a token is rotated or revoked, so the next publish is checked again. That normally happens within a second, and at most within the broker's cache window. Ingest keeps its own check for up to 30 seconds.

Code samples#

Generated from the same registry the platform validates against. Replace the placeholder id and token with the values from the device's Connection tab.

"""
Raw Meal Silo - Logable MQTT Integration (Python)
Device Type: silo
Device ID: <DEVICE_ID>

Broker: MQTT over TLS on port 8883 (Let's Encrypt certificate; standard system CAs validate it). WebSocket: wss://mqtt.logable.app/mqtt
Client ID must be unique per connection - a duplicate ID disconnects the other client.
Access: this device may publish/subscribe only under devices/<DEVICE_ID>/* - everything else is denied.

Installation: pip install paho-mqtt
"""

import paho.mqtt.client as mqtt
import json
from datetime import datetime, timezone
import time

MQTT_HOST = "mqtt.logable.app"
MQTT_PORT = 8883
MQTT_USERNAME = "<DEVICE_ID>"
MQTT_PASSWORD = "<DEVICE_TOKEN>"
MQTT_CLIENT_ID = "logable-<DEVICE_ID>"
MQTT_TOPIC = "devices/<DEVICE_ID>/data"

def on_connect(client, userdata, flags, reason_code, properties):
    if reason_code.is_failure:
        print(f"Connection failed: {reason_code}")
    else:
        print(f"Connected to MQTT broker at {MQTT_HOST}:{MQTT_PORT}")

def send_data(client):
    # The "data" fields shown are this device type's registered metrics.
    # Optionally add your OWN custom fields to "data" (e.g. "totalizer": 1284300.0).
    # Custom keys: start with a letter; letters/digits/underscores; max 64 chars.
    # Up to 20 custom fields; values: number, string (max 256 chars) or boolean.
    # Custom values appear on dashboards via a widget's "Show Custom Data" option.
    payload = {
        "timestamp": datetime.now(timezone.utc).isoformat(),
        "status": "online",
        "data": {
            "weight": 18750.5,
            "status": "filling"
        }
    }
    result = client.publish(MQTT_TOPIC, json.dumps(payload), qos=1)
    if result.rc == mqtt.MQTT_ERR_SUCCESS:
        print(f"Data sent to {MQTT_TOPIC}")

def main():
    client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=MQTT_CLIENT_ID)
    client.on_connect = on_connect
    client.username_pw_set(MQTT_USERNAME, MQTT_PASSWORD)
    # TLS with the default system CA store - validates the broker's
    # Let's Encrypt certificate out of the box.
    client.tls_set()

    try:
        client.connect(MQTT_HOST, MQTT_PORT, keepalive=60)
        client.loop_start()
        time.sleep(1)
        send_data(client)
        time.sleep(1)
        client.loop_stop()
        client.disconnect()
    except Exception as e:
        print(f"Error: {e}")

if __name__ == "__main__":
    main()

Validation and limits#

Everything the HTTP endpoint enforces applies here too, because both transports meet at the same validation step: the payload limits, the custom key rules, and the one hour maximum drift on a supplied timestamp.

The rate limit is the same on both transports: 10 messages per second per device. Over MQTT a message above the limit is dropped without a reply. The device log shows the drop.

The device log#

MQTT has no reply channel, so a device never learns why a message was refused. The device log shows you the refusal instead. Open a device, go to the Connection tab, and the log shows what the device sent, what Logable accepted, what it rejected and why, and what the broker saw when the device connected or dropped.

It shows the wrong topic, invalid JSON, a metric of the wrong type, a payload over the limit, a burst over the rate limit, a token the broker refused, and a publish outside the device namespace. Every row names the fix. See Error codes for the full list.

The log is live. It shows what happens while it is open, plus the one most recent problem, which also appears as a line on the device overview until the device sends an accepted message.

Going offline#

Logable decides a device is offline from its readings, not from the broker connection. A device is marked offline when it stops sending. The wait is five minutes, or three times the device's own reporting interval when that is longer.

Keep publishing on a steady interval even when nothing changes. A silence is how Logable knows something is wrong.

Gateways#

A PLC or a Modbus device does not speak MQTT. A gateway sits between them: it reads the equipment over Modbus RTU or Modbus TCP and republishes each reading on the topic above. Logable sees a normal MQTT device. Every gateway that can publish JSON to a topic with a username and password works, and each piece of equipment behind the gateway gets its own Logable device, its own token and its own topic.

Search the docs

Find a guide, an integration page, or a device type.