目前就是在做一个智能家居的项目,里面出现一些列没有接触过的东西,比如本篇MQTT协议讲解,这边也会在STMM32项目的集合里持续更新。

物联网(IoT)发展迅猛,传感器、网关、云平台之间如何高效通信成了核心问题。MQTT(Message Queuing Telemetry Transport)作为一种轻量级的消息传输协议,近年来被广泛应用于智能家居、工业控制、车联网等场景。

一、MQTT 是什么?一句话概括

MQTT 是一种基于发布/订阅(Pub/Sub)模式的轻量级消息协议,设计初衷是为低带宽、不稳定网络环境下的设备通信而生。

不像 HTTP 一问一答,它更像是广播电台:你订阅频道,谁在频道里发布了消息你就能收到,中间由一个叫做 Broker 的中间人来转发消息。

二、MQTT 的三大角色

  1. Broker(消息代理)
    Broker 就是 MQTT 网络的大脑。客户端不互相通信,所有消息都通过 Broker 中转。主流 Broker 有:

Mosquitto(轻量、适合嵌入式开发)

EMQX(高性能、支持百万连接)

HiveMQ、RabbitMQ(企业级)

  1. Publisher(发布者)
    发布消息的人,比如你家的温湿度传感器,每隔 5 秒发布一次环境数据。

  2. 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 的本质,并在项目中顺利落地

文档更新时间: 2025-06-14 14:36   作者:月影鹏鹏
IT运维支持-AIWALY-月影工作室