Wio Terminal 夜灯上云实战:通过 MQTT 向 Broker 发布 JSON 遥测数据(IoT-For-Beginners 第 4 课)
【免费下载链接】IoT-For-Beginners12 Weeks, 24 Lessons, IoT for All!项目地址: https://gitcode.com/GitHub_Trending/io/IoT-For-Beginners
本篇技术指南聚焦于 IoT-For-Beginners 课程第 4 课「将设备连接到互联网」中 Wio Terminal 一节的遥测发布环节:在前一课完成 WiFi 与 MQTT 连接的基础上,为夜灯项目引入 ArduinoJson 库、定义遥测主题,并在loop中把光敏传感器读取到的光照强度序列化为 JSON 消息,发布到test.mosquitto.org公共 MQTT Broker。读完本文,你将掌握 Arduino 环境下 MQTT 遥测发布的完整链路——从platformio.ini依赖管理、config.h主题常量定义,到main.cpp中analogRead、DynamicJsonDocument与client.publish的组合用法,并能在串口监视器中验证{"light":652}形式的遥测输出。
本环节的定位:从「连接上」到「发数据」
在 IoT-For-Beginners 的 第 4 课总览 中,遥测(Telemetry)被定义为「从传感器采集数据并发送到云端」的过程。整节课围绕一个远程可控的夜灯展开,整体分四个环节:
- 连接 MQTT Broker(对应 wio-terminal-mqtt.md);
- 发布遥测数据(本文主题);
- 服务端接收遥测并回发命令;
- 设备接收命令并控制 LED。
本文对应的是第 2 环节:设备把光敏传感器(WIO Terminal 板载WIO_LIGHT引脚)读取到的光照强度,通过 MQTT 发布到一个以ID + "/telemetry"命名的主题上。这里的ID是你为设备指定的唯一标识,用于确保在公共 Broker(test.mosquitto.org)上不会与其他学习者或设备的主题/客户端名冲突。该环节的完整可运行代码存放在仓库 code-telemetry/wio-terminal 目录下。
💡 公共测试 Broker
test.mosquitto.org无需注册账号即可使用,但它公开且不安全——任何人都有可能监听到你发布的消息,因此绝不能用它传输需要保密的私有数据。
安装 ArduinoJson 库:在 platformio.ini 中声明依赖
通过 MQTT 发送消息的常用方式之一是使用 JSON 编码。Arduino 生态中有专门的 JSON 库(本课程使用 ArduinoJson),它封装了 JSON 文档的读取与写入,让开发者不必手工拼接字符串。
操作步骤
- 在 VS Code 中打开夜灯项目(
nightlight); - 在
platformio.ini文件的lib_deps列表中追加一行:
bblanchon/ArduinoJson @ 6.17.3该声明即引入 ArduinoJson 库(作者 bblanchon,版本锁定为 6.17.3)。@ 版本号语法用于锁定具体版本,PlatformIO 在下次构建项目时会自动下载对应源码并编译进你的工程。
仓库中的完整依赖清单
在仓库的 code-telemetry/wio-terminal/nightlight/platformio.ini 中,[env:seeed_wio_terminal]环境的完整lib_deps如下:
[env:seeed_wio_terminal] platform = atmelsam board = seeed_wio_terminal framework = arduino lib_deps = knolleary/PubSubClient @ 2.8 seeed-studio/Seeed Arduino rpcWiFi @ 1.0.5 seeed-studio/Seeed Arduino FS @ 2.1.1 seeed-studio/Seeed Arduino SFUD @ 2.0.2 seeed-studio/Seeed Arduino rpcUnified @ 2.1.3 seeed-studio/Seeed_Arduino_mbedtls @ 3.0.1 bblanchon/ArduinoJson @ 6.17.3可以看出,本环节新增的只有最后一行bblanchon/ArduinoJson @ 6.17.3,其余五条分别来自前一环节(连接 MQTT 时)引入的 Seeed WiFi 库与 PubSubClient。各依赖的作用如下:
knolleary/PubSubClient @ 2.8:Arduino 平台的 MQTT 客户端库;seeed-studio/Seeed Arduino rpcWiFi @ 1.0.5:Wio Terminal 板载 WiFi 芯片的通信驱动(硬件相关,仅适用于 Seeed 硬件);Seeed Arduino FS、SFUD、rpcUnified、mbedtls:WiFi 库运行所需的底层支持库;bblanchon/ArduinoJson @ 6.17.3:本环节新增的 JSON 读写库。
💁 如果你去掉
@ 版本号,PlatformIO 将始终拉取最新版本;但最新版本不保证与本节代码兼容——仓库中这些代码是经指定版本测试通过的。
定义遥测主题:在 config.h 中声明常量
设备需要知道把遥测发布到哪个 MQTT 主题。这一步通过修改config.h完成:在文件末尾追加一行常量定义:
const string CLIENT_TELEMETRY_TOPIC = ID + "/telemetry";仓库中完整的 config.h 内容为:
#pragma once #include <string> using namespace std; // WiFi credentials const char *SSID = "<SSID>"; const char *PASSWORD = "<PASSWORD>"; // MQTT settings const string ID = "<ID>"; const string BROKER = "test.mosquitto.org"; const string CLIENT_NAME = ID + "nightlight_client"; const string CLIENT_TELEMETRY_TOPIC = ID + "/telemetry";要点说明:
CLIENT_TELEMETRY_TOPIC是设备发布光照强度所用的主题名,由唯一标识ID拼接"/telemetry"生成。例如ID = "abc123"时,主题为abc123/telemetry;- 使用
ID前缀可以避免在公共 Broker 上与其他设备或同学的项目相互串扰——主题和客户端名(CLIENT_NAME = ID + "nightlight_client")都需要唯一; - 回顾前一环节可知,wio-terminal-mqtt.md 中创建
config.h时已经定义了SSID、PASSWORD(WiFi 凭据)以及ID、BROKER、CLIENT_NAME(MQTT 连接信息)。本环节只新增CLIENT_TELEMETRY_TOPIC一行; BROKER固定为test.mosquitto.org,MQTT 默认端口为 1883(见下文client.setServer(BROKER.c_str(), 1883))。
⚠️ 别忘了把
<SSID>、<PASSWORD>、<ID>替换为你自己的值:SSID 与密码来自你的 WiFi,ID可以是 GUIDGen 这类工具生成的随机串。这个ID在后续编写服务端代码时还要复用,必须保持一致。
发布遥测:在 loop 中读取光照并序列化 JSON
打开main.cpp,先在其文件顶部添加#include指令:
#include <ArduinoJSON.h>然后,在loop函数内、delay调用之前插入如下代码:
int light = analogRead(WIO_LIGHT); DynamicJsonDocument doc(1024); doc["light"] = light; string telemetry; serializeJson(doc, telemetry); Serial.print("Sending telemetry "); Serial.println(telemetry.c_str()); client.publish(CLIENT_TELEMETRY_TOPIC.c_str(), telemetry.c_str());这段代码完成了四件事:
- 读取传感器:
analogRead(WIO_LIGHT)从 Wio Terminal 板载光敏传感器引脚读取 0~1023 的模拟量,即当前光照强度; - 构造 JSON 文档:
DynamicJsonDocument doc(1024)在堆上分配一块 1024 字节的缓冲区(足以容纳本场景的小型文档),doc["light"] = light把光照值写入light键; - 序列化:
serializeJson(doc, telemetry)将 JSON 文档输出到string变量,例如{"light":652}; - 发布与调试输出:
Serial.println在串口打印遥测内容便于观察,client.publish(CLIENT_TELEMETRY_TOPIC.c_str(), telemetry.c_str())通过 PubSubClient 把消息发布到之前定义的主题。
发布效果验证
将代码上传到 Wio Terminal 后,打开串口监视器即可看到遥测数据持续发送到 MQTT Broker:
Connecting to WiFi.. Connected! Attempting MQTT connection...connected Sending telemetry {"light":652} Sending telemetry {"light":612} Sending telemetry {"light":583}这段输出展示了完整的启动链路:先连 WiFi,再连 MQTT,随后每 2 秒发布一条遥测。用手遮挡光敏传感器(或用手指改变进光量),light数值会随之变化。
源码全景:从连接管理到遥测发布的完整闭环
仓库 code-telemetry/wio-terminal/nightlight/src/main.cpp 提供了本环节的完整实现。除上文新增的发布代码外,它还包含前一环节搭建的连接管理函数,共同构成一个可独立运行的遥测发布程序:
#include <Arduino.h> #include <ArduinoJSON.h> #include <PubSubClient.h> #include <rpcWiFi.h> #include <SPI.h> #include "config.h" void connectWiFi() { while (WiFi.status() != WL_CONNECTED) { Serial.println("Connecting to WiFi.."); WiFi.begin(SSID, PASSWORD); delay(500); } Serial.println("Connected!"); } WiFiClient wioClient; PubSubClient client(wioClient); void reconnectMQTTClient() { while (!client.connected()) { Serial.print("Attempting MQTT connection..."); if (client.connect(CLIENT_NAME.c_str())) { Serial.println("connected"); } else { Serial.print("Retying in 5 seconds - failed, rc="); Serial.println(client.state()); delay(5000); } } } void createMQTTClient() { client.setServer(BROKER.c_str(), 1883); reconnectMQTTClient(); } void setup() { Serial.begin(9600); while (!Serial) ; // Wait for Serial to be ready delay(1000); pinMode(WIO_LIGHT, INPUT); pinMode(D0, OUTPUT); connectWiFi(); createMQTTClient(); } void loop() { reconnectMQTTClient(); client.loop(); int light = analogRead(WIO_LIGHT); DynamicJsonDocument doc(1024); doc["light"] = light; string telemetry; serializeJson(doc, telemetry); Serial.print("Sending telemetry "); Serial.println(telemetry.c_str()); client.publish(CLIENT_TELEMETRY_TOPIC.c_str(), telemetry.c_str()); delay(2000); }从源码结构看,整个程序遵循「连接管理 + 主循环发布」的典型嵌入式 MQTT 模式:
connectWiFi():循环重试直到 WiFi 连接成功,每次尝试间隔 500ms;WiFiClient wioClient; PubSubClient client(wioClient);:先用 Wio Terminal WiFi 库创建 TCP 客户端,再以此构造 MQTT 客户端;reconnectMQTTClient():检查并维持 MQTT 连接。连接失败时打印返回码client.state()并等待 5 秒重试。它同时被createMQTTClient()与loop()调用,因为 MQTT 连接很容易断开,需要周期性检查重连;createMQTTClient():client.setServer(BROKER.c_str(), 1883)指定 Broker 地址与端口,随后立即尝试连接;setup():串口初始化、配置WIO_LIGHT为输入、D0为输出(后者供后续环节控制 LED),再依次执行connectWiFi()与createMQTTClient();loop():先重连并调用client.loop()处理网络上的待收消息——这是单线程程序,必须把主线程时间分配给 MQTT 消息处理;随后读取光照、构造 JSON、序列化、发布;最后的delay(2000)把发送间隔控制在 2 秒,既避免过于频繁地发送(省电、省带宽),也能及时反映光照变化。
遥测频率与断连:工程上必须考虑的两个问题
发布遥测「能跑」只是第一步,实际 IoT 工程还要回答两个问题(详见 第 4 课 README 的「Telemetrie」小节):
多久发一次?答案取决于场景。测得太频繁会浪费电量、占用带宽并推高云端处理存储成本;测得太少又无法及时响应变化。温度类慢变信号(如恒温器)每隔几分钟测一次即可;而工厂里价值高昂、故障代价巨大的设备,可能需要每秒多次采样。本节夜灯采用 2 秒间隔,是功耗与实时性的折中。
断了怎么办?公共 WiFi 与 MQTT 连接并不总是稳定。恒温器这类设备可以接受丢失旧读数——系统只关心当前温度;而用于趋势分析与异常检测(如预测性维护)的场景,则希望在恢复连接后补发断网期间产生的所有遥测。此外,设备还应具备断连时本地兜底的能力(例如恒温器离线时仍能按有限规则控制加热)。本文的reconnectMQTTClient()在loop中反复调用,正是为了在断连时尽快恢复连接。
下一步:接收命令与对照参考
发布遥测只是远程夜灯的一半。服务端(Python + Paho-MQTT)订阅ID + "/telemetry"主题接收消息后,会依据光照阈值(如light < 300)向ID + "/commands"主题回发{"led_on": true/false}命令,设备再订阅该主题控制 LED——这是 wio-terminal-commands.md 的后续环节。服务端示例代码可参考仓库的 code-server/server 与 code-commands/server 目录。
如果你使用的是 Raspberry Pi 或虚拟 IoT 设备(而非 Wio Terminal),同一环节的对照实现见 single-board-computer-telemetry.md。
关键文件索引
| 文件 | 作用 |
|---|---|
| code-telemetry/wio-terminal/nightlight/src/main.cpp | 遥测发布完整实现(连接管理 + JSON 发布) |
| code-telemetry/wio-terminal/nightlight/src/config.h | WiFi 凭据、MQTT 连接信息与遥测主题常量 |
| code-telemetry/wio-terminal/nightlight/platformio.ini | PlatformIO 工程配置与全部库依赖 |
| wio-terminal-mqtt.md | 前一环节:WiFi 与 MQTT 连接建立 |
| README.md | 第 4 课总览:MQTT、遥测、命令与断连设计 |
【免费下载链接】IoT-For-Beginners12 Weeks, 24 Lessons, IoT for All!项目地址: https://gitcode.com/GitHub_Trending/io/IoT-For-Beginners
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考