目前就是在做一个智能家居的项目,里面出现一些列没有接触过的东西,比如本篇MQTT协议讲解,这边也会在STMM32项目的集合里持续更新。
物联网(IoT)发展迅猛,传感器、网关、云平台之间如何高效通信成了核心问题。MQTT(Message Queuing Telemetry Transport)作为一种轻量级的消息传输协议,近年来被广泛应用于智能家居、工业控制、车联网等场景。
一、MQTT 是什么?一句话概括
MQTT 是一种基于发布/订阅(Pub/Sub)模式的轻量级消息协议,设计初衷是为低带宽、不稳定网络环境下的设备通信而生。
不像 HTTP 一问一答,它更像是广播电台:你订阅频道,谁在频道里发布了消息你就能收到,中间由一个叫做 Broker 的中间人来转发消息。
二、MQTT 的三大角色
- Broker(消息代理)
Broker 就是 MQTT 网络的大脑。客户端不互相通信,所有消息都通过 Broker 中转。主流 Broker 有:
Mosquitto(轻量、适合嵌入式开发)
EMQX(高性能、支持百万连接)
HiveMQ、RabbitMQ(企业级)
Publisher(发布者)
发布消息的人,比如你家的温湿度传感器,每隔 5 秒发布一次环境数据。Subscriber(订阅者)
对某类消息感兴趣的接收者,比如你手机里的 APP 订阅了“家里客厅/温度”,只要 Broker 收到这个主题的消息,就会推送给你。
三、核心机制:主题、QoS 和保留消息
🌱 主题(Topic)
MQTT 的消息没有标题,靠的是主题(Topic)分类。
例如:
home/livingroom/temperature
home/kitchen/humidity主题结构采用“/”分隔的多级形式,支持通配符:
+:单级通配符,如 home/+/temperature 可匹配 home/livingroom/temperature
#:多级通配符,如 home/# 可匹配 home/kitchen/humidity
🔁 服务质量等级(QoS)
消息可靠性有三种级别:
QoS
描述
场景示例
0
至多一次(不保证送达)
传感器高频上报,丢一个无所谓
1
至少一次(可能重复)
命令下发,确保送达
2
仅一次(不重复不丢失)
银行、订单处理等关键业务
大多数场景用 QoS 0 或 1 足矣。
📌 保留消息(Retained Message)
比如你家的空调状态是“开启”,订阅者上线时希望立刻知道当前状态,可以发布一条“保留消息”,Broker 会记住它,并在有人订阅时立刻推送。
四、MQTT 通信流程简图
[Publisher] → (Publish message) → [Broker] → (Distribute) → [Subscribers]
所有的通信都基于 TCP(默认端口 1883),也支持 TLS 安全加密(端口 8883)。
MQTT 报文轻量,一个连接只需少量字节。连接成功后会维持一个持久连接,心跳(Keep Alive)机制保证通信活跃。
五、MQTT 实战:STM32 通过 ESP32 Wi-Fi 模组发布 DHT11 数据到云端
以实际项目说话,下面是一个用 ESP32 采集温湿度,通过 MQTT 上报到服务器的例子。
#include <WiFi.h>
#include <PubSubClient.h>
const char* ssid = "Your_WiFi_SSID";
const char* password = "Your_WiFi_Password";
const char* mqtt_server = "broker.hivemq.com"; // 你可以改为自己的 MQTT broker 地址
const int mqtt_port = 1883;
WiFiClient espClient;
PubSubClient client(espClient);
String inputBuffer = "";
void setup_wifi() {
Serial.println("Connecting to WiFi...");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nWiFi connected, IP: ");
Serial.println(WiFi.localIP());
}
void reconnect() {
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
if (client.connect("ESP32Client_DHT11")) {
Serial.println("connected");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" retrying in 2 seconds");
delay(2000);
}
}
}
void setup() {
Serial.begin(9600); // 串口接收 STM32 数据
delay(1000); // 等待串口稳定
setup_wifi();
client.setServer(mqtt_server, mqtt_port);
}
void loop() {
if (!client.connected()) reconnect();
client.loop();
// 接收 STM32 通过串口发送的数据
while (Serial.available()) {
char c = Serial.read();
if (c == '\n') {
// 收到一整行 JSON 字符串
Serial.print("Received: ");
Serial.println(inputBuffer);
// 发布到 MQTT 主题
if (client.publish("env/office/dht11", inputBuffer.c_str())) {
Serial.println("MQTT published successfully.");
} else {
Serial.println("MQTT publish failed.");
}
inputBuffer = ""; // 清空缓存
} else {
inputBuffer += c;
}
}
}
六、MQTT 开发建议与常见问题
保持 ClientID 唯一,防止连接互踢
使用遗嘱消息(Last Will)监测设备在线状态
利用 TLS 保证安全传输(比如 MQTTS)
合理规划主题命名,避免混乱
常见问题排查
连不上 Broker?确认端口、认证信息、防火墙设置
消息不达?检查主题是否一致,是否订阅了通配符
数据乱码?确认编码格式是否一致(推荐 UTF-8)
七、结语:为什么选择 MQTT?
相比 HTTP:
连接长时间保持,不必频繁重连
消息机制更灵活,低功耗设备友好
更适合物联网中“一对多”或“多对多”的场景
对于 IoT 开发者来说,MQTT 是一把称手的利器,不难学但很强大。希望这篇文章能帮你理解 MQTT 的本质,并在项目中顺利落地