ESP32 IoT Weather Logger

Sending real-time Temperature & Humidity data from a DHT22 sensor to ThingSpeak using an ESP32 development board.

๐Ÿ“ก Project Overview

In this project, we build on the basic ThingSpeak account setup from the previous tutorial and create a real IoT application: an ESP32 board reads temperature and humidity values from a DHT22 sensor and uploads them to a ThingSpeak channel every 15 seconds, where they can be visualized as live charts.

ESP32 Board
โ‡„
DHT22 Sensor
ESP32 Board
โ†’ Wi-Fi โ†’
ThingSpeak Cloud
โ†’
Live Dashboard

The ESP32 connects to a local Wi-Fi network, reads sensor data, and sends it via an HTTP GET request to the ThingSpeak API.

๐Ÿงฐ Requirements

ComponentPurpose
ESP32 Development BoardMain microcontroller with built-in Wi-Fi
DHT22 (AM2302) SensorMeasures temperature and humidity
Jumper WiresConnects sensor to ESP32
ThingSpeak AccountFree cloud platform to store and visualize IoT data

Required Library

Only one external library is required for this project โ€” the DHT sensor library. No HTTP or ThingSpeak-specific library is required because we send data manually using simple HTTP GET requests.

โš ๏ธ Important Warning:
Avoid using the official โ€œThingSpeakโ€ Arduino library. It is known to be unreliable โ€” it may work occasionally and fail unpredictably at other times. The most robust and stable approach is to build the ThingSpeak update URL manually and send it using the standard HTTPClient library, exactly as shown in this tutorial.

๐Ÿ”Œ Wiring Diagram

The DHT22 sensor requires only 3 connections to the ESP32: power, ground, and one data pin.

DHT22 PinESP32 Pin
VCC3.3V
GNDGND
DATAGPIO 27
ESP32
3.3V
โ€”
DHT22
VCC
ESP32
GND
โ€”
DHT22
GND
ESP32
GPIO 27
โ€”
DHT22
DATA
๐Ÿ’ก In the code, the data pin is defined using #define DHTPIN 27. If you wire the sensor to a different GPIO, update this value accordingly.

โ˜๏ธ ThingSpeak Channel Setup

Before uploading the code, prepare your ThingSpeak channel:

1. Log in to your ThingSpeak account
2. Create a New Channel
3. Enable Field 1 โ†’ name it "Temperature"
4. Enable Field 2 โ†’ name it "Humidity"
5. Save Channel
6. Go to API Keys tab
7. Copy the Write API Key

This project uses only Field 1 (Temperature) and Field 2 (Humidity), even though a channel can support up to 8 fields.

๐Ÿง‘โ€๐Ÿ’ป Code Explanation โ€” Step by Step

1. Including Libraries

Three libraries are used: Wi-Fi connectivity, HTTP requests, and DHT sensor communication.

#include <WiFi.h>
#include <HTTPClient.h>
#include "DHT.h"

2. Defining the Sensor

We specify which GPIO pin the sensor's data line is connected to, and which DHT model we're using (DHT22).

#define DHTPIN 27
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);

3. Wi-Fi Credentials & ThingSpeak URL

The SSID and password connect the board to your local network. The serverName string is the ThingSpeak "update" endpoint containing your unique Write API Key.

const char* ssid = "Robotics Lab";
const char* password = "Robotics@321";
String serverName = "https://api.thingspeak.com/update?api_key=XXNUJDNUCHY4FTYU";
Replace the API key in serverName with your own Write API Key from your ThingSpeak channelโ€™s "API Keys" tab.

4. setup() โ€” Connecting to Wi-Fi

The board attempts to connect repeatedly until successful, printing dots to the Serial Monitor as feedback, then prints the assigned local IP address once connected.

Serial.begin(9600);
WiFi.begin(ssid, password);
while(WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
}
Serial.println(WiFi.localIP());
dht.begin();

5. loop() โ€” Reading Sensor & Sending Data

Inside the main loop, the program checks the Wi-Fi status. If connected, it reads temperature/humidity, builds the request URL, and sends it via HTTP GET.

if(WiFi.status() == WL_CONNECTED) {
    HTTPClient http;
    float h = dht.readHumidity();
    float t = dht.readTemperature();

    String url = serverName + "&field1=" + t + "&field2=" + h;
    http.begin(url.c_str());
    int httpResponseCode = http.GET();

    if (httpResponseCode > 0) {
        Serial.println(httpResponseCode);
    }
    http.end();
    delay(15000);
}

6. The 15-Second Rule

A free ThingSpeak account only allows one update every 15 seconds per channel. Thatโ€™s why delay(15000) is placed at the end of each successful upload cycle โ€” sending faster than this will cause updates to be silently ignored.

7. Handling Disconnection

If Wi-Fi is not connected, the board prints a "WiFi Disconnected" message with a short 1-second delay, rather than the full 15 seconds, so reconnection status feedback still refreshes at a fast pace.

else {
    Serial.println("WiFi Disconnected");
    delay(1000);
}

๐Ÿ“„ Complete Source Code

// Import necessary libraries
#include <WiFi.h>
#include <HTTPClient.h>
#include "DHT.h"
#define DHTPIN 27 // dht connection
#define DHTTYPE DHT22   // DHT 22  (AM2302), AM2321
DHT dht(DHTPIN, DHTTYPE);

// Set our wifi name and password
const char* ssid = "Robotics Lab";
const char* password = "Robotics@321";

// Your thingspeak channel url with api_key query
String serverName = "https://api.thingspeak.com/update?api_key=XXNUJDNUCHY4FTYU"; // please replace with your write API Key

void setup() 
{
  Serial.begin(9600);

  WiFi.begin(ssid, password);
  Serial.println("Connecting");
  while(WiFi.status() != WL_CONNECTED) 
  {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to WiFi network with IP Address: ");
  Serial.println(WiFi.localIP());
  delay(2000);
  dht.begin();
}

void loop() 
{
    if(WiFi.status()== WL_CONNECTED)
    { 
      HTTPClient http;
      float h = dht.readHumidity(); 
      float t = dht.readTemperature();
      Serial.print("Temperature = "); Serial.println(t);
      Serial.print("Humidity = "); Serial.println(h);
      Serial.println("*****************************************");
      String url = serverName + "&field1=" + t + "&field2=" + h;
      http.begin(url.c_str());
      int httpResponseCode = http.GET();
      if (httpResponseCode > 0)
      { 
        Serial.print("HTTP Response code: ");
        Serial.println(httpResponseCode);
      }
      else
      {
        Serial.print("Error code: ");
        Serial.println(httpResponseCode);
      }
      http.end();
      delay(15000);  
    }
    else 
    {
      Serial.println("WiFi Disconnected");
      delay(1000);
    }
}

๐Ÿš€ Upload & Test Instructions

Follow these steps in the Arduino IDE:

1. Connect the ESP32 board via USB
2. Select Tools โ†’ Board โ†’ ESP32 Dev Module
3. Select Tools โ†’ Port โ†’ (your COM port)
4. Replace ssid and password with your Wi-Fi credentials
5. Replace api_key value with your ThingSpeak Write API Key
6. Click Upload
7. Open Tools โ†’ Serial Monitor
8. Set baud rate to 9600

Expected Serial Monitor Output

Connecting.....
Connected to WiFi network with IP Address: 192.168.1.45
Temperature = 26.70
Humidity = 58.30
*****************************************
HTTP Response code: 200
โœ… A response code of 200 means the data was successfully received by ThingSpeak. A response of 0 or negative indicates a connection or request error.

๐Ÿ“Š Visualizing Data on ThingSpeak

Once data starts arriving, ThingSpeak automatically generates two default charts โ€” one per field โ€” labeled "Field 1 Chart" and "Field 2 Chart". You can rename these fields (e.g. "Room Temperature" and "Room Humidity") and customize each chart's appearance from the channel settings.

Customizable Chart Settings

SettingDescription
TitleCustom name shown above the chart
X-Axis LabelTypically set to "Time"
Y-Axis LabelTypically set to "Value", or the unit (ยฐC, %)
Time ScaleControls how much historical data is displayed
TypeLine, bar, or column style
๐Ÿ’ก Because free ThingSpeak channels enforce a minimum 15-second update interval, keep delay(15000) (or slightly higher) to avoid dropped data points.

๐Ÿ”ฎ Next Steps

This project can be extended further, such as:

IdeaBenefit
Add a gauge widgetReal-time visual indicator of current values
Export data to CSVDownload historical logs for analysis
Add alertsGet notified when temperature/humidity crosses a threshold
MATLAB AnalysisRun analytics directly within ThingSpeak