|
ESP32 温湿度监控系统:DHT22 + MQTT + Node-RED 仪表盘完整项目教程

ESP32 温湿度监控系统:DHT22 + MQTT + Node-RED 仪表盘完整项目教程

项目概述

温湿度监控是物联网领域最经典、最基础的项目之一。无论是智能家居、农业大棚、仓储管理还是实验室环境监控,温湿度数据都是最基本的监测指标。

本教程将带你从零搭建一个完整的 ESP32 温湿度监控系统,涵盖:

  • 硬件层:ESP32 开发板 + DHT22 温湿度传感器
  • 通信层:MQTT 协议数据上报
  • 服务层:Mosquitto MQTT Broker
  • 可视化层:Node-RED 仪表盘

你也可以将 MQTT Broker 替换为任何公共 MQTT 云平台(如阿里云 IoT、华为云 IoT、EMQX Cloud),代码只需修改 Broker 地址。

硬件清单

组件型号数量预估价格
开发板ESP32-DevKitC 或 NodeMCU-32S1¥25-40
温湿度传感器DHT22 (AM2302)1¥15-25
面包板830 孔1¥8-12
杜邦线公对母/公对公10 根¥3-5
电阻4.7kΩ 上拉电阻1¥0.1
MicroUSB 线数据线1¥5-10

总计约 ¥60-90,你大部分组件可能已有现成的。

硬件接线

DHT22 引脚定义

DHT22 有 4 个引脚(从左到右,面对传感器正面):

引脚名称说明
1VDD电源正极 3.3V-5V
2DATA数据引脚
3NC空脚(不连接)
4GND电源负极/地

接线图

ESP32                DHT22
------               -----
3.3V  ────────────── VDD  (引脚1)
GPIO4 ────────────── DATA (引脚2)
                       NC  (引脚3) — 不接
GND   ────────────── GND  (引脚4)

关键注意事项

  • DATA 引脚到 3.3V 之间需接一个 4.7kΩ 上拉电阻(DHT22 使用单总线协议,需要上拉电阻保证信号稳定)
  • 如果使用 DHT22 模块版(带 PCB 的),通常已集成上拉电阻,可直接接线
  • 线与线之间保持距离,避免信号串扰

环境配置

1. 安装 ESP32 开发环境

本教程使用 Arduino IDE,这是最快速的入门方式。

步骤

  1. 下载并安装 Arduino IDE(推荐 2.x 版本)
  2. 打开 Arduino IDE → 文件 → 首选项 → 附加开发板管理器网址,添加:
    https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
  3. 工具 → 开发板 → 开发板管理器 → 搜索 “ESP32” → 安装
  4. 安装完成后,在「工具 → 开发板」中选择 ESP32 Dev Module

2. 安装所需库

在 Arduino IDE 中:工具 → 管理库 → 搜索并安装以下库:

  • DHT sensor library by Adafruit (v1.4.4+)
  • Adafruit Unified Sensor by Adafruit (v1.1.9+)
  • PubSubClient by Nick O’Leary (v2.8+)
  • ArduinoJson by Benoit Blanchon (v6.21+)

完整代码

#include <WiFi.h>
#include <PubSubClient.h>
#include <DHT.h>
#include <ArduinoJson.h>

// ===== WiFi 配置 =====
const char* ssid = "你的WiFi名称";
const char* password = "你的WiFi密码";

// ===== MQTT 配置 =====
const char* mqtt_server = "你的MQTT服务器IP";
const int mqtt_port = 1883;
const char* mqtt_topic = "sensor/temperature-humidity";

// ===== DHT22 配置 =====
#define DHTPIN 4          // GPIO4 连接 DHT22 DATA
#define DHTTYPE DHT22     // DHT22 传感器 (AM2302)
DHT dht(DHTPIN, DHTTYPE);

// ===== 全局对象 =====
WiFiClient espClient;
PubSubClient client(espClient);

// ===== 上报间隔 =====
unsigned long lastMsg = 0;
const long interval = 30000;  // 30 秒上报一次

// ===== WiFi 连接 =====
void setup_wifi() {
  delay(10);
  Serial.println();
  Serial.print("连接 WiFi: ");
  Serial.println(ssid);

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println();
  Serial.println("WiFi 连接成功");
  Serial.print("IP 地址: ");
  Serial.println(WiFi.localIP());
}

// ===== MQTT 重连 =====
void reconnect() {
  while (!client.connected()) {
    Serial.print("连接 MQTT...");
    String clientId = "ESP32Client-";
    clientId += String(random(0xffff), HEX);

    if (client.connect(clientId.c_str())) {
      Serial.println("已连接");
    } else {
      Serial.print("失败 rc=");
      Serial.print(client.state());
      Serial.println(" 5 秒后重试");
      delay(5000);
    }
  }
}

// ===== 初始化 =====
void setup() {
  Serial.begin(115200);
  Serial.println("ESP32 温湿度监控系统启动");

  dht.begin();
  setup_wifi();
  client.setServer(mqtt_server, mqtt_port);
}

// ===== 主循环 =====
void loop() {
  if (!client.connected()) {
    reconnect();
  }
  client.loop();

  unsigned long now = millis();
  if (now - lastMsg > interval) {
    lastMsg = now;

    // 读取温湿度
    float humidity = dht.readHumidity();
    float temperature = dht.readTemperature();

    // 检查读取是否成功
    if (isnan(humidity) || isnan(temperature)) {
      Serial.println("DHT22 读取失败!");
      return;
    }

    // 构建 JSON 数据包
    StaticJsonDocument<200> doc;
    doc["temperature"] = temperature;
    doc["humidity"] = humidity;
    doc["device"] = "esp32-001";

    char buffer[256];
    size_t n = serializeJson(doc, buffer);
    
    // 发布到 MQTT
    if (client.publish(mqtt_topic, buffer, n)) {
      Serial.print("数据已发送: ");
      Serial.print("温度: ");
      Serial.print(temperature);
      Serial.print("°C, 湿度: ");
      Serial.print(humidity);
      Serial.println("%");
    } else {
      Serial.println("MQTT 发布失败");
    }
  }
}

代码说明

关键函数解析

  • setup_wifi():连接 WiFi,显示 IP 地址用于调试
  • reconnect():MQTT 断线自动重连(带随机 Client ID 避免冲突)
  • dht.readTemperature() / dht.readHumidity():读取 DHT22 数据
  • client.publish():以 JSON 格式将数据发布到 MQTT Topic
  • 每 30 秒上报一次,防止数据过于频繁

为什么用 JSON 格式

  • 结构清晰,可扩展(以后可以添加更多传感器字段)
  • Node-RED 和云平台都原生支持 JSON 解析
  • 比纯文本格式更适合多字段数据

搭建 MQTT Broker

方案一:本地 Mosquitto(推荐)

使用 Docker 一键部署:

docker run -d \
  --name mosquitto \
  -p 1883:1883 \
  -p 9001:9001 \
  -v mosquitto_data:/mosquitto/data \
  -v mosquitto_log:/mosquitto/log \
  eclipse-mosquitto:2

方案二:公共云平台

平台免费额度特点
EMQX Cloud100 连接全球节点,延迟低
阿里云 IoT50 设备国内速度快
HiveMQ Cloud10 连接无需注册,即开即用
腾讯云 IoT100 设备与微信生态集成好

验证 MQTT 服务

安装 MQTT 客户端工具:

# 安装 mosquitto 客户端 (macOS)
brew install mosquitto

# 订阅数据(在另一终端窗口运行)
mosquitto_sub -h 你的MQTT服务器IP -t "sensor/temperature-humidity"

# 如果看到类似以下输出,说明系统跑通了
{"temperature": 26.3, "humidity": 58.2, "device": "esp32-001"}

Node-RED 仪表盘

1. 安装 Node-RED

# 使用 Docker 一键部署
docker run -d \
  --name nodered \
  -p 1880:1880 \
  -v nodered_data:/data \
  nodered/node-red:latest

2. 安装 Dashboard 插件

浏览器访问 http://你的服务器IP:1880,点击右上角菜单 → 管理面板 → 安装:

node-red-dashboard

3. 创建数据流

导入以下 JSON 流到 Node-RED

  1. 复制下面的 JSON 代码
  2. 在 Node-RED 中:菜单 → 导入 → 剪贴板
  3. 粘贴后点击部署
[
  {
    "id": "mqtt-in",
    "type": "mqtt in",
    "topic": "sensor/temperature-humidity",
    "broker": "localhost",
    "port": "1883",
    "name": "接收传感器数据",
    "datatype": "json"
  },
  {
    "id": "function-parse",
    "type": "function",
    "func": "msg.payload = JSON.parse(msg.payload);\nmsg.temperature = msg.payload.temperature;\nmsg.humidity = msg.payload.humidity;\nreturn msg;",
    "name": "解析 JSON"
  },
  {
    "id": "ui-temp",
    "type": "ui_gauge",
    "group": "sensor-group",
    "label": "温度",
    "format": "{{value}} °C",
    "min": 0,
    "max": 50,
    "colors": ["#00b500","#e6e600","#ca3838"]
  },
  {
    "id": "ui-humid",
    "type": "ui_gauge",
    "group": "sensor-group",
    "label": "湿度",
    "format": "{{value}} %",
    "min": 0,
    "max": 100,
    "colors": ["#00b500","#e6e600","#ca3838"]
  },
  {
    "id": "ui-chart",
    "type": "ui_chart",
    "group": "sensor-group",
    "label": "温湿度趋势",
    "chartType": "line",
    "x": 10,
    "y": 10,
    "w": 20,
    "h": 10
  }
]

4. 访问仪表盘

浏览器打开 http://你的服务器IP:1880/ui,即可看到实时温湿度仪表盘:

  • 温度仪表盘(0-50°C,绿-黄-红 三色)
  • 湿度仪表盘(0-100%)
  • 温湿度趋势折线图

调试与排错

常见问题

1. DHT22 读取失败(NaN)

  • 检查 4.7kΩ 上拉电阻是否接好
  • 确认 DATA 引脚连接到 GPIO4(代码中定义的 DHTPIN)
  • 尝试将 DHT22 换成 DHT11(代码中 #define DHTTYPE DHT22 改为 DHT11

2. WiFi 连接失败

  • 检查 SSID 和密码是否正确
  • ESP32 仅支持 2.4GHz WiFi,不支持 5GHz
  • 确认路由器 DHCP 功能正常

3. MQTT 连接失败

  • 检查防火墙是否开放 1883 端口
  • 确认 MQTT Broker 正在运行:docker ps | grep mosquitto
  • 查看 MQTT Broker 日志:docker logs mosquitto

4. 数据乱码或不完整

  • 确认 JSON 格式正确,可以使用在线 JSON 校验工具检查
  • 增大 PubSubClient 缓冲区:在代码开头添加 #define MQTT_MAX_PACKET_SIZE 512

扩展方向

基础项目跑通后,你可以轻松扩展:

多传感器整合

  • 添加光照传感器(BH1750)→ 光照度数据
  • 添加土壤湿度传感器 → 植物浇水监控
  • 添加气压传感器(BMP280)→ 天气预报

数据持久化

  • 将 MQTT 数据存入 InfluxDB 时序数据库
  • 使用 Grafana 创建更专业的仪表盘

远程访问

  • 使用 FRP 或 Ngrok 将 MQTT Broker 暴露到公网
  • 或直接用云平台 MQTT 服务(阿里云/华为云/EMQX Cloud)

低功耗改造

  • 启用 ESP32 深度睡眠模式,电池供电
  • 只在需要采集数据时唤醒,大幅延长续航

总结

本教程从零搭建了一个完整的 ESP32 温湿度监控系统,涵盖了:

  1. 硬件选型与接线
  2. Arduino IDE 开发环境配置
  3. DHT22 数据读取与 MQTT 上报
  4. Mosquitto Broker 部署
  5. Node-RED 仪表盘可视化

这个项目是物联网入门的最佳实践——它包含了 IoT 系统的完整链路:感知层 → 网络层 → 平台层 → 应用层。跑通这个项目后,你已经掌握了 IoT 开发的核心技能,可以轻松扩展到其他传感器和应用场景。

下一步推荐:尝试将 ESP32 切换到深度睡眠模式,用两节 AA 电池供电,做一个能运行数月的无线温湿度监测节点。