This one is about the wire, not the chip. Nothing below changes with the board you picked, which is why the chip and language switches are not on it. They come back on the ESP32 pages this one sits underneath.
MQTT and a broker
The board does not send a message to your phone. It publishes a name to a broker, and the broker works out who cares — which is why you can add a second sensor, or a dashboard, without changing a line of firmware.
Publish one message and watch who gets a copy. The board is told nothing about any of them.
# takes everything below a level, + takes exactly one level, and the board is told about none of it.The one idea
With HTTP the board
needs an address, a path, and a server that is awake. With MQTT it needs a
broker and a topic — a name like home/kitchen/temp. Everybody connects to
the broker; nobody connects to anybody else.
That single indirection buys three things:
- Publishers don't know their subscribers. Add a dashboard, a logger and a phone. The sensor firmware never changes.
- Nobody has to be awake at the same time. A subscriber that connects an hour later gets the next message — or the last one, with retain.
- One connection carries everything. Handshake once at boot, then send 30-byte messages for a month.
Topics are a path, not a folder
There is nothing to create. The first publish to home/kitchen/temp makes it
exist, and a topic nobody subscribes to costs nothing.
Subscribers use two wildcards:
| Filter | Matches | Does not match |
|---|---|---|
home/kitchen/temp | exactly that | anything else |
home/+/temp | home/kitchen/temp, home/garage/temp | home/kitchen/oven/temp |
home/# | everything under home | office/desk/temp |
+ is exactly one level. # is the rest, and only at the end. The trap in
the middle row is that + never matches nothing — a subscriber to
home/+/temp will not hear home/temp.
Name topics the way you would name folders, most general first:
house/floor/room/device/measurement. You will want to subscribe to a whole
floor eventually, and you cannot if the room is the last level.
Retain: the difference between a number and a dash
A broker forgets a message the moment it has delivered it. Publish with the retain flag and it keeps the last one per topic and hands it to anything that subscribes later. Turn it on in the figure and press a dashboard connects now.
Retain state, not events. home/kitchen/temp — yes, a new dashboard should
know it is 21.4°. home/doorbell/pressed — no, or every dashboard that opens
tomorrow announces yesterday's visitor.
QoS, in one table
| QoS | Promise | Cost | Use it for |
|---|---|---|---|
| 0 | at most once, fire and forget | 1 message | Temperature every 30 s |
| 1 | at least once, may duplicate | 2 messages | A command that matters |
| 2 | exactly once | 4 messages | Almost nothing |
QoS 0 is the right default for sensors: if a reading is lost, another one is
along in thirty seconds. QoS 1 is for the things where losing one is not fine —
turning a heater off. Handle the duplicate rather than reaching for QoS 2; make
the command idempotent (set/heater = off, not toggle/heater).
What the code looks like
client.setServer("192.168.1.10", 1883);
client.setWill("home/kitchen/status", "offline", true, 1); // retained
client.connect("kitchen-esp32", user, pass);
client.publish("home/kitchen/status", "online", true);
client.subscribe("home/kitchen/heater/set", 1);
// then, every 30 seconds:
client.publish("home/kitchen/temp", "21.4"); // QoS 0, not retainedclient.loop() has to run often. It is not decoration: it is what answers the
broker's keepalive pings, and a board that stops answering is dropped in about
ninety seconds — after which your publishes go nowhere and no error says so.
Running the broker
Mosquitto on a Raspberry Pi or any always-on box, one apt install and a
config file. Two settings are worth doing on day one:
- Turn off anonymous access. Default Mosquitto lets anything on the network
publish anything, including to your
heater/settopic. - Keep it off the internet. If you need to reach it from outside, use a VPN or a hosted broker with TLS — not a forwarded port.
When MQTT is not the answer
One board and one server that already speaks HTTP: use HTTP, there is nothing to run. A browser page that needs to feel instant: the browser cannot speak MQTT without extra parts, and WebSocket is the shorter road.
Edit this page — content/esp32/mqtt-and-a-broker.mdx
Discuss this article
Ask about this page. The answer stays here, on the page it belongs to, for whoever hits the same wall next.