mqtt
stableEncode and decode MQTT 3.1.1 protocol packets for publish/subscribe messaging, including authentication, will messages, and QoS acknowledgement flows.
use plugin mqtt::{encode_connect, encode_connect_with_auth, encode_connect_with_will, …} Functions (21)
- encode_connect Encode a CONNECT packet
- encode_connect_with_auth Encode CONNECT with username and password
- encode_connect_with_will Encode CONNECT with a last-will message
- encode_publish Encode a PUBLISH packet
- encode_publish_with_options Encode PUBLISH with retain, dup, and packet ID
- encode_subscribe Encode a SUBSCRIBE packet for one topic
- encode_subscribe_multiple Encode SUBSCRIBE for multiple topics
- encode_unsubscribe Encode an UNSUBSCRIBE packet
- encode_disconnect Encode a DISCONNECT packet
- encode_pingreq Encode a PINGREQ packet
- encode_puback Encode a PUBACK acknowledgement
- encode_pubrec Encode a PUBREC (QoS 2 received) packet
- encode_pubrel Encode a PUBREL (QoS 2 release) packet
- encode_pubcomp Encode a PUBCOMP (QoS 2 complete) packet
- decode_connack Decode a CONNACK response packet
- decode_publish Decode a PUBLISH packet
- decode_suback Decode a SUBACK response packet
- decode_packet_type Decode the first byte of any MQTT packet
- packet_type_name Convert packet type integer to name string
- remaining_length_encode Encode an integer as MQTT variable-length field
- remaining_length_decode Decode an MQTT variable-length field from bytes
Overview
mqtt is a dependency-free codec for the MQTT 3.1.1 wire protocol. It does not open sockets or manage a connection — instead, each encode_* function builds the raw bytes of one control packet, and each decode_* function parses incoming bytes back into a table. You drive the actual transport yourself (typically over the net plugin or a raw TCP stream), feeding encoded packets out and handing received bytes to the decoders. This keeps the plugin small and lets you implement exactly the publish/subscribe flow your broker needs.
The mental model is a request/response handshake expressed as byte buffers: send a CONNECT, read a CONNACK; send a SUBSCRIBE, read a SUBACK; send or receive PUBLISH frames, and for QoS 1/2 exchange the matching PUBACK/PUBREC/PUBREL/PUBCOMP acknowledgements. Use decode_packet_type to peek at any inbound frame's first byte and dispatch it to the right decoder. Use it whenever you need an embedded, allocation-light MQTT client without pulling in a full broker library.
Common patterns
Open a session: encode a CONNECT, send it, then decode the broker's CONNACK reply.
use plugin mqtt::{encode_connect, decode_connack}
let connect = encode_connect("device-01", true)
// ... send `connect` over your transport, then read the reply bytes ...
let reply = [0x20, 0x02, 0x00, 0x00]
let ack = decode_connack(reply)
print("accepted={ack["return_code"] == 0}")
Round-trip a message: encode a PUBLISH and decode it back into its fields.
use plugin mqtt::{encode_publish, decode_publish}
let frame = encode_publish("sensors/temp", "23.5", 1)
let msg = decode_publish(frame)
print("{msg["topic"]} = {msg["payload"]} (QoS {msg["qos"]})")
Dispatch any inbound frame by peeking at its type byte before decoding.
use plugin mqtt::{decode_packet_type, decode_publish, decode_suback}
fn handle(bytes) {
let info = decode_packet_type(bytes)
if info["type_name"] == "PUBLISH" {
let m = decode_publish(bytes)
print("message on {m["topic"]}")
} else if info["type_name"] == "SUBACK" {
let s = decode_suback(bytes)
print("subscribed, packet {s["packet_id"]}")
}
}
Encode a CONNECT packet
Encodes a minimal MQTT 3.1.1 CONNECT packet with the given client ID and clean-session flag. Uses a 60-second keep-alive with no username, password, or will.
use plugin mqtt::{encode_connect, decode_connack}
let pkt = encode_connect("my-client-1", true)
print("CONNECT bytes: {pkt}")
Encode CONNECT with username and password
Encodes a CONNECT packet with username and password credentials. Sets the username and password flags in the connect flags byte.
use plugin mqtt::{encode_connect_with_auth}
let pkt = encode_connect_with_auth("device-01", true, 30, "admin", "secret")
print(pkt)
Encode CONNECT with a last-will message
Encodes a CONNECT packet with a last-will-and-testament message, which the broker publishes if the client disconnects unexpectedly.
use plugin mqtt::{encode_connect_with_will}
let pkt = encode_connect_with_will(
"sensor-01", true, 60,
"sensors/sensor-01/status", "offline", 1, true
)
Encode a PUBLISH packet
Encodes a PUBLISH packet with a topic, string payload, and QoS level (0, 1, or 2). For QoS > 0, uses packet ID 1.
use plugin mqtt::{encode_publish, decode_publish}
let pkt = encode_publish("sensors/temperature", "23.5", 0)
let decoded = decode_publish(pkt)
print(decoded["topic"])
print(decoded["payload"])
Encode PUBLISH with retain, dup, and packet ID
Encodes a PUBLISH packet with full control over all MQTT header flags: retain bit, duplicate delivery flag, and explicit packet ID for QoS > 0.
use plugin mqtt::{encode_publish_with_options}
let pkt = encode_publish_with_options("home/lights", "on", 1, true, false, 42)
Set dup to true when re-sending an unacknowledged QoS 1 message with the same packet ID, so the broker knows it may be a duplicate:
use plugin mqtt::{encode_publish_with_options, decode_publish}
let resend = encode_publish_with_options("home/lights", "on", 1, false, true, 42)
let msg = decode_publish(resend)
print("dup={msg["dup"]} packet_id={msg["packet_id"]}")
Encode a SUBSCRIBE packet for one topic
Encodes a SUBSCRIBE packet for a single topic filter with the requested QoS level.
use plugin mqtt::{encode_subscribe, decode_suback}
let pkt = encode_subscribe("sensors/#", 1, 1)
Encode SUBSCRIBE for multiple topics
Encodes a SUBSCRIBE packet for multiple topic filters in a single packet. Each entry in topics is a table with topic and qos fields.
use plugin mqtt::{encode_subscribe_multiple}
let topics = [
#{"topic": "sensors/temp", "qos": 1},
#{"topic": "sensors/humidity", "qos": 0},
#{"topic": "alerts/#", "qos": 2}
]
let pkt = encode_subscribe_multiple(topics, 5)
Encode an UNSUBSCRIBE packet
Encodes an UNSUBSCRIBE packet for one or more topic filters.
use plugin mqtt::{encode_unsubscribe}
let pkt = encode_unsubscribe(["sensors/temp", "sensors/humidity"], 6)
Encode a DISCONNECT packet
Returns the 2-byte DISCONNECT packet (0xE0 0x00). Send this before closing the TCP connection for a clean disconnect.
use plugin mqtt::{encode_disconnect}
let pkt = encode_disconnect()
Encode a PINGREQ packet
Returns the 2-byte PINGREQ packet used to keep the connection alive. The broker responds with PINGRESP.
use plugin mqtt::{encode_pingreq}
let pkt = encode_pingreq()
Encode a PUBACK acknowledgement
Encodes a PUBACK acknowledgement for a QoS 1 PUBLISH. Send this after receiving and processing a QoS 1 message.
use plugin mqtt::{encode_puback}
let ack = encode_puback(42)
Encode a PUBREC (QoS 2 received) packet
Encodes a PUBREC packet, the first step of the QoS 2 acknowledgement flow (received).
use plugin mqtt::{encode_pubrec, encode_pubrel, encode_pubcomp}
let rec = encode_pubrec(10)
let rel = encode_pubrel(10)
let comp = encode_pubcomp(10)
Encode a PUBREL (QoS 2 release) packet
Encodes a PUBREL packet, the second step of the QoS 2 flow (release).
use plugin mqtt::{encode_pubrel}
let pkt = encode_pubrel(10)
Encode a PUBCOMP (QoS 2 complete) packet
Encodes a PUBCOMP packet, the final step of the QoS 2 flow (complete).
use plugin mqtt::{encode_pubcomp}
let pkt = encode_pubcomp(10)
Decode a CONNACK response packet
Decodes a CONNACK response into {session_present, return_code}. A return_code of 0 means the connection was accepted.
use plugin mqtt::{decode_connack}
let connack_bytes = [0x20, 0x02, 0x00, 0x00]
let result = decode_connack(connack_bytes)
print("accepted={result["return_code"] == 0}")
print("session_present={result["session_present"]}")
Decode a PUBLISH packet
Decodes a PUBLISH packet into {topic, payload, qos, retain, dup, packet_id}.
use plugin mqtt::{encode_publish, decode_publish}
let pkt = encode_publish("home/temp", "22.1", 1)
let msg = decode_publish(pkt)
print("{msg["topic"]}: {msg["payload"]} (QoS {msg["qos"]})")
Decode a SUBACK response packet
Decodes a SUBACK response into {packet_id, return_codes} where each return code is the granted QoS level (0, 1, 2) or 0x80 for failure.
use plugin mqtt::{decode_suback}
let suback_bytes = [0x90, 0x03, 0x00, 0x01, 0x01]
let result = decode_suback(suback_bytes)
print("packet_id={result["packet_id"]}")
Pair it with encode_subscribe_multiple to confirm the broker granted a QoS for every topic you asked for:
use plugin mqtt::{encode_subscribe_multiple, decode_suback}
let topics = [
#{"topic": "a/#", "qos": 1},
#{"topic": "b/#", "qos": 2}
]
let sub = encode_subscribe_multiple(topics, 11)
// ... send `sub`, then read the SUBACK reply ...
let granted = decode_suback([0x90, 0x04, 0x00, 0x0B, 0x01, 0x02])
print("granted codes for packet {granted["packet_id"]}")
Decode the first byte of any MQTT packet
Peeks at the first byte of any MQTT packet and returns {type_id, type_name, dup, qos, retain}. Use to dispatch incoming bytes to the correct decoder.
use plugin mqtt::{encode_publish, decode_packet_type}
let pkt = encode_publish("test", "hello", 0)
let info = decode_packet_type(pkt)
print(info["type_name"])
Because it also surfaces the header flags, you can read QoS and retain straight from the type byte without fully decoding the packet:
use plugin mqtt::{encode_publish_with_options, decode_packet_type}
let pkt = encode_publish_with_options("status", "up", 2, true, false, 7)
let info = decode_packet_type(pkt)
print("{info["type_name"]} qos={info["qos"]} retain={info["retain"]}")
Convert packet type integer to name string
Converts a packet type integer (1–14) to its name string such as "CONNECT", "PUBLISH", "SUBACK", etc.
use plugin mqtt::{packet_type_name}
print(packet_type_name(3))
print(packet_type_name(9))
Encode an integer as MQTT variable-length field
Encodes an integer as an MQTT variable-length field (1–4 bytes). Useful when manually constructing raw MQTT frames.
use plugin mqtt::{remaining_length_encode, remaining_length_decode}
let encoded = remaining_length_encode(300)
let decoded = remaining_length_decode(encoded)
print(decoded["length"])
print(decoded["bytes_used"])
Decode an MQTT variable-length field from bytes
Decodes an MQTT variable-length field from a byte sequence, returning {length, bytes_used}.
use plugin mqtt::{remaining_length_decode}
let result = remaining_length_decode([0xC1, 0x02])
print(result["length"])