Log the weather to the cloud with ThingSpeak

Send temperature, humidity, light and rain readings to free online charts every five minutes, and let the ESP32 sleep in between so it can run from a power bank.
  • Level:Advanced
  • Duration: 1 h 30 min
  • Ages 13+
  • Platform: ESP32

Tools for this lesson

Helpful for this build. Open a tool to see tips and more projects that use it.

Log the weather to the cloud with ThingSpeak – EEMENTOR STEM™ lesson

A weather station is most useful when it runs for days and you can look at its data from anywhere. In this capstone the ESP32 wakes up every five minutes, measures temperature, humidity, light and rain, sends the four values to ThingSpeak, a free cloud service that draws charts from them, and goes back to sleep. Because it sleeps almost all the time, it uses very little energy. This wake, measure, send, sleep pattern is how most battery-powered IoT sensors work.

What you'll learn

  • How to send data to a cloud service with a web request (HTTP)
  • What an API key is and why you keep it secret
  • How deep sleep works and why it saves so much energy
  • Why some ESP32 analog pins stop working when Wi-Fi is on

What you need

  • ESP32 board, expansion board and USB cable (ESP32 IoT Starter Kit)
  • DHT11 module, KY-015 (ESP32 IoT Starter Kit)
  • Photoresistor module (45-in-1 Sensor Kit)
  • Water level sensor (45-in-1 Sensor Kit), used here as a rain sensor
  • A free ThingSpeak account
  • Optional: a USB power bank
  • Breadboard and jumper wires (ESP32 IoT Starter Kit)
  • A 2.4 GHz Wi-Fi network

Wiring

Breadboard wiring diagram: Log the weather to the cloud with ThingSpeak
Breadboard view. Check each connection against the wiring table below.
From To
DHT11 S (signal) ESP32 GPIO 27
DHT11 + and − 3V3 and GND
Photoresistor module S ESP32 GPIO 34
Photoresistor module + and − 3V3 and GND
Water level sensor S ESP32 GPIO 35
Water level sensor + ESP32 GPIO 32 (powers the sensor only while measuring)
Water level sensor − GND

Sensor modules from different makers can label and order their pins differently. Always follow the labels printed on your module.

The light and rain sensors are on GPIO 34 and 35 on purpose. The ESP32 has two groups of analog pins, and the second group (GPIO 0, 2, 4, 12 to 15 and 25 to 27) can't measure while Wi-Fi is on. GPIO 32 to 39 always work.

Set up ThingSpeak

  1. Go to thingspeak.com and sign up for a free account. It uses a MathWorks account; if you are under the age required by their terms, ask a parent or teacher to create it.
  2. Open Channels → My Channels and click New Channel.
  3. Name it Weather station, tick four fields and name them Temperature, Humidity, Light and Rain. Click Save Channel.
  4. Open the API Keys tab and copy the Write API Key. You need it in the sketch.

Keep your Write API Key secret. Anyone who has it can write data into your channel. Don't post it online or share screenshots of it.

ThingSpeak updates its menus from time to time. If a button has a slightly different name, look for the closest match.

Example screen for: Log the weather to the cloud with ThingSpeak
Example screen with sample values. Yours may look different.

The sketch

Install the DHT sensor library by Adafruit. Put your Wi-Fi details and your Write API Key in the first lines.

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

const char* ssid = "YOUR_WIFI_NAME";
const char* password = "YOUR_WIFI_PASSWORD";
const char* WRITE_API_KEY = "YOUR_WRITE_API_KEY";

const int SLEEP_MINUTES = 5;      // time between two readings

const int DHT_PIN = 27;
const int LIGHT_PIN = 34;
const int RAIN_PIN = 35;
const int RAIN_POWER = 32;

DHT dht(DHT_PIN, DHT11);
RTC_DATA_ATTR int wakeUps = 0;    // this variable survives deep sleep

void goToSleep() {
  Serial.printf("Sleeping for %d minutes\n", SLEEP_MINUTES);
  Serial.flush();
  esp_sleep_enable_timer_wakeup((uint64_t)SLEEP_MINUTES * 60 * 1000000ULL);   // microseconds
  esp_deep_sleep_start();         // the sketch stops here
}

void setup() {
  Serial.begin(115200);
  wakeUps++;
  Serial.printf("\nWake-up number %d\n", wakeUps);

  // 1. Measure
  dht.begin();
  pinMode(RAIN_POWER, OUTPUT);
  delay(2000);                                    // the DHT11 needs 2 s after power-up
  float temperature = dht.readTemperature();
  float humidity = dht.readHumidity();
  int light = map(analogRead(LIGHT_PIN), 0, 4095, 100, 0);   // bright = high %

  digitalWrite(RAIN_POWER, HIGH);                 // power the rain sensor briefly
  delay(100);
  int rain = map(analogRead(RAIN_PIN), 0, 4095, 0, 100);     // wet = high %
  digitalWrite(RAIN_POWER, LOW);

  if (isnan(temperature) || isnan(humidity)) {
    Serial.println("DHT11 error, skipping this reading");
    goToSleep();
  }
  Serial.printf("%.1f C, %.0f %%, light %d %%, rain %d %%\n", temperature, humidity, light, rain);

  // 2. Connect (give up after 15 seconds)
  WiFi.begin(ssid, password);
  unsigned long start = millis();
  while (WiFi.status() != WL_CONNECTED && millis() - start < 15000) delay(250);
  if (WiFi.status() != WL_CONNECTED) {
    Serial.println("No Wi-Fi, skipping this reading");
    goToSleep();
  }

  // 3. Send
  String url = "http://api.thingspeak.com/update?api_key=" + String(WRITE_API_KEY) +
               "&field1=" + String(temperature, 1) +
               "&field2=" + String(humidity, 0) +
               "&field3=" + String(light) +
               "&field4=" + String(rain);
  HTTPClient http;
  http.begin(url);
  int status = http.GET();
  String answer = http.getString();
  http.end();
  Serial.printf("ThingSpeak answered %d, entry number %s\n", status, answer.c_str());

  // 4. Sleep
  goToSleep();
}

void loop() {
  // never reached: after deep sleep the ESP32 starts again from setup()
}

See your charts

  1. Upload the sketch and open the Serial Monitor at 115200 baud. You should see the readings, then "ThingSpeak answered 200, entry number 1".
  2. Open your channel's Private View on thingspeak.com. Four charts appear, with one point each.
  3. Leave the station running. A new point arrives every five minutes.
  4. Drip some water on the lines of the rain sensor and watch the Rain chart at the next reading.
  5. To watch on a phone, open thingspeak.com in the phone's browser and log in, or make the channel public on the Sharing tab and open its public address.

Uploading a new sketch while it sleeps: the ESP32 can't listen to the computer during deep sleep. Press the EN button on the board just after you click Upload, or hold the BOOT button while the IDE shows "Connecting…".

How it works

The ESP32 sends its data with a normal web request, the same thing a browser does when it opens a page. The address contains your key and the four values: …/update?api_key=…&field1=22.5&field2=48…. ThingSpeak stores the values with the current time and answers with the number of the new entry. An answer of 0 means the update was refused, usually because the last one was less than 15 seconds ago, which is the limit for free accounts.

In deep sleep the ESP32 switches off its processor, its Wi-Fi and almost everything else. Only a tiny timer keeps running. When the timer ends, the chip restarts and runs setup() from the first line, which is why all the work is in setup() and loop() stays empty. Normal variables are lost, but a variable marked RTC_DATA_ATTR is kept in a small memory that stays powered, so wakeUps keeps counting.

Awake with Wi-Fi on, the ESP32 chip uses roughly a thousand times more current than asleep. Being awake for about five seconds out of every five minutes cuts the average use to a small fraction. The development board itself still uses some power for its USB chip and power LED, so a board on a power bank won't reach the months of battery life that purpose-built sensors get, but the idea is the same.

The sensors are read before Wi-Fi starts. That keeps the time with Wi-Fi on as short as possible.

Try this next

  • Add the DS18B20 as a fifth field for an outdoor temperature.
  • Send wakeUps as a field. A sudden drop back to 1 shows that the power was interrupted.
  • In ThingSpeak, add a Gauge or Numeric Display widget to your channel view.
  • Change SLEEP_MINUTES to 15 and compare how long a power bank lasts.

Troubleshooting

  • It never connects to Wi-Fi: check the network name and password (both are case-sensitive) and make sure the network is 2.4 GHz. The ESP32 can't use 5 GHz networks.
  • "ThingSpeak answered 200, entry number 0": you sent two updates less than 15 seconds apart, or the Write API Key is wrong.
  • "ThingSpeak answered -1": the ESP32 has Wi-Fi but can't reach the internet. Try another network or a phone hotspot.
  • The upload fails with "Failed to connect": the board is asleep. Press EN just after clicking Upload, or hold BOOT while the IDE connects.
  • The power bank switches itself off: many power banks turn off when the current is very low. Use one with a "low current" or "always on" mode, or shorten the sleep time.
  • The light value is the wrong way round: swap 100, 0 to 0, 100 in the light line.

Build it yourself

Everything used in this lesson comes in one kit, with parts tested by our engineers.

ESP32 IoT Starter Kit | Arduino IDE Compatible | Free Tutorials $57.00

Shop the kit