ESP32 温湿度采集上云实战:DHT11驱动、MQTT协议与断线重连机制完整实现

ESP32 温湿度采集上云实战:DHT11驱动、MQTT协议与断线重连机制完整实现
ESP32 温湿度采集上云实战:DHT11驱动、MQTT协议与断线重连机制完整实现
一、问题背景与写作目标
1.1 为什么要做这个项目
很多嵌入式入门项目停留在点亮 LED、读取传感器、串口打印数据这几个动作上。这样的练习可以帮助理解基础语法和硬件接口,但离真实项目还有一段距离。实际现场更关注的是设备能不能持续运行,断网后能不能恢复,数据格式是否便于平台解析,出现异常时能不能快速定位问题。
本篇文章基于 ESP32、DHT11 和 MQTT 做一个温湿度采集上云终端。重点不是简单读取一次温湿度,而是把采集、联网、协议封装、数据发布、状态监测和异常恢复串成一条完整链路。
1.2 从普通 Demo 到 IoT 工程链路
这个项目适合初学者从普通 Demo 过渡到工程化思维。DHT11 负责采集环境温湿度,ESP32 负责读取和处理数据,WiFi 负责联网,MQTT Broker 负责消息中转,电脑端客户端负责订阅和验证数据。

放在开篇的位置,是为了先把项目边界讲清楚。真正有价值的不是某一行读取传感器的代码,而是 DHT11 到 ESP32,再到 MQTT Broker 和云端可视化这一整条链路。后面所有代码和排查方法,都是围绕这条链路展开。
最终要实现的能力包括:
| 能力 | 说明 |
|---|---|
| 传感器采集 | 使用 DHT11 读取温度和湿度 |
| 网络连接 | 使用 ESP32 接入 2.4GHz WiFi |
| 数据上报 | 使用 MQTT 周期性发布数据 |
| 数据格式 | 使用 JSON 封装设备编号、温度、湿度、信号强度和运行时间 |
| 状态监测 | 使用 status Topic 判断设备在线状态 |
| 异常恢复 | 对 WiFi 和 MQTT 分层重连 |
| 调试排查 | 通过串口日志定位网络、协议和传感器问题 |
原理说明:嵌入式联网项目不能只验证“能不能跑”,还要验证“异常后能不能恢复”。这就是普通示例代码和工程化代码的主要区别。
二、项目整体架构
2.1 数据流设计
本项目的数据流可以拆成五个动作:采集、处理、联网、发布、订阅。DHT11 输出温湿度数据,ESP32 读取后进行简单校验和格式化,然后通过 WiFi 连接局域网,再由 MQTT 客户端发布到指定 Topic,最后电脑端通过 MQTTX 或 MQTT Explorer 订阅查看数据。
这里要注意一个判断:WiFi 和 MQTT 不是一回事。WiFi 连接正常,只说明设备进入了局域网;MQTT 连接正常,才说明设备和消息服务器之间建立了发布通道。很多排查误区就出在把这两层混在一起。
2.2 运行时交互流程
设备启动后,先连接 WiFi,再连接 MQTT Broker。连接成功后,按固定周期读取 DHT11 数据,并组装成 JSON 消息发布到数据主题。电脑端提前订阅对应主题,就可以持续接收温湿度数据。
三、硬件与软件环境
3.1 硬件清单
硬件部分不复杂,常见 ESP32 DevKit 开发板和 DHT11 模块即可完成实验。这里不建议一上来使用复杂传感器,因为初学阶段更重要的是把采集、联网、协议和调试链路跑通。
| 硬件 | 说明 |
|---|---|
ESP32 开发板 |
常见 ESP32 DevKit 即可 |
DHT11 温湿度传感器 |
三针或四针模块均可 |
| 杜邦线 | 用于连接传感器和开发板 |
USB 数据线 |
用于供电、下载程序和查看串口日志 |
| 电脑 | 用于编译代码和订阅 MQTT 数据 |
| 路由器 | ESP32 需要连接 2.4GHz WiFi |
3.2 DHT11 与 ESP32 接线说明
本文使用 ESP32 的 GPIO4 连接 DHT11 的数据引脚。接线时不要只看模块插针顺序,不同厂家的 DHT11 模块引脚排列可能不完全一致,建议以模块丝印为准。

这里使用三线连接即可,分别是供电、地线和数据线。VCC 接 3.3V,GND 接 GND,DATA 接 GPIO4。如果使用的是裸 DHT11 传感器而不是模块,通常还需要在 DATA 和 VCC 之间增加上拉电阻。
DHT11 引脚 |
ESP32 引脚 |
说明 |
|---|---|---|
VCC |
3.3V |
给传感器供电 |
GND |
GND |
公共地 |
DATA |
GPIO4 |
温湿度数据线 |
DHT11 VCC ---> ESP32 3.3V
DHT11 GND ---> ESP32 GND
DHT11 DATA ---> ESP32 GPIO4
风险提醒:如果 DATA 线接错,程序一般不会报编译错误,但运行时会持续出现读取失败。排查传感器问题时,第一步永远是核对供电、地线和数据引脚。
3.3 软件环境准备
软件部分使用 Arduino IDE 完成开发,主要依赖两个库:DHT sensor library 用于读取温湿度,PubSubClient 用于连接和发布 MQTT 消息。
| 软件或库 | 用途 |
|---|---|
Arduino IDE |
编写和下载 ESP32 程序 |
ESP32 开发板支持包 |
让 Arduino IDE 支持 ESP32 编译下载 |
DHT sensor library |
读取 DHT11 温湿度 |
PubSubClient |
实现 MQTT 客户端功能 |
MQTTX |
电脑端订阅和调试 MQTT 数据 |
MQTT Explorer |
可视化查看 Topic 和消息内容 |
| 串口监视器 | 查看 ESP32 启动和运行日志 |
推荐做法:先单独验证 DHT11 读取,再验证 WiFi 连接,最后接入 MQTT。不要把所有功能一次性写完再排查,否则很难判断问题到底出在硬件、网络还是协议层。
四、MQTT Topic 与数据结构设计
4.1 为什么 Topic 不能随便命名
MQTT Topic 的命名在小项目里看起来不重要,但设备数量增加后会直接影响后续管理和排查。如果一开始随便写成 test、data、temp,后面很难区分设备来源、数据类型和用途。
本文使用下面三个主题:
Topic |
用途 |
|---|---|
esp32/dht11/data |
上报温湿度数据 |
esp32/dht11/status |
上报设备在线状态 |
esp32/dht11/debug |
预留调试信息主题 |
实际代码中主要使用 esp32/dht11/data 和 esp32/dht11/status。前者负责周期性上报温湿度,后者负责标记设备上线和异常离线状态。
4.2 MQTT Topic 与 JSON 数据结构设计
MQTT 消息不要只发送 26.3,48.0 这样的裸数据。它虽然短,但后续接数据库、可视化平台、规则引擎和告警系统时,解析成本会变高,而且字段扩展容易破坏原有格式。

这里采用 JSON 结构,一条消息同时带上设备编号、温度、湿度、WiFi RSSI 和运行时间。这样做的好处是数据含义明确,字段扩展更自然,后续服务端也更容易做解析和入库。
{
"device": "esp32-dht11-001",
"temperature": 26.30,
"humidity": 48.00,
"wifi_rssi": -52,
"uptime": 12345
}
| 字段 | 含义 |
|---|---|
device |
设备编号 |
temperature |
温度 |
humidity |
湿度 |
wifi_rssi |
WiFi 信号强度 |
uptime |
设备运行时间,单位毫秒 |
原理说明:Topic 负责区分消息通道,JSON 负责描述消息内容。一个设计通道,一个设计数据结构,两者不要混在一起。
4.3 为什么要上报 WiFi RSSI
现场设备经常出现一种情况:代码没有问题,服务器也没有问题,但数据就是偶发不上报。很多时候根因不是程序逻辑,而是设备部署位置的 WiFi 信号不稳定。
RSSI 范围 |
大致判断 |
|---|---|
-40 dBm 左右 |
信号较强 |
-60 dBm 左右 |
正常可用 |
-70 dBm 以下 |
信号偏弱,可能不稳定 |
-80 dBm 以下 |
容易掉线 |
把 wifi_rssi 放进上报数据后,排查网络问题时就不需要只靠猜测。平台侧长期观察信号强度,也可以提前发现部署点位不合理的问题。
五、完整代码实现
5.1 代码使用前需要修改的位置
完整代码中需要根据自己的环境修改四类参数:WiFi 名称、WiFi 密码、MQTT Broker 地址和端口。如果 Broker 启用了账号密码,还需要填写 MQTT_USER 和 MQTT_PASSWORD。
风险提醒:ESP32 常见开发板通常连接 2.4GHz WiFi,不要使用仅支持 5GHz 的无线网络,否则会一直连接失败。
5.2 Arduino 完整代码
下面代码把 DHT11 读取、WiFi 连接、MQTT 发布、在线状态、断线重连和串口日志放到一起。为了避免重连逻辑过度阻塞,代码中使用了时间间隔控制,而不是在主循环里疯狂重连。
#include <WiFi.h>
#include <PubSubClient.h>
#include "DHT.h"
// ==========================
// 1. WiFi 配置
// ==========================
const char* WIFI_SSID = "你的WiFi名称";
const char* WIFI_PASSWORD = "你的WiFi密码";
// ==========================
// 2. MQTT 配置
// ==========================
const char* MQTT_SERVER = "192.168.1.100";
const int MQTT_PORT = 1883;
const char* MQTT_CLIENT_ID = "esp32-dht11-001";
const char* MQTT_TOPIC_DATA = "esp32/dht11/data";
const char* MQTT_TOPIC_STATUS = "esp32/dht11/status";
const char* MQTT_USER = "";
const char* MQTT_PASSWORD = "";
// ==========================
// 3. DHT11 配置
// ==========================
#define DHT_PIN 4
#define DHT_TYPE DHT11
DHT dht(DHT_PIN, DHT_TYPE);
// ==========================
// 4. 全局对象
// ==========================
WiFiClient espClient;
PubSubClient mqttClient(espClient);
// ==========================
// 5. 时间控制
// ==========================
unsigned long lastPublishTime = 0;
const unsigned long PUBLISH_INTERVAL = 5000;
unsigned long lastWifiCheckTime = 0;
const unsigned long WIFI_CHECK_INTERVAL = 3000;
unsigned long lastMqttReconnectAttempt = 0;
const unsigned long MQTT_RECONNECT_INTERVAL = 3000;
// ==========================
// 6. 连接 WiFi
// ==========================
void connectWiFi() {
if (WiFi.status() == WL_CONNECTED) {
return;
}
Serial.println();
Serial.println("正在连接 WiFi...");
Serial.print("SSID: ");
Serial.println(WIFI_SSID);
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
int retryCount = 0;
while (WiFi.status() != WL_CONNECTED && retryCount < 20) {
delay(500);
Serial.print(".");
retryCount++;
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println();
Serial.println("WiFi 连接成功");
Serial.print("IP 地址: ");
Serial.println(WiFi.localIP());
Serial.print("WiFi 信号强度 RSSI: ");
Serial.println(WiFi.RSSI());
} else {
Serial.println();
Serial.println("WiFi 连接失败,稍后重试");
}
}
// ==========================
// 7. 连接 MQTT
// ==========================
bool connectMQTT() {
if (mqttClient.connected()) {
return true;
}
if (WiFi.status() != WL_CONNECTED) {
Serial.println("WiFi 未连接,暂不连接 MQTT");
return false;
}
Serial.println("正在连接 MQTT Broker...");
Serial.print("MQTT Server: ");
Serial.println(MQTT_SERVER);
bool connected = false;
if (strlen(MQTT_USER) > 0) {
connected = mqttClient.connect(
MQTT_CLIENT_ID,
MQTT_USER,
MQTT_PASSWORD,
MQTT_TOPIC_STATUS,
0,
true,
"offline"
);
} else {
connected = mqttClient.connect(
MQTT_CLIENT_ID,
MQTT_TOPIC_STATUS,
0,
true,
"offline"
);
}
if (connected) {
Serial.println("MQTT 连接成功");
mqttClient.publish(MQTT_TOPIC_STATUS, "online", true);
return true;
} else {
Serial.print("MQTT 连接失败,状态码: ");
Serial.println(mqttClient.state());
return false;
}
}
// ==========================
// 8. 读取并发布传感器数据
// ==========================
void publishSensorData() {
float humidity = dht.readHumidity();
float temperature = dht.readTemperature();
if (isnan(humidity) || isnan(temperature)) {
Serial.println("DHT11 读取失败,本次不上报");
return;
}
char payload[256];
snprintf(
payload,
sizeof(payload),
"{\"device\":\"%s\",\"temperature\":%.2f,\"humidity\":%.2f,\"wifi_rssi\":%d,\"uptime\":%lu}",
MQTT_CLIENT_ID,
temperature,
humidity,
WiFi.RSSI(),
millis()
);
Serial.print("发布数据: ");
Serial.println(payload);
bool result = mqttClient.publish(MQTT_TOPIC_DATA, payload);
if (result) {
Serial.println("MQTT 数据发布成功");
} else {
Serial.println("MQTT 数据发布失败");
}
}
// ==========================
// 9. WiFi 状态检查
// ==========================
void checkWiFi() {
unsigned long now = millis();
if (now - lastWifiCheckTime < WIFI_CHECK_INTERVAL) {
return;
}
lastWifiCheckTime = now;
if (WiFi.status() != WL_CONNECTED) {
Serial.println("检测到 WiFi 断开,开始重连");
connectWiFi();
}
}
// ==========================
// 10. MQTT 状态检查
// ==========================
void checkMQTT() {
if (mqttClient.connected()) {
return;
}
unsigned long now = millis();
if (now - lastMqttReconnectAttempt < MQTT_RECONNECT_INTERVAL) {
return;
}
lastMqttReconnectAttempt = now;
Serial.println("检测到 MQTT 断开,开始重连");
connectMQTT();
}
// ==========================
// 11. 初始化
// ==========================
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println();
Serial.println("ESP32 DHT11 MQTT 温湿度采集终端启动");
dht.begin();
connectWiFi();
mqttClient.setServer(MQTT_SERVER, MQTT_PORT);
mqttClient.setKeepAlive(30);
connectMQTT();
}
// ==========================
// 12. 主循环
// ==========================
void loop() {
checkWiFi();
checkMQTT();
if (mqttClient.connected()) {
mqttClient.loop();
}
unsigned long now = millis();
if (now - lastPublishTime >= PUBLISH_INTERVAL) {
lastPublishTime = now;
if (WiFi.status() == WL_CONNECTED && mqttClient.connected()) {
publishSensorData();
} else {
Serial.println("网络或 MQTT 未连接,跳过本次数据上报");
}
}
}
六、代码核心逻辑分析
6.1 为什么要拆分 WiFi 重连和 MQTT 重连
入门代码经常把 WiFi 和 MQTT 的连接写在同一个函数里,出问题后就从头开始阻塞重连。短时间演示可以跑,但现场使用时会带来三个问题:日志不好判断,重连节奏不可控,传感器采集容易被长时间阻塞。

本文把重连逻辑拆成两层。第一层检查 WiFi,只有网络接入正常,才有继续连接 MQTT Broker 的意义。第二层检查 MQTT,用于处理服务器关闭、端口不可达、账号密码错误或 Client ID 冲突等问题。
WiFi状态检查 ---> WiFi断线重连
MQTT状态检查 ---> MQTT断线重连
这样串口日志会更干净。看到 WiFi 连接失败,优先排查无线网络;看到 MQTT 连接失败,优先排查 Broker 地址、端口、防火墙和认证信息;看到 DHT11 读取失败,优先排查接线和传感器。
推荐做法:重连逻辑要设置间隔,不要在 loop 中无间隔持续请求 Broker。频繁重连不仅影响设备本身,还可能干扰服务器侧日志判断。
6.2 Last Will 遗嘱消息的作用
代码中连接 MQTT 时设置了遗嘱消息。设备正常上线后主动向 esp32/dht11/status 发布 online,如果设备异常掉线,MQTT Broker 会自动向状态主题发布 offline。
mqttClient.connect(
MQTT_CLIENT_ID,
MQTT_TOPIC_STATUS,
0,
true,
"offline"
);
这个机制非常适合 IoT 设备在线状态判断。电脑端或服务端只要订阅 esp32/dht11/status,就能知道设备最近一次状态。这里的 retain 设置为 true,是为了让新订阅客户端也能拿到最新状态。
6.3 传感器读取失败为什么不能继续上报
DHT11 读取失败时,库函数可能返回 NaN。如果不做判断,后续拼接出来的数据会变成无效值,平台侧反而更难处理。所以代码中遇到 NaN 时直接跳过本次上报。
if (isnan(humidity) || isnan(temperature)) {
Serial.println("DHT11 读取失败,本次不上报");
return;
}
原理说明:无效数据不上报,比上报错误数据更安全。采集类设备最怕把异常数据当成真实数据写入平台,后续统计和告警都会被污染。
七、PC 端验证与完整数据链路
7.1 PC 端订阅验证与完整数据链路
代码下载完成后,验证不能只看串口打印。串口只能证明 ESP32 本地逻辑在运行,电脑端能够订阅到 MQTT 消息,才能证明数据链路真正打通。

验证链路建议按顺序执行:先确认 ESP32 获得 IP 地址,再确认 MQTT 连接成功,然后使用 MQTTX 或 MQTT Explorer 订阅 esp32/dht11/data。如果电脑端能持续收到 JSON 数据,说明采集、处理、发布和订阅链路已经跑通。
| 配置项 | 示例 |
|---|---|
Host |
192.168.1.100 |
Port |
1883 |
Client ID |
pc-debug-client |
Username |
根据 Broker 设置填写 |
Password |
根据 Broker 设置填写 |
电脑端订阅数据主题:
esp32/dht11/data
电脑端订阅状态主题:
esp32/dht11/status
正常数据示例:
{
"device": "esp32-dht11-001",
"temperature": 26.30,
"humidity": 48.00,
"wifi_rssi": -52,
"uptime": 21435
}
7.2 串口日志应该怎么看
串口监视器波特率设置为 115200。正常启动时,日志应该依次出现 WiFi 连接、IP 地址、RSSI、MQTT 连接成功和数据发布成功。
ESP32 DHT11 MQTT 温湿度采集终端启动
正在连接 WiFi...
SSID: YourWiFi
........
WiFi 连接成功
IP 地址: 192.168.1.88
WiFi 信号强度 RSSI: -51
正在连接 MQTT Broker...
MQTT Server: 192.168.1.100
MQTT 连接成功
发布数据: {"device":"esp32-dht11-001","temperature":26.00,"humidity":48.00,"wifi_rssi":-51,"uptime":6123}
MQTT 数据发布成功
如果出现下面这类日志,优先排查无线网络:
检测到 WiFi 断开,开始重连
正在连接 WiFi...
如果出现下面这类日志,优先排查 MQTT Broker:
检测到 MQTT 断开,开始重连
正在连接 MQTT Broker...
MQTT 连接失败,状态码: -2
如果出现下面这类日志,优先排查传感器接线、供电和 GPIO 配置:
DHT11 读取失败,本次不上报
八、测试用例设计
8.1 不要只验证一次成功
很多项目第一次跑通并不代表稳定。建议至少做几组基础测试,尤其是断网、恢复、Broker 停止、传感器异常这几类场景。只有这些测试都能解释清楚,代码才算具备基本工程价值。
| 测试项 | 操作方法 | 预期结果 |
|---|---|---|
| 上电启动测试 | 给 ESP32 通电 |
能连接 WiFi 和 MQTT |
| 温湿度读取测试 | 正常连接 DHT11 |
串口输出温度和湿度 |
MQTT 发布测试 |
订阅 esp32/dht11/data |
能收到 JSON 数据 |
WiFi 断线测试 |
临时关闭路由器无线网络 | 串口打印 WiFi 重连日志 |
WiFi 恢复测试 |
恢复路由器无线网络 | 设备自动恢复连接 |
MQTT Broker 断线测试 |
停止 Broker 服务 |
串口打印 MQTT 重连失败 |
MQTT Broker 恢复测试 |
重新启动 Broker |
设备恢复发布数据 |
| 传感器异常测试 | 拔掉 DHT11 DATA 线 |
串口提示读取失败,不发布异常数据 |
推荐做法:测试时不要只记录“成功”或“失败”,要记录串口日志、客户端订阅结果和触发操作。这样后续复盘时能知道问题发生在硬件层、网络层还是协议层。
九、常见问题与踩坑记录
9.1 串口一直显示 WiFi 连接失败
WiFi 连接失败时,先不要怀疑 MQTT。设备还没有进入网络,后续协议层肯定无法建立连接。
| 可能原因 | 排查方法 | 解决方案 |
|---|---|---|
SSID 写错 |
检查名称是否完全一致 | 修改 WIFI_SSID |
| 密码错误 | 用手机连接同一网络验证 | 修改 WIFI_PASSWORD |
使用了 5GHz WiFi |
检查路由器频段 | 切换到 2.4GHz WiFi |
| 信号太弱 | 查看 RSSI 或靠近路由器 |
调整设备位置 |
| 路由器限制接入 | 检查黑名单或 MAC 过滤 |
放行 ESP32 |
9.2 MQTT 一直连接失败
MQTT 连接失败时,串口会打印 mqttClient.state() 的状态码。状态码可以快速缩小排查范围。
| 状态码 | 含义 |
|---|---|
-4 |
连接超时 |
-3 |
网络连接失败 |
-2 |
网络连接失败 |
-1 |
连接断开 |
1 |
协议版本错误 |
2 |
Client ID 被拒绝 |
4 |
用户名或密码错误 |
5 |
未授权 |
重点检查 MQTT_SERVER 是否正确,MQTT_PORT 是否为 1883,电脑和 ESP32 是否在同一网络,防火墙是否拦截端口,Broker 是否需要账号密码,以及 Client ID 是否重复。
风险提醒:如果多个客户端使用同一个 Client ID,可能互相挤掉连接,表现为设备频繁离线和重连。
9.3 DHT11 一直读取失败
DHT11 读取失败通常集中在接线、供电、引脚号和读取频率上。本文代码使用 GPIO4,实际接线也必须接到 GPIO4。
| 可能原因 | 说明 |
|---|---|
DATA 引脚接错 |
代码使用 GPIO4,实际也要接 GPIO4 |
| 电源接错 | VCC 接 3.3V,GND 接 GND |
| 模块损坏 | 更换一个 DHT11 测试 |
| 杜邦线过长 | 缩短连接线,减少干扰 |
| 读取频率过高 | DHT11 不适合高频读取 |
| 库未安装正确 | 重新安装 DHT sensor library |
9.4 MQTT 客户端订阅不到数据
客户端订阅不到数据时,要把问题拆开看。先看串口是否打印发布成功,再看电脑端是否连接到同一个 Broker,最后确认订阅的 Topic 是否和代码里完全一致。
| 检查项 | 说明 |
|---|---|
Topic 是否一致 |
发布和订阅必须完全一致 |
Broker 地址是否一致 |
ESP32 和电脑端要连接同一个服务器 |
| 串口是否发布成功 | 看是否打印 MQTT 数据发布成功 |
| 防火墙是否拦截 | Windows 防火墙 可能拦截 1883 |
| 客户端是否连接成功 | MQTTX 或 MQTT Explorer 要先连接 |
| 设备是否在线 | 订阅 esp32/dht11/status 查看状态 |
风险提醒:MQTT Topic 区分大小写。esp32/dht11/data 和 ESP32/DHT11/DATA 不是同一个主题。
十、工程化优化思路
10.1 增加配网机制
当前代码把 WiFi 名称、密码和 MQTT Broker 地址写死在程序里。实验环境可以接受,但真实设备不适合每次换网络都重新烧录固件。
后续可以考虑增加 SoftAP 配网、BLE 配网、Web 配网页面或 NVS 参数保存。这样设备部署时只需要通过网页或手机端填写参数,不需要重新打开 Arduino IDE。
10.2 增加本地缓存机制
当前逻辑在网络或 MQTT 未连接时会跳过本次上报。如果业务要求数据不能丢,就需要增加本地缓存机制。网络恢复后,再把缓存数据补发到 Broker。
ESP32 可以使用内存队列、SPIFFS、LittleFS、外接 Flash 或 SD 卡实现缓存。具体选择取决于数据量、掉线时长和写入寿命要求。
10.3 增加异常过滤和状态上报
DHT11 精度不高,也可能出现偶发异常值。后续可以增加数据过滤逻辑,例如温度或湿度突变过大时标记异常,连续读取失败达到阈值后向状态主题发布传感器异常。
如果本次数据与上次数据差值过大,则标记为异常;
如果连续3次读取失败,则上报传感器异常状态;
如果数据恢复正常,再恢复正常上报。
10.4 增加远程控制能力
当前设备只会上报数据,还没有接收命令。如果要把它升级成可远程管理终端,可以增加命令主题,例如 esp32/dht11/cmd,让服务端下发采集周期、重启、状态查询等命令。
{
"cmd": "set_interval",
"value": 10000
}
ESP32 收到命令后,可以动态修改上报间隔。这个能力会让设备从单向数据采集终端,升级为可管理的 IoT 节点。
10.5 增加 OTA 远程升级
真实设备部署后,不可能每次升级都插 USB 线重新烧录。后续可以加入 OTA 升级能力,例如局域网 OTA、HTTP OTA、MQTT 通知升级、双分区升级和失败回滚。
原理说明:OTA 不是锦上添花,而是联网设备长期维护的基础能力。只要设备有远程部署场景,就应该尽早考虑升级和回滚机制。
十一、总结
本文完成了一个基于 ESP32、DHT11 和 MQTT 的温湿度采集上云项目。它不是单纯读取一个传感器值,而是把硬件采集、数据封装、网络连接、消息发布、在线状态、断线重连和串口调试整合成了一条完整链路。
最终实现流程可以概括为:
DHT11采集温湿度
↓
ESP32读取并校验数据
↓
组装JSON消息
↓
连接WiFi网络
↓
连接MQTT Broker
↓
发布到指定Topic
↓
PC端订阅查看数据
↓
异常时自动重连
这个项目的实际价值在于,它把一个入门级传感器练习提升到了更接近工程现场的形态。能跑起来只是第一步,能在断线、异常、传感器读取失败和服务器不可达时保持可观测、可恢复,才是嵌入式联网项目真正需要沉淀的能力。
| 能力 | 当前状态 |
|---|---|
DHT11 传感器采集 |
已实现 |
WiFi 联网 |
已实现 |
MQTT 数据上报 |
已实现 |
JSON 数据格式 |
已实现 |
WiFi 断线重连 |
已实现 |
MQTT 断线重连 |
已实现 |
| 在线状态上报 | 已实现 |
| 串口日志 | 已实现 |
| 传感器异常处理 | 已实现 |
| 本地缓存 | 待优化 |
| 远程控制 | 待优化 |
OTA 升级 |
待优化 |
后续如果继续扩展,可以在这个项目基础上加入 Web 配网、本地缓存、远程控制、OTA 升级、数据可视化和告警推送。这样它就不只是一个温湿度实验,而是一个可以继续演进的 IoT 设备原型。
🔝 返回顶部
更多推荐
所有评论(0)