Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
Build an ESP32 logger that reads a DHT11 or DHT22, sends temperature and relative humidity to ThingSpeak, and optionally archives the readings in Google Sheets. The ESP32 writes to ThingSpeak first; Sheets is a separate reporting and archive layer, so you can verify device uploads before adding spreadsheet automation.
What this logger measures
A DHT sensor measures air temperature and relative humidity. It does not measure pressure, wind, or rainfall, so this project is an indoor environmental monitor or a starting point for a weather station—not a complete weather station by itself.
The data path is:
DHT sensor → ESP32 → Wi-Fi → ThingSpeak → optional Google Sheets
Recommended Free Tools
ThingSpeak provides the device-facing channel, feed, and charts. Google Sheets is useful for formulas, manual analysis, sharing, and export. If Internet access drops, neither cloud destination guarantees preservation of readings unless you add local buffering.
#1 Best Overall
- 2.4GHz Dual Mode WiFi + Bluetooth Development Board
- Support LWIP protocol, Freertos
- SupportThree Modes: AP, STA, and AP+STA
- Ultra-Low power consumption, Compatible with Arduino IDE
- ESP32 is a safe, reliable, and scalable to a variety of applications
Choose a sensor and gather the parts
DHT11 or DHT22
| Sensor | Best fit | Trade-off |
|---|---|---|
| DHT11 | Low-cost classroom demonstrations and simple indoor monitoring. | Narrower range and lower precision than the DHT22. |
| DHT22 / AM2302 | General-purpose temperature and humidity logging. | Usually costs more than a DHT11 and remains a relatively slow sensor. |
Neither is laboratory-grade. Placement, airflow, enclosure, condensation, self-heating, and module quality all affect readings. The firmware sensor type must match the actual part: use DHT11 for a DHT11 or DHT22 for a DHT22.
Parts and software
- ESP32 development board, USB cable, and USB power source.
- DHT11 or DHT22 module, breadboard, and jumper wires.
- A 4.7 kΩ–10 kΩ pull-up resistor if using a bare four-pin sensor without a breakout board that already includes one.
- Arduino IDE with ESP32 board support, the Adafruit DHT sensor library, any dependency it prompts you to install, and the ThingSpeak library.
- A ThingSpeak account, channel number, and write API key; Wi-Fi credentials for the network the ESP32 will use.
- Optional Google account and Sheet. For local backup, add a microSD module; a Sheet is not an offline buffer.
The ThingSpeak Arduino library is listed as compatible with ESP32; its Arduino library-index entry showed version 2.1.1 on June 26, 2025. Library and IDE labels can change, so check the installed library’s examples and method signatures if your version differs. See the Arduino ThingSpeak library listing, MathWorks library repository, and Adafruit DHT library.
Wire the sensor and test it locally
For a typical three-pin breakout module, connect:
- DHT VCC → ESP32 3V3
- DHT GND → ESP32 GND
- DHT DATA → ESP32 GPIO 4
GPIO 4 is an example, not a requirement; set the sketch’s DHTPIN to the GPIO you actually use. Pin order varies among modules, so follow their labels or datasheet rather than relying on a universal left-to-right order. Avoid pins reserved by your particular ESP32 board for flash, PSRAM, bootstrapping, or onboard peripherals.
If using a bare sensor, check its datasheet for pinout and pull-up requirements. Keep the DHT away from the ESP32 voltage regulator and antenna area when temperature accuracy matters. Start with a DHT-only test before adding Wi-Fi, which makes sensor wiring and sensor-type errors easier to isolate.
Rank #2
- Dual-Core Performance Up to 240 MHz: Run sensor processing, wireless communication, automation logic and connected-device tasks on a 32-bit dual-core ESP32 platform designed for responsive embedded and IoT projects
- Built-in Wi-Fi and Bluetooth 4.2: Connect to 2.4 GHz Wi-Fi networks or use Bluetooth Classic and BLE for wireless sensors, smart devices, remote controls, home automation and other connected projects
- Flexible Power-Saving Modes: ESP32 power-management features support dynamic clock scaling and low-power operating modes, helping developers reduce energy use in compatible sensing, monitoring and connected-device applications, suitable for battery-powered Internet of Things (IoT) devices.
- USB-C Programming with CP2102: Connect through USB-C for power, sketch uploads and serial monitoring, while GPIO, UART, SPI and I2C interfaces support sensors, displays, motor drivers and other modules (USB-C cable not included)
- Over-the-Air Update Support: Configure OTA functionality through a compatible ESP-32 software framework to update deployed firmware over Wi-Fi without reconnecting the board by USB for every revision
Create a ThingSpeak channel
- Sign in to ThingSpeak and create a channel.
- Name the fields and units. A practical mapping is Field 1: Temperature °C; Field 2: Relative humidity %; optionally Field 3: Temperature °F and Field 4: Wi-Fi RSSI.
- Save the channel, then copy its Channel ID and Write API Key. The ID identifies the destination; the write key authorizes device updates. Keep the key private.
- Choose public or private visibility. Treat a public channel as observable by anyone who can reach it; indoor readings may reveal occupancy or heating patterns. A private channel requires suitable credentials to read.
Send temperature and humidity together in one channel update. ThingSpeak defines a message as a write of up to eight fields to a channel, making a single multi-field write the sensible design for these paired readings. The ESP32 Wi-Fi workflow is documented in Espressif’s Arduino-ESP32 Wi-Fi documentation.
Upload readings from the ESP32
In Arduino IDE, install the ESP32 board package, select the actual board model, and install the DHT and ThingSpeak libraries. Replace the Wi-Fi name, password, channel number, and write key below. Do not publish a sketch containing real credentials or commit it to a public repository.
This sketch checks the connection with a timeout, retries on later loop passes, rejects failed DHT reads, and submits both measurements in one write every 30 seconds. It also includes RSSI in Field 4; remove that field call if the channel does not use it.
#include <WiFi.h>
#include "DHT.h"
#include "ThingSpeak.h"
#define DHTPIN 4
#define DHTTYPE DHT22 // Change to DHT11 if that is your sensor
const char* ssid = "YOUR_WIFI_NAME";
const char* password = "YOUR_WIFI_PASSWORD";
unsigned long channelNumber = 123456; // Replace with your channel ID
const char* writeAPIKey = "YOUR_WRITE_API_KEY";
DHT dht(DHTPIN, DHTTYPE);
WiFiClient client;
const unsigned long uploadInterval = 30000;
unsigned long lastUpload = 0;
void connectWiFi() {
if (WiFi.status() == WL_CONNECTED) return;
WiFi.begin(ssid, password);
unsigned long started = millis();
while (WiFi.status() != WL_CONNECTED && millis() - started < 15000) {
delay(500);
Serial.print(".");
}
Serial.println();
if (WiFi.status() == WL_CONNECTED) {
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
} else {
Serial.println("Wi-Fi connection timed out; will retry");
}
}
void setup() {
Serial.begin(115200);
dht.begin();
connectWiFi();
ThingSpeak.begin(client);
}
void loop() {
connectWiFi();
if (millis() - lastUpload < uploadInterval) return;
lastUpload = millis();
float humidity = dht.readHumidity();
float temperatureC = dht.readTemperature();
if (isnan(humidity) || isnan(temperatureC) || humidity < 0 || humidity > 100) {
Serial.println("Invalid DHT reading; not uploading");
return;
}
if (WiFi.status() != WL_CONNECTED) {
Serial.println("No Wi-Fi; reading not uploaded");
return;
}
ThingSpeak.setField(1, temperatureC);
ThingSpeak.setField(2, humidity);
ThingSpeak.setField(4, WiFi.RSSI());
int result = ThingSpeak.writeFields(channelNumber, writeAPIKey);
if (result == 200) {
Serial.println("ThingSpeak update successful");
} else {
Serial.print("ThingSpeak update failed; status: ");
Serial.println(result);
}
}
Temperature is stored in Celsius. If you also want Fahrenheit, calculate it as temperatureC * 9.0 / 5.0 + 32.0 and write it to a field explicitly labeled °F. Never put Fahrenheit values in a Celsius field.
Rank #3
- Powerful ESP-32 Board: Unlock the world of Internet of Things (IoT) and advanced electronics with the heart of this kit: the ESP-32 board. It features a powerful dual-core processor, integrated Wi-Fi and Bluetooth 4.2, making it perfect for building connected, smart devices that communicate with your phone or the cloud. It's fully compatible with the Arduino IDE for easy programming.
- Super Starter Kit: This kit contains over 35 different modules and electronic components, including sensors, displays, motors, and input devices. From LEDs and buttons to an OLED screen, servo motor, and keypad, you have everything needed to explore a vast range of projects in one box.
- Step by Step Online Tutorial: Jump right in with our detailed, beginner-friendly tutorial. Access 30+ projects with complete code, clear circuit diagrams, and step-by-step instructions. Learn the fundamentals of electronics, coding, and how to utilize the ESP-32's unique capabilities without any prior experience.
- Hands-on Learning for All Skill Levels: Perfect for students, makers, engineers, and hobbyists. Start with basic circuits and coding, then progress to intermediate and advanced IoT applications. Build practical projects like weather stations, smart home controllers, remote-controlled devices, and interactive gadgets. The skills you learn are the foundation for real-world innovation.
- Quality & Great Support: Elegoo is committed to quality. We provide a clear, detailed tutorial guide, refined code, and a well-organized component kit. All modules are carefully selected for reliability and ease of use. Our dedicated technical support team and active online community are ready to help you succeed in your learning journey.
Open Serial Monitor at 115200 baud, upload the sketch, and confirm a valid sensor reading and successful update. The ThingSpeak library’s writeFields method and examples are in the official library repository. If your installed version reports a compile error, check its included examples rather than assuming every version has identical signatures.
Set a useful sampling interval
For ordinary room monitoring, 30–60 seconds is more sensible than uploading as fast as possible: DHT sensors are slow, so extra writes often add cloud traffic without materially improving the record. The 30-second sketch above makes one write each interval.
ThingSpeak’s free option is intended for small non-commercial projects. As stated on the licensing pages checked August 18, 2026, it allows 3 million messages per year, four channels, and a minimum 15-second update interval per channel. A ThingSpeak message can contain up to eight fields, so paired temperature and humidity still count as one channel write. Limits vary by license and can change; check the current license FAQ and Standard license page before deploying. Paid options may permit one-second updates depending on license, but that is rarely useful for a DHT logger.
| Upload interval | Approximate writes per year |
|---|---|
| 15 seconds | 2,102,400 |
| 20 seconds | 1,576,800 |
| 30 seconds | 1,051,200 |
| 60 seconds | 525,600 |
| 5 minutes | 105,120 |
These estimates assume an uninterrupted schedule and one ThingSpeak write per interval. The 20-second total is below the stated free annual allowance; actual totals vary with uptime and retries.
Rank #4
- 2.4GHz Dual Mode WiFi + Bluetooth Development Board
- Support LWIP protocol, Freertos;ESP32 is a safe, reliable, and scalable to a variety of applications
- SupportThree Modes: AP, STA, and AP+STA
- Ultra-Low power consumption, Compatible with Arduino IDE
- 1PCS 30Pin ESP32 Development Board 2.4GHz WiFi Dual Cores Microcontroller Integrated with Antenna RF Low Noise Amplifiers Filters
Archive ThingSpeak data in Google Sheets
For most beginners, keep ThingSpeak as the device’s single destination and let a scheduled Google Apps Script retrieve the channel feed. This separates device ingestion from spreadsheet processing: a Sheet-side failure need not stop the ESP32 from sending readings to ThingSpeak. It also means the Sheet may lag behind the ThingSpeak update.
Use Google’s Apps Script web-app documentation to create and authorize the importer, and consult current Google documentation for account-specific quotas and deployment controls. Those limits and access settings can vary. A private ThingSpeak channel needs authorized read access; do not expose a read key in a public Sheet or script. Avoid making an Apps Script endpoint public unless that exposure is acceptable.
Use an explicit spreadsheet schema
Recommended columns are Timestamp, ThingSpeak entry ID, Temperature °C, Humidity %, Temperature °F (if collected), Wi-Fi RSSI (if collected), and Device status (if collected). Preserve the timestamp supplied with the ThingSpeak entry. If the script also records its import time, put that in a separate column; do not assume the ESP32’s local clock is correct.
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Prevent duplicate rows
- Use the ThingSpeak entry ID as the unique key for each row.
- Store the last imported ID in script properties or a dedicated control cell.
- Import only entries with a greater ID, and ignore entries already present when retrying.
- Handle missing fields explicitly and use a consistent timezone convention, preferably UTC.
Do not use spreadsheet row count as the deduplication mechanism: a retry after a partial run can otherwise append the same ThingSpeak entry twice.
Best Value
- 2.4GHz Dual Mode WiFi + Bluetooth Development Board
- Ultra-Low power consumption, works perfectly with the Arduino IDE
- Support LWIP protocol, Freertos
- SupportThree Modes: AP, STA, and AP+STA
- ESP32 is a safe, reliable, and scalable to a variety of applications
When direct ESP32-to-Sheets posting makes sense
An advanced alternative is an ESP32 HTTP POST to a Google Apps Script web app that appends rows directly. It gives more control over columns and formatting, but adds endpoint deployment, authorization, request parsing, quotas, and redeployment as failure points. A public web-app URL is not private merely because it is embedded in firmware. Choose this approach only when spreadsheet-first storage is more important than isolating the device from Google’s deployment and quota behavior.
Improve reliability and protect the data
The example deliberately skips a reading if Wi-Fi is down; it does not buffer and replay it. For a brief demonstration that may be acceptable. If losing measurements matters, queue timestamped readings locally in flash or on microSD and retry later, while designing the upload logic so retries do not create duplicate entries. Add an RTC if accurate timestamps must continue when Internet time is unavailable.
- Keep Wi-Fi credentials and the ThingSpeak write key out of public code and screenshots; rotate exposed keys.
- Reject NaN and out-of-range humidity rather than uploading zero as a substitute. Zero looks like a valid measurement.
- For a larger build, flag sudden jumps or a permanently unchanged reading for review instead of silently treating every numeric value as trustworthy.
- Use one consistent timestamp convention and preserve the server-provided entry time when importing.
Use a DHT outdoors only with protection
A bare indoor DHT module is not an outdoor weather sensor. Rain and condensation can damage it or skew readings, while direct sun and a sealed enclosure can heat the sensor and create a false local climate. For outdoor use, provide ventilation, a radiation shield, protection from water, dust and insects, and suitable UV-resistant materials. Consider cable length and signal quality as well as enclosure heat buildup.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
For actual weather data, add the measurements the DHT cannot provide—such as pressure, wind, and rainfall—and use sensors designed for the exposure. A BME280 can add pressure to temperature and humidity monitoring. ThingSpeak’s weather-station example channel illustrates a channel that includes pressure alongside temperature and humidity; it is an example, not a specification for your hardware.
Quick Recap
Troubleshoot by layer
| Symptom | Checks and recovery |
|---|---|
| No valid sensor readings | Check VCC, GND, the chosen GPIO, and DHTTYPE. Add the pull-up resistor for a bare sensor if required, shorten the cable, and test with a minimal DHT-only sketch. |
| Wi-Fi never connects | Verify SSID and password, test near the access point, and check that the network and ESP32 configuration are compatible. Print connection status and local IP. Keep a timeout so a failed connection does not hang forever. |
| ThingSpeak update fails | Check channel ID and write key, confirm the channel’s update interval has elapsed, and ensure the fields are numeric. Print the returned status and check channel visibility and account limits. |
| Google Sheets contains duplicate rows | Deduplicate on ThingSpeak entry ID and persist the last imported ID; do not rely on row count. |
| Sheets import stops working | Check Apps Script authorization, deployment status, execution identity and access settings, quotas, and execution logs. Confirm the endpoint still accepts the same method and parameter names. |
Possible next steps
- Add a pressure sensor for a more informative weather monitor.
- Add a microSD card for local logging during network outages.
- Add an OLED display, battery-voltage field, or light sensor.
- Use a scheduled importer to create spreadsheet charts and formulas without making Sheets the device’s only backend.
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

