Skip to content

RaftMQTTManagerSysMod

Rob Dobson edited this page Oct 27, 2026 · 3 revisions

MQTTManager SysMod

Built-in SysMod (registered as MQTTMan) that connects to an MQTT broker and exposes per-topic Comms Channels. Messages received on inbound (subscribed) topics are handled as REST API commands, like commands arriving over BLE or HTTP; messages sent on an outbound topic's channel are published to the broker.

Source: RaftSysMods/components/MQTTManager/ and the client in RaftCore/components/core/MQTT/

What it provides

  • Single-connection MQTT 3.1.1 client (RaftMQTTClient) over a plain TCP socket, with auto-reconnect, keep-alive and optional username/password.
  • Publishes at QoS 0 or 1 (QoS 2 is sent as QoS 1), with optional retain. QoS 1 publishes are tracked until the broker acknowledges them (PUBACK).
  • Subscribes to inbound topics (filters may use + and #) and passes received messages to the command handler.
  • One comms channel per topic, named after the topic's name.
  • Optional StatePublisher subscriptions per outbound topic (pubSources), so data is published to MQTT without a client having to subscribe.

SysType configuration

"MQTTMan": {
    "enable": 1,
    "brokerHostname": "broker.example.com",
    "brokerPort": 1883,
    "clientID": "",
    "username": "device",
    "password": "secret",
    "keepAliveSecs": 30,
    "topics": [
        {
            "name": "cmdIn",
            "inbound": true,
            "path": "devices/{uid}/cmd",
            "qos": 1
        },
        {
            "name": "dataOut",
            "inbound": false,
            "path": "devices/{uid}/data",
            "qos": 1,
            "retain": false,
            "pubSources": [
                { "pubTopic": "devjson", "rateHz": 1.0, "trigger": "timeorchange", "minMs": 50 }
            ]
        }
    ]
}
Top-level key Type Default Meaning
enable bool false Master switch
brokerHostname string "" MQTT broker hostname (resolved by DNS) or IP address
brokerPort int 1883 Broker port
clientID string "" Prefix of the MQTT client identifier, to which the system unique string is appended. When absent or "" the SystemName is the prefix. (In RaftSysMods 1.29.0 and earlier an absent key used the unique string as the prefix, so it appeared twice.)
username string "" Username sent in CONNECT. Not sent if empty.
password string "" Password sent in CONNECT. Only sent when username is also set.
keepAliveSecs int 30 Keep-alive interval sent to the broker; 0 or values over 65535 use the default. A PINGREQ is sent every keepAliveSecs / 2.
topics array [] Per-topic configuration array
Topic key Type Default Meaning
name string topic<n> (1-based) Name of the topic's comms channel (and the name used internally to refer to the topic)
inbound bool true true: subscribe to path; messages received are handled as commands. false: publish-only.
path string "" MQTT topic. For an inbound topic this is a topic filter and may contain + and #. {uid} is replaced by the system unique string, so devices sharing one config get their own topics. An outbound topic with an empty path can't publish.
qos int 0 QoS for publishes (outbound) or requested in the subscription (inbound). 0 or 1; higher values are treated as 1.
retain bool false Set the retain flag on publishes (outbound only)
pubSources array none Outbound only: StatePublisher subscriptions created at startup for this topic's channel - see below

All channels use the RICJSON codec.

Inbound topics → commands

Each inbound topic gets its own channel. A message received on a subscribed topic is matched against the inbound topics' filters in config order; the first match gets it and it is passed to CommsCore on that topic's channel, where the RICJSON codec treats it as a JSON command frame and runs it through the REST API: {"cmdName":"x","a":1} runs x?a=1.

  • A message received at QoS 1 is acknowledged (PUBACK) to the broker.
  • There is no reply path: the REST response is discarded, and anything sent on an inbound topic's channel is dropped. Results a remote client needs must be published on an outbound topic.
  • An inbound packet longer than 1024 bytes (or malformed) closes the connection, which is then re-established.

Outbound topics and publish acknowledgement

A message sent on an outbound topic's channel is published to the topic's path at its qos and retain.

  • While not connected to the broker the channel reports no connection and messages are discarded.
  • While 8 QoS 1 publishes are awaiting PUBACK, further messages wait in the channel's queue.
  • A QoS 1 publish not acknowledged within 10 s closes the connection. Publishes still unacknowledged when the connection closes (for any reason) are counted as lost; they are not resent.

A SysMod can tell when its QoS 1 messages have reached the broker from the named values below (e.g. wait for pubInFlight to reach 0 and pubAcked to have increased before entering deep sleep).

Publishing data with pubSources

In postSetup(), each entry in an outbound topic's pubSources creates a StatePublisher subscription for that topic's channel (with createSubscription):

Key Default Meaning
pubTopic (required) StatePublisher topic, e.g. devjson
rateHz 1.0 Publish rate
trigger "timeorchange" time, change or timeorchange
minMs 50 Minimum time between messages

These subscriptions are kept while the broker isn't connected (unlike a client's subscription, which StatePublisher removes when its channel has no connection) and publish once it connects - see Subscription Mechanism. (RaftSysMods versions after 1.29.0; earlier, a publish made before the broker connected removed them.)

Connection timing

  • Connection attempts start once the network is up and are retried every 5 s after a failure. While an attempt fails at once for lack of network (no address for the broker yet, or connect() failing immediately with no route) it is retried every 250 ms, so the connection is made as soon as the network comes up (e.g. on wake from deep sleep).
  • The broker hostname is looked up with DNSResolver. The first lookup isn't delayed and a lookup isn't attempted (or counted as failed) until the device has an IP address; after a failed lookup the next is made 5 s later. A resolved address is kept.
  • Timeouts that close the connection: socket connect 5 s, CONNACK 5 s, PINGRESP 10 s, PUBACK 10 s. A CONNACK refusing the connection (e.g. code 4, bad username or password; 5, not authorised) is logged and the connection retried.
  • Inbound topics are subscribed each time the connection is made (clean session).

Status and named values

getStatusJSON() (e.g. sysmodinfo/MQTTMan) returns:

{"conn":1,"inFlight":0,"acked":42,"lost":0,"rx":3}

The same values are available through the named-value mechanism (getNamedValue("MQTTMan", ...)):

Name Status key Meaning
connected conn 1 when connected to the broker, else 0
pubInFlight inFlight QoS 1 messages published and not yet acknowledged
pubAcked acked QoS 1 messages acknowledged by the broker (count since startup)
pubLost lost QoS 1 messages not acknowledged before the connection closed (count since startup)
rxMsgs rx Messages received on inbound topics (count since startup)

REST endpoints exposed

None — MQTTManager is purely a transport.

Related

Clone this wiki locally