Subscribing to Topics
How to listen for messages from the platform, other devices, or external systems.
How subscriptions work
Subscriptions in the Minimalist SDK are defined as a null-terminated array of topic strings, passed to mqtt.set_subscriptions() before the connection is established. The SDK subscribes to every topic in the list on first connect — and automatically re-subscribes on every reconnect. You set it up once and never think about it again.
static const char * my_topics[] = {
"~/~/command",
"~/~/config/setpoint",
"~/broadcast/alert",
nullptr // ← must be null-terminated
};
void setup() {
// ... wifi and mqtt setup ...
mqtt.set_subscriptions(my_topics);
mqtt.set_callback(on_message);
}Topic prefixing with ~/ and ~/~/
Subscription topics follow the exact same prefix rules as publish topics. The SDK rewrites a leading ~/ or ~/~/ before it hands the topic to the broker.
"~/~/command"
// subscribes to: larry/a8f3k2m1/command
// (only your device receives this)
"~/~/config/setpoint"
// subscribes to: larry/a8f3k2m1/config/setpoint
"~/fleet/alert"
// subscribes to: larry/fleet/alert
// (any device on your account publishing here is heard)
"larry/fleet/alert"
// subscribes to: larry/fleet/alert
// (same result, but written out verbatim)Use ~/~/ for topics your device alone should receive — commands, config updates, per-device state. Use ~/ for account-wide topics like group broadcasts or shared alerts. Use a verbatim topic when you already have the full string and don't need rewriting.
~/ or ~/~/ is rewritten. A ~ elsewhere in the topic is treated as a literal character.Handling incoming messages
Register a callback function with mqtt.set_callback(). It receives the full topic string and the payload as null-terminated char * strings:
void on_message(char * topic, char * message) {
Serial.print(" topic: "); Serial.println(topic);
Serial.print(" message: "); Serial.println(message);
// example: react to a command
if (strstr(topic, "/command") != NULL) {
if (strcmp(message, "reboot") == 0) {
ESP.restart();
}
}
}
void setup() {
// ...
mqtt.set_callback(on_message);
}topic your callback receives is the full broker topic, including the username and device ID prefix — e.g. larry/a8f3k2m1/command. Keep this in mind when matching topics in your handler.Complete example
Here's a full sketch that subscribes to two topics — one device-specific and one shared — and handles messages from both:
#include <Arduino.h>
#include "credentials.h"
#include "device_id.h"
#include "wifi_tools.h"
#include "mqtt.h"
char DEVICE_ID[9];
void on_message(char * topic, char * message) {
Serial.print(" topic: "); Serial.println(topic);
Serial.print(" message: "); Serial.println(message);
if (strstr(topic, "/command") != NULL) {
if (strcmp(message, "reboot") == 0) {
Serial.println(" rebooting...");
ESP.restart();
}
if (strcmp(message, "identify") == 0) {
// flash an LED, beep, or publish a response
Serial.println(" I'm here!");
}
}
if (strstr(topic, "/alert") != NULL) {
Serial.print(" got shared alert: ");
Serial.println(message);
}
}
static const char * my_topics[] = {
"~/~/command", // → larry/a8f3k2m1/command
"~/fleet/alert", // → larry/fleet/alert
nullptr
};
void setup() {
Serial.begin(115200);
device_id.get_or_set(DEVICE_ID);
wifi_tools.begin(WIFI_SSID, WIFI_PASS);
mqtt.setup(MQTT_HOST, MQTT_PORT, DEVICE_ID, MQTT_USER, MQTT_PASS);
mqtt.set_subscriptions(my_topics);
mqtt.set_callback(on_message);
}
void loop() {
if (wifi_tools.is_connected) {
mqtt.maintain();
} else {
wifi_tools.reconnect();
mqtt.report_disconnect();
}
}