📡 MQTT 入门与实战:从协议原理到两块 WB2 对联
两块 Ai-WB2 开发板 · 一个 MQTT Broker · 板 A 发、板 B 收、收到就闪灯
Ai-WB2 MQTT 3.1.1 RISC-V FreeRTOS
📖 一、什么是 MQTT
一句话定义
MQTT(Message Queuing Telemetry Transport)是一种基于发布/订阅模型的极轻量级消息协议,专为低带宽、高延迟、不可靠网络下的物联网设备而设计。
1999 年诞生 IBM 发明 最初用于石油管道监控 如今是 IoT 事实标准
它解决什么问题
假如你有 1000 个温度传感器分布在一个城市里。如果用 HTTP:
每个传感器每 5 秒问一次服务器:"有指令吗?"
服务器 99% 的时间回答:"没有。"
浪费带宽、浪费电量、响应还慢。
这叫 轮询(Pull)。MQTT 反过来——推送(Push):
传感器连上 Broker,安静等着。
控制台发出"全部上报" → Broker 瞬间推给 1000 个传感器。
省电、省带宽、实时。
HTTP vs MQTT
| 维度 |
HTTP |
MQTT |
| 通信模型 |
请求/响应(客户端拉) |
发布/订阅(服务器推) |
| 连接方式 |
短连接,每次握手 |
TCP 长连接,一次复用 |
| 最小报文 |
几百字节 |
仅 2 字节 |
| 消息方向 |
单向 |
双向 |
| 功耗 |
每次完整 TCP 握手 |
维持心跳即可 |
| 适用场景 |
Web、REST API |
IoT、智能家居、车联网 |
🧱 二、MQTT 架构:三个角色
MQTT 的世界只有三种角色。理解它们就理解了 MQTT:
graph LR
A[📢 Publisher · 发布者] -->|"PUBLISH /home/temp"| B[🏢 Broker · 消息代理]
B -->|FORWARD| C[📥 Subscriber A · 手机App]
B -->|FORWARD| D[📥 Subscriber B · 监控大屏]
| 角色 |
英文 |
职责 |
打个比方 |
| 🏢代理 |
Broker |
接收所有消息、按主题路由、转发给订阅者 |
快递中转站 |
| 📢发布者 |
Publisher |
往指定 Topic 发消息,不知道谁在收 |
寄件人 |
| 📥订阅者 |
Subscriber |
订阅感兴趣的 Topic,有新消息就收到 |
收件人 |
🎯 核心设计哲学
Publisher 和 Subscriber 完全解耦。双方只和 Broker 对话。
你可以随时增删设备,系统不受任何影响。
🏷️ 三、Topic:消息的门牌号
Topic 是一个 UTF-8 字符串,用 / 分层,和文件路径一样。每条消息必须带一个 Topic,Broker 据此决定转发给谁。
✅ 推荐 vs ❌ 不推荐
| ✅ 好的 Topic |
❌ 差的 Topic |
原因 |
home/bedroom/temp |
/temp |
不要 / 开头 |
WB2 |
temp001 |
层级化便于扩展 |
building/3F/light |
builDing_3F_light_Data |
简短清晰 |
🌟 通配符:一次订阅一类消息
| 符号 |
作用 |
匹配范围 |
举例 |
+ |
通配一层 |
只替代一个层级 |
home/+/temp → home/bedroom/temp |
# |
通配所有后续层 |
从当前位置往后全部 |
home/# → home 下一切 |
⚠️ # 必须是最后一个字符。home/#/temp 非法。
🛡️ 四、QoS:消息可靠性三档
不是越高越好,是越合适越好。
0️⃣ QoS 0 · 最多一次
发完就忘。不等确认。丢了就丢了。
温湿度定时上报,丢几条不影响大局。
1️⃣ QoS 1 · 至少一次 ⭐ 最常用
发出 → 等对方回 PUBACK 确认。没收到确认就重发。
保证不丢,但可能重复。开关灯、开门锁。
2️⃣ QoS 2 · 仅一次
PUBLISH → PUBREC → PUBREL → PUBCOMP。四步握手。
不丢不重。支付扣款,多扣一次就破产了。
| QoS |
保证 |
开销 |
典型场景 |
| 0 |
不保证 |
最低 |
传感器定时上报 |
| 1 |
不丢,可能重复 |
中等 |
指令下发、开关控制 |
| 2 |
不丢不重 |
最高 |
支付、计费 |
🎯 实战铁律:99% 场景 QoS 0 或 1。你的项目,QoS 1 够用。
📚 五、其他重要概念
| 概念 |
一句话解释 |
典型用法 |
| ❤️Keep Alive |
定期心跳。超时没心跳,Broker 判你离线 |
每 60 秒自动 PINGREQ/PINGRESP |
| 💀Last Will |
设备非正常断线时,Broker 代发的一条消息 |
连上后发 online,遗嘱设 offline |
| 🧹Clean Session |
true=断线全忘,false=记住订阅和未收消息 |
电池设备用 true,可靠设备用 false |
| 📌Retained |
Broker 保留指定 Topic 的最后一条消息 |
新订阅者一上来就能收到当前温度 |
🔬 六、实战:两块 WB2 对联
理论知识讲完。下面用两块 Ai-WB2 开发板验证一切。
硬件准备
- 🔵 Ai-WB2 开发板 (BL602 RISC-V) × 2
- 🔌 USB Type-C 数据线× 2
- 📶 可上网的 Wi-Fi

目标架构
graph TD
B[🏢 Broker · mqtt.xemowo.top]
A[🔵 板 A · Publisher] -->|"PUBLISH /WB2 每5秒一条"| B
B -->|"FORWARD /WB2"| C[🟢 板 B · Subscriber]
C -->|收到消息| D[💡 RGB 闪绿 100ms]
消息流程序列
sequenceDiagram
participant A as 🔵 板 A (发布者)
participant B as 📡 Broker
participant C as 🟢 板 B (订阅者)
A->>B: CONNECT
A->>B: SUBSCRIBE /WB2
C->>B: CONNECT
C->>B: SUBSCRIBE /WB2
Note over A,C: 两边就绪
loop 每 5 秒
A->>B: PUBLISH /WB2 "TEST1"
B-->>A: PUBACK
B->>C: FORWARD "TEST1"
Note over C: 💡 闪绿 100ms → 熄
end
🔵 板 A · 定时发布者
static int g_count = 0;
/* FreeRTOS 定时器:每 5 秒触发 */
static void pub_cb(TimerHandle_t x)
{
char msg[32];
snprintf(msg, sizeof(msg), "TEST%d", ++g_count);
axk_mqtt_client_publish(g_client, "WB2", msg, 0, 1, 0);
printf("📤 [A] → %s\r\n", msg);
}
/* Broker 连上 → 订阅 → 启动定时器 */
static axk_err_t on_mqtt(axk_mqtt_event_handle_t e)
{
if (e->event_id == MQTT_EVENT_CONNECTED)
axk_mqtt_client_subscribe(e->client, "WB2", 0);
if (e->event_id == MQTT_EVENT_SUBSCRIBED) {
TimerHandle_t t = xTimerCreate("pub",
pdMS_TO_TICKS(5000), pdTRUE, NULL, pub_cb);
xTimerStart(t, 0);
printf("✅ [A] 开始定时发布\r\n");
}
return AXK_OK;
}
上电 → WiFi → Broker → 订阅 WB2 → 每 5 秒发 TEST1 TEST2 TEST3 …
🟢 板 B · 订阅者 + RGB 反馈
static TimerHandle_t g_led_timer; /* 100ms 后自动关灯 */
static void led_off(TimerHandle_t x) {
ws2812_set_pixel_color(0, 0, 0, 0);
ws2812_show_leds();
}
static axk_err_t on_mqtt(axk_mqtt_event_handle_t e)
{
if (e->event_id == MQTT_EVENT_CONNECTED)
axk_mqtt_client_subscribe(e->client, "WB2", 0);
if (e->event_id == MQTT_EVENT_DATA) {
printf("📥 [B] ← %.*s\r\n", e->data_len, e->data);
ws2812_set_pixel_color(0, 0x00, 0xFF, 0x00); /* 绿 */
ws2812_show_leds();
xTimerStart(g_led_timer, 0); /* 100ms 熄 */
}
return AXK_OK;
}
上电 → WiFi → Broker → 订阅 WB2 → 安静等 → 收到 → 💡 闪 → 继续等
烧录 & 运行
cd applications/xemowo/XEMOWO_TEST1
export BL60X_SDK_PATH=~/Ai-Thinker-WB2
make -j8 # 编译
make flash p=/dev/ttyUSB0 b=921600 # 烧板 A
make flash p=/dev/ttyUSB1 b=921600 # 烧板 B
运行效果
两块板各自的串口输出(115200 波特率):
| 时间 |
🔵 板 A 串口 |
🟢 板 B 串口 |
板 B LED |
| +5s |
📤 → TEST1 |
📥 ← TEST1 |
💡 |
| +10s |
📤 → TEST2 |
📥 ← TEST2 |
💡 |
| +15s |
📤 → TEST3 |
📥 ← TEST3 |
💡 |
| +20s |
📤 → TEST4 |
📥 ← TEST4 |
💡 |

🎉 一条 publish 调用,穿越房间,变成另一块板上的物理绿光。
PC 端验证
也可以用电脑上的 MQTT 客户端和板子互动:
| 方向 |
截图 |
💻 电脑发消息到 /WB2 |
 |
| 📡 板子收到电脑发来的消息 |
 |
✅ 七、知识清单
🚀 八、下一步
| 方向 |
怎么做 |
效果 |
| 🔒 TLS 加密 |
mqtt:// → mqtts:// |
数据不再明文 |
| 📊 JSON 载荷 |
Payload 改 {"temp":25.5} |
结构化数据 |
| 🔄 双向通信 |
B 收到后回一条给 A |
形成闭环 |
| 💀 遗嘱消息 |
断线时 Broker 自动通知 |
全网感知设备状态 |
| 📱 手机接入 |
MQTTX App 连同一 Broker |
手机和板子聊天 |
| ☁️ 云平台 |
对接阿里云 IoT / AWS IoT Core |
数据实时可视化 |
"A single protocol, from the sensor on the wall to the dashboard in the cloud."
— Andy Stanford-Clark, MQTT 发明人
Ai-WB2 (BL602 RISC-V) · Broker: mqtt.xemowo.top · 代码: applications/xemowo/XEMOWO_TEST1/