STANNUM
Open the simulator

Tutorials / Connectivity

MQTT: readings to the cloud and back

Publish a potentiometer reading to a public broker on the internet every three seconds, subscribe to the same topic, and blink an LED when the message comes back.

Parts in the example:
  • LED
  • Potentiometer
  • Wi-Fi router

What it is

MQTT is the messaging protocol of small connected devices. A device does not talk to another device: it publishes messages on a topic (stannum/room01/sensor) to a broker, a server that forwards them to everyone subscribed to that topic. Tiny messages, one connection kept open, and no web server to write — it is how sensors reach dashboards and phones.

In the simulator

The circuit is the Wi-Fi one plus a potentiometer: the router block gives the ESP32 a network, and through it the real internet. The sketch connects to broker.hivemq.com, a public broker anyone can use, so the bytes really leave the simulation and come back.

Wiring

The circuit below is the example MQTT: send readings to the cloud from the lab — open it with Project → Open example… and it comes ready to run.

The wired circuit, as the lab draws it.
PartPinGoes to
LEDAD2 on the board (GPIO 2)
LEDKa GND symbol
Potentiometer3V3a 3V3 symbol
PotentiometerSD34 on the board (GPIO 34)
PotentiometerGNDa GND symbol

Code

The PubSubClient library is the usual MQTT client for Arduino. Three things every MQTT project has to get right are in the comments of the sketch: the client name must be unique on the broker, mqtt.loop() must be called all the time, and a public topic is public.

sketch.cpp
#include <Arduino.h>
#include <WiFi.h>
#include <PubSubClient.h>

// CHANGE this to a name of your own. This broker is PUBLIC: anyone in the
// world reads what you publish here, and you read what they publish.
const char *BASE = "stannum/room01";

WiFiClient rede;          // the TCP socket
PubSubClient mqtt(rede);  // the MQTT protocol on top of it

// The client name has to be UNIQUE on the broker: two clients with the same
// name knock each other out in an endless loop. With a whole class running
// this same example that is a given, so we draw a suffix at startup.
String nomeCliente = "stannum-" + String(esp_random(), HEX);

const int LED = 2;
const int POT = 34;
int idas = 0;

// Called when a message ARRIVES from a subscribed topic.
void aoChegar(char *topico, byte *carga, unsigned int tam) {
  String msg;
  for (unsigned int i = 0; i < tam; i++) msg += (char)carga[i];
  idas++;
  digitalWrite(LED, idas % 2);       // blinks on every round trip
  Serial.printf("<- came from the broker [%s] %s\n", topico, msg.c_str());
}

void conectarBroker() {
  while (!mqtt.connected()) {
    Serial.print("connecting to the broker as " + nomeCliente + "... ");
    if (mqtt.connect(nomeCliente.c_str())) {
      Serial.println("ok");
      mqtt.subscribe((String(BASE) + "/sensor").c_str());
    } else {
      // negative rc = it never even spoke MQTT (network/DNS); positive = the
      // broker refused it (duplicate name, version, authentication)
      Serial.printf("failed rc=%d, trying again in 3 s\n", mqtt.state());
      delay(3000);
    }
  }
}

void setup() {
  Serial.begin(115200);
  pinMode(LED, OUTPUT);

  WiFi.begin("MyNetwork", "secret123");
  while (WiFi.status() != WL_CONNECTED) delay(200);
  Serial.print("IP: ");
  Serial.println(WiFi.localIP());

  mqtt.setServer("broker.hivemq.com", 1883);
  mqtt.setCallback(aoChegar);
}

unsigned long ultimo = 0;

void loop() {
  conectarBroker();
  mqtt.loop();          // WITHOUT THIS nothing arrives: here the lib reads the socket

  if (millis() - ultimo > 3000) {
    ultimo = millis();
    char valor[12];
    snprintf(valor, sizeof(valor), "%d", analogRead(POT));
    mqtt.publish((String(BASE) + "/sensor").c_str(), valor);
    Serial.printf("-> published %s\n", valor);
  }
  delay(20);
}

setServer names the broker and the port; setCallback registers the function that runs when a message arrives; subscribe asks for the topic. In the loop, every three seconds the potentiometer's reading is published — and since the sketch is subscribed to its own topic, the broker sends it right back. The round trip toggles the LED.

Run it

Press Build and run. The first build of a project takes a while; after that, only what changed is rebuilt.

The simulation running: the canvas reacts and the serial monitor shows what the code prints.

The serial monitor shows the IP address, “connecting to the broker as stannum-… ok”, then pairs of lines: “-> published 2048” and “<- came from the broker [stannum/room01/sensor] 2048”. The LED toggles on every round trip. Drag the potentiometer and the number changes.

How the simulation models it

Try this

  1. Open a web MQTT client (HiveMQ has one on its site) and subscribe to your topic: the readings appear there as the sketch publishes them.
  2. From that client, publish “on” or “off” to a second topic and make the sketch drive the LED from it — the other direction.
  3. Change BASE to a name of your own and publish a JSON string with two readings instead of a bare number.

See also