|
ESP32 Temperature & Humidity Monitoring System: DHT22 + MQTT + Node-RED Dashboard Complete Project Tutorial

ESP32 Temperature & Humidity Monitoring System: DHT22 + MQTT + Node-RED Dashboard Complete Project Tutorial

Project Overview

Temperature and humidity monitoring is one of the most classic and fundamental projects in the IoT field. Whether it’s smart homes, agricultural greenhouses, warehouse management, or laboratory environment monitoring, temperature and humidity data are the most basic monitoring indicators.

This tutorial will take you through building a complete ESP32 temperature and humidity monitoring system from scratch, covering:

  • Hardware Layer: ESP32 development board + DHT22 temperature and humidity sensor
  • Communication Layer: MQTT protocol data reporting
  • Service Layer: Mosquitto MQTT Broker
  • Visualization Layer: Node-RED dashboard

You can also replace the MQTT Broker with any public MQTT cloud platform (such as Alibaba Cloud IoT, Huawei Cloud IoT, EMQX Cloud) - the code only needs the Broker address modified.

Hardware List

ComponentModelQuantityEstimated Price
Development BoardESP32-DevKitC or NodeMCU-32S1¥25-40
Temperature/Humidity SensorDHT22 (AM2302)1¥15-25
Breadboard830 holes1¥8-12
Jumper WiresMale-to-female/Male-to-male10 pieces¥3-5
Resistor4.7kΩ pull-up resistor1¥0.1
MicroUSB CableData cable1¥5-10

Total approximately ¥60-90, you probably already have most components on hand.

Hardware Wiring

DHT22 Pin Definition

DHT22 has 4 pins (from left to right, facing the sensor front):

PinNameDescription
1VDDPower positive 3.3V-5V
2DATAData pin
3NCNo connection
4GNDPower negative/Ground

Wiring Diagram

ESP32                DHT22
------               -----
3.3V  ────────────── VDD  (Pin 1)
GPIO4 ────────────── DATA (Pin 2)
                       NC  (Pin 3) — Not connected
GND   ────────────── GND  (Pin 4)

Key Notes:

  • A 4.7kΩ pull-up resistor is needed between DATA pin and 3.3V (DHT22 uses one-wire protocol, pull-up resistor ensures signal stability)
  • If using DHT22 module version (with PCB), pull-up resistor is usually already integrated, can wire directly
  • Keep distance between wires to avoid signal crosstalk

Environment Configuration

1. Install ESP32 Development Environment

This tutorial uses Arduino IDE, which is the fastest way to get started.

Steps:

  1. Download and install Arduino IDE (recommend 2.x version)
  2. Open Arduino IDE → File → Preferences → Additional Board Manager URLs, add:
    https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
  3. Tools → Board → Boards Manager → Search “ESP32” → Install
  4. After installation, select ESP32 Dev Module in “Tools → Board”

2. Install Required Libraries

In Arduino IDE: Tools → Manage Libraries → Search and install the following libraries:

  • 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+)

Complete Code

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

// ===== WiFi Configuration =====
const char* ssid = "YourWiFiName";
const char* password = "YourWiFiPassword";

// ===== MQTT Configuration =====
const char* mqtt_server = "YourMQTTServerIP";
const int mqtt_port = 1883;
const char* mqtt_topic = "sensor/temperature-humidity";

// ===== DHT22 Configuration =====
#define DHTPIN 4          // GPIO4 connected to DHT22 DATA
#define DHTTYPE DHT22     // DHT22 sensor (AM2302)
DHT dht(DHTPIN, DHTTYPE);

// ===== Global Objects =====
WiFiClient espClient;
PubSubClient client(espClient);

// ===== Reporting Interval =====
unsigned long lastMsg = 0;
const long interval = 30000;  // Report every 30 seconds

// ===== WiFi Connection =====
void setup_wifi() {
  delay(10);
  Serial.println();
  Serial.print("Connecting to 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 connected successfully");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
}

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

    if (client.connect(clientId.c_str())) {
      Serial.println("Connected");
    } else {
      Serial.print("Failed rc=");
      Serial.print(client.state());
      Serial.println(" retry in 5 seconds");
      delay(5000);
    }
  }
}

// ===== Initialization =====
void setup() {
  Serial.begin(115200);
  Serial.println("ESP32 Temperature & Humidity Monitoring System Starting");

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

// ===== Main Loop =====
void loop() {
  if (!client.connected()) {
    reconnect();
  }
  client.loop();

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

    // Read temperature and humidity
    float humidity = dht.readHumidity();
    float temperature = dht.readTemperature();

    // Check if reading was successful
    if (isnan(humidity) || isnan(temperature)) {
      Serial.println("DHT22 read failed!");
      return;
    }

    // Build JSON data packet
    StaticJsonDocument<200> doc;
    doc["temperature"] = temperature;
    doc["humidity"] = humidity;
    doc["device"] = "esp32-001";

    char buffer[256];
    size_t n = serializeJson(doc, buffer);
    
    // Publish to MQTT
    if (client.publish(mqtt_topic, buffer, n)) {
      Serial.print("Data sent: ");
      Serial.print("Temperature: ");
      Serial.print(temperature);
      Serial.print("°C, Humidity: ");
      Serial.print(humidity);
      Serial.println("%");
    } else {
      Serial.println("MQTT publish failed");
    }
  }
}

Code Explanation

Key Function Analysis:

  • setup_wifi(): Connects to WiFi, displays IP address for debugging
  • reconnect(): MQTT auto-reconnection on disconnect (with random Client ID to avoid conflicts)
  • dht.readTemperature() / dht.readHumidity(): Read DHT22 data
  • client.publish(): Publish data to MQTT Topic in JSON format
  • Reports every 30 seconds to prevent data being too frequent

Why use JSON format?

  • Clear structure, extensible (can add more sensor fields later)
  • Node-RED and cloud platforms natively support JSON parsing
  • More suitable for multi-field data than plain text format

Setting Up MQTT Broker

One-click deployment using 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

Option 2: Public Cloud Platforms

PlatformFree QuotaFeatures
EMQX Cloud100 connectionsGlobal nodes, low latency
Alibaba Cloud IoT50 devicesFast speed in China
HiveMQ Cloud10 connectionsNo registration needed, ready to use
Tencent Cloud IoT100 devicesGood integration with WeChat ecosystem

Verify MQTT Service

Install MQTT client tools:

# Install mosquitto clients (macOS)
brew install mosquitto

# Subscribe to data (run in another terminal window)
mosquitto_sub -h YourMQTTServerIP -t "sensor/temperature-humidity"

# If you see output similar to below, the system is working
{"temperature": 26.3, "humidity": 58.2, "device": "esp32-001"}

Node-RED Dashboard

1. Install Node-RED

# One-click deployment using Docker
docker run -d \
  --name nodered \
  -p 1880:1880 \
  -v nodered_data:/data \
  nodered/node-red:latest

2. Install Dashboard Plugin

Access http://YourServerIP:1880 in browser, click top-right menu → Manage Palette → Install:

node-red-dashboard

3. Create Data Flow

Import the following JSON flow into Node-RED:

  1. Copy the JSON code below
  2. In Node-RED: Menu → Import → Clipboard
  3. Paste and click deploy
[
  {
    "id": "mqtt-in",
    "type": "mqtt in",
    "topic": "sensor/temperature-humidity",
    "broker": "localhost",
    "port": "1883",
    "name": "Receive sensor data",
    "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": "Parse JSON"
  },
  {
    "id": "ui-temp",
    "type": "ui_gauge",
    "group": "sensor-group",
    "label": "Temperature",
    "format": "{{value}} °C",
    "min": 0,
    "max": 50,
    "colors": ["#00b500","#e6e600","#ca3838"]
  },
  {
    "id": "ui-humid",
    "type": "ui_gauge",
    "group": "sensor-group",
    "label": "Humidity",
    "format": "{{value}} %",
    "min": 0,
    "max": 100,
    "colors": ["#00b500","#e6e600","#ca3838"]
  },
  {
    "id": "ui-chart",
    "type": "ui_chart",
    "group": "sensor-group",
    "label": "Temperature & Humidity Trend",
    "chartType": "line",
    "x": 10,
    "y": 10,
    "w": 20,
    "h": 10
  }
]

4. Access Dashboard

Open http://YourServerIP:1880/ui in browser to see the real-time temperature and humidity dashboard:

  • Temperature gauge (0-50°C, green-yellow-red three colors)
  • Humidity gauge (0-100%)
  • Temperature and humidity trend line chart

Debugging and Troubleshooting

Common Issues

1. DHT22 read failure (NaN)

  • Check if 4.7kΩ pull-up resistor is connected properly
  • Confirm DATA pin is connected to GPIO4 (DHTPIN defined in code)
  • Try switching DHT22 to DHT11 (change #define DHTTYPE DHT22 to DHT11 in code)

2. WiFi connection failed

  • Check if SSID and password are correct
  • ESP32 only supports 2.4GHz WiFi, does not support 5GHz
  • Confirm router DHCP function is working properly

3. MQTT connection failed

  • Check if firewall has port 1883 open
  • Confirm MQTT Broker is running: docker ps | grep mosquitto
  • Check MQTT Broker logs: docker logs mosquitto

4. Data garbled or incomplete

  • Confirm JSON format is correct, can use online JSON validation tool to check
  • Increase PubSubClient buffer: add #define MQTT_MAX_PACKET_SIZE 512 at the beginning of code

Extension Directions

After getting the basic project running, you can easily extend:

Multi-sensor integration:

  • Add light sensor (BH1750) → Illuminance data
  • Add soil moisture sensor → Plant watering monitoring
  • Add air pressure sensor (BMP280) → Weather forecast

Data persistence:

  • Store MQTT data in InfluxDB time-series database
  • Use Grafana to create more professional dashboards

Remote access:

  • Use FRP or Ngrok to expose MQTT Broker to public network
  • Or directly use cloud platform MQTT services (Alibaba Cloud/Huawei Cloud/EMQX Cloud)

Low-power modification:

  • Enable ESP32 deep sleep mode, battery powered
  • Only wake up when data collection is needed, greatly extending battery life

Summary

This tutorial built a complete ESP32 temperature and humidity monitoring system from scratch, covering:

  1. Hardware selection and wiring
  2. Arduino IDE development environment configuration
  3. DHT22 data reading and MQTT reporting
  4. Mosquitto Broker deployment
  5. Node-RED dashboard visualization

This project is the best practice for IoT beginners - it contains the complete chain of an IoT system: perception layer → network layer → platform layer → application layer. After completing this project, you have mastered the core skills of IoT development and can easily extend to other sensors and application scenarios.

Next step recommendation: Try switching ESP32 to deep sleep mode, power with two AA batteries, make a wireless temperature and humidity monitoring node that can run for months.