IoT Weather Station with Cloud Integration

 


Amazing Features:

Sensors (6 Total):

  •  DHT22 - Temperature & Humidity
  •  BMP280 - Pressure & Altitude
  •  Light Sensor - Brightness level (0-100%)
  •  Rain Sensor - Precipitation detection
  •  OLED Display - Real-time local display
  •  Status LED - Activity indicator
CODE:
/*
 * ESP32 IoT Weather Station with Cloud Integration
 * Features:
 * - DHT22 Temperature & Humidity Sensor
 * - BMP280 Pressure & Altitude Sensor
 * - LDR Light Sensor
 * - Rain Detection Sensor
 * - OLED Display for local readings
 * - Web Dashboard
 * - ThingSpeak Cloud Integration
 * - Data Logging & Visualization
 * - Real-time Updates
 */

#include <WiFi.h>
#include <WebServer.h>
#include <HTTPClient.h>
#include <DHT.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_BMP280.h>

// WiFi Credentials
const char* ssid = "Wokwi-GUEST";
const char* password = "";

// ThingSpeak Settings
const char* thingSpeakServer = "api.thingspeak.com";
String thingSpeakAPIKey = "01PCHXCFEQN5RXS5"; // Replace with your ThingSpeak Write API Key
const long thingSpeakChannel = 3254641; // Replace with your channel number

// Pin Definitions
#define DHT_PIN 15
#define LDR_PIN 34      // Analog pin for light sensor
#define RAIN_PIN 35     // Analog pin for rain sensor
#define LED_PIN 2       // Built-in LED for status

// DHT Sensor Setup
#define DHT_TYPE DHT22
DHT dht(DHT_PIN, DHT_TYPE);

// BMP280 Pressure Sensor Setup
Adafruit_BMP280 bmp;

// OLED Display Setup
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// Web Server
WebServer server(80);

// Weather Data Structure
struct WeatherData {
  float temperature;
  float humidity;
  float pressure;
  float altitude;
  int lightLevel;
  int rainLevel;
  String weatherCondition;
  unsigned long timestamp;
};

WeatherData currentWeather;

// Timing variables
unsigned long lastSensorRead = 0;
unsigned long lastCloudUpload = 0;
const long sensorInterval = 2000;      // Read sensors every 2 seconds
const long cloudUploadInterval = 20000; // Upload to cloud every 20 seconds

// Data arrays for graphing
const int maxDataPoints = 50;
float tempHistory[50];
float humidityHistory[50];
int dataIndex = 0;

// Status variables
bool cloudConnected = false;
int uploadCount = 0;

void setup() {
  Serial.begin(115200);
 
  // Initialize pins
  pinMode(LED_PIN, OUTPUT);
  pinMode(LDR_PIN, INPUT);
  pinMode(RAIN_PIN, INPUT);
 
  // Initialize DHT sensor
  dht.begin();
 
  // Initialize BMP280
  if (!bmp.begin(0x76)) {
    Serial.println("Could not find BMP280 sensor!");
  } else {
    Serial.println("BMP280 initialized successfully");
    // Configure BMP280
    bmp.setSampling(Adafruit_BMP280::MODE_NORMAL,
                    Adafruit_BMP280::SAMPLING_X2,
                    Adafruit_BMP280::SAMPLING_X16,
                    Adafruit_BMP280::FILTER_X16,
                    Adafruit_BMP280::STANDBY_MS_500);
  }
 
  // Initialize OLED display
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("SSD1306 allocation failed"));
  } else {
    display.clearDisplay();
    display.setTextSize(1);
    display.setTextColor(SSD1306_WHITE);
    display.setCursor(0, 0);
    display.println("Weather Station");
    display.println("Initializing...");
    display.display();
    delay(2000);
  }
 
  // Connect to WiFi
  connectWiFi();
 
  // Setup web server routes
  server.on("/", handleRoot);
  server.on("/data", handleData);
  server.on("/history", handleHistory);
  server.on("/api/weather", handleAPIWeather);
 
  server.begin();
  Serial.println("HTTP server started");
 
  // Initial sensor read
  readSensors();
  updateDisplay();
 
  Serial.println("\n=== Weather Station Ready ===");
  Serial.println("Features:");
  Serial.println("- Local Web Dashboard");
  Serial.println("- Cloud Data Logging");
  Serial.println("- Real-time Monitoring");
  Serial.println("=============================\n");
}

void loop() {
  server.handleClient();
 
  unsigned long currentMillis = millis();
 
  // Read sensors periodically
  if (currentMillis - lastSensorRead >= sensorInterval) {
    lastSensorRead = currentMillis;
    readSensors();
    updateDisplay();
    blinkLED();
  }
 
  // Upload to cloud periodically
  if (currentMillis - lastCloudUpload >= cloudUploadInterval) {
    lastCloudUpload = currentMillis;
    uploadToCloud();
  }
}

void connectWiFi() {
  WiFi.begin(ssid, password);
  Serial.print("Connecting to WiFi");
 
  display.clearDisplay();
  display.setCursor(0, 0);
  display.println("Connecting WiFi...");
  display.display();
 
  int attempts = 0;
  while (WiFi.status() != WL_CONNECTED && attempts < 20) {
    delay(500);
    Serial.print(".");
    attempts++;
  }
 
  if (WiFi.status() == WL_CONNECTED) {
    Serial.println("\nWiFi connected");
    Serial.print("IP address: ");
    Serial.println(WiFi.localIP());
   
    display.clearDisplay();
    display.setCursor(0, 0);
    display.println("WiFi Connected!");
    display.print("IP: ");
    display.println(WiFi.localIP());
    display.display();
    delay(2000);
  } else {
    Serial.println("\nWiFi connection failed");
  }
}

void readSensors() {
  // Read DHT22
  currentWeather.temperature = dht.readTemperature();
  currentWeather.humidity = dht.readHumidity();
 
  // Read BMP280
  currentWeather.pressure = bmp.readPressure() / 100.0F; // Convert to hPa
  currentWeather.altitude = bmp.readAltitude(1013.25); // Sea level pressure
 
  // Read LDR (Light sensor)
  int ldrValue = analogRead(LDR_PIN);
  currentWeather.lightLevel = map(ldrValue, 0, 4095, 0, 100);
 
  // Read Rain sensor
  int rainValue = analogRead(RAIN_PIN);
  currentWeather.rainLevel = map(rainValue, 0, 4095, 100, 0); // Inverted
 
  // Timestamp
  currentWeather.timestamp = millis();
 
  // Determine weather condition
  currentWeather.weatherCondition = determineWeatherCondition();
 
  // Check for errors
  if (isnan(currentWeather.temperature) || isnan(currentWeather.humidity)) {
    Serial.println("Failed to read from DHT sensor!");
    currentWeather.temperature = 0;
    currentWeather.humidity = 0;
  }
 
  // Store in history
  tempHistory[dataIndex] = currentWeather.temperature;
  humidityHistory[dataIndex] = currentWeather.humidity;
  dataIndex = (dataIndex + 1) % maxDataPoints;
 
  // Print to Serial
  printWeatherData();
}

String determineWeatherCondition() {
  String condition = "Unknown";
 
  if (currentWeather.rainLevel > 60) {
    condition = "Rainy";
  } else if (currentWeather.rainLevel > 30) {
    condition = "Drizzle";
  } else if (currentWeather.humidity > 80) {
    condition = "Humid";
  } else if (currentWeather.lightLevel < 20) {
    condition = "Cloudy";
  } else if (currentWeather.lightLevel > 80) {
    condition = "Sunny";
  } else if (currentWeather.temperature > 30) {
    condition = "Hot";
  } else if (currentWeather.temperature < 15) {
    condition = "Cold";
  } else {
    condition = "Clear";
  }
 
  return condition;
}

void printWeatherData() {
  Serial.println("\n=== Weather Data ===");
  Serial.print("Temperature: "); Serial.print(currentWeather.temperature); Serial.println(" °C");
  Serial.print("Humidity: "); Serial.print(currentWeather.humidity); Serial.println(" %");
  Serial.print("Pressure: "); Serial.print(currentWeather.pressure); Serial.println(" hPa");
  Serial.print("Altitude: "); Serial.print(currentWeather.altitude); Serial.println(" m");
  Serial.print("Light Level: "); Serial.print(currentWeather.lightLevel); Serial.println(" %");
  Serial.print("Rain Level: "); Serial.print(currentWeather.rainLevel); Serial.println(" %");
  Serial.print("Condition: "); Serial.println(currentWeather.weatherCondition);
  Serial.println("===================\n");
}

void updateDisplay() {
  display.clearDisplay();
  display.setTextSize(1);
  display.setCursor(0, 0);
 
  // Title
  display.setTextSize(1);
  display.println("WEATHER STATION");
  display.drawLine(0, 9, 128, 9, SSD1306_WHITE);
 
  // Temperature
  display.setCursor(0, 12);
  display.print("Temp: ");
  display.print(currentWeather.temperature, 1);
  display.println(" C");
 
  // Humidity
  display.setCursor(0, 22);
  display.print("Humid: ");
  display.print(currentWeather.humidity, 1);
  display.println(" %");
 
  // Pressure
  display.setCursor(0, 32);
  display.print("Press: ");
  display.print(currentWeather.pressure, 0);
  display.println("hPa");
 
  // Light & Rain
  display.setCursor(0, 42);
  display.print("Light: ");
  display.print(currentWeather.lightLevel);
  display.print("% ");
 
  // Condition
  display.setCursor(0, 52);
  display.setTextSize(1);
  display.print("Status: ");
  display.println(currentWeather.weatherCondition);
 
  display.display();
}

void uploadToCloud() {
  if (WiFi.status() != WL_CONNECTED) {
    Serial.println("WiFi not connected. Skipping cloud upload.");
    cloudConnected = false;
    return;
  }
 
  HTTPClient http;
 
  // Build ThingSpeak URL
  String url = "http://" + String(thingSpeakServer) + "/update?api_key=" + thingSpeakAPIKey;
  url += "&field1=" + String(currentWeather.temperature);
  url += "&field2=" + String(currentWeather.humidity);
  url += "&field3=" + String(currentWeather.pressure);
  url += "&field4=" + String(currentWeather.lightLevel);
  url += "&field5=" + String(currentWeather.rainLevel);
  url += "&field6=" + String(currentWeather.altitude);
 
  Serial.println("Uploading to ThingSpeak...");
  Serial.println(url);
 
  http.begin(url);
  int httpCode = http.GET();
 
  if (httpCode > 0) {
    String payload = http.getString();
    Serial.print("HTTP Response: ");
    Serial.println(httpCode);
    Serial.print("Payload: ");
    Serial.println(payload);
   
    if (httpCode == 200) {
      cloudConnected = true;
      uploadCount++;
      Serial.println("✓ Data uploaded successfully to cloud!");
      Serial.print("Total uploads: ");
      Serial.println(uploadCount);
    }
  } else {
    Serial.print("HTTP Error: ");
    Serial.println(http.errorToString(httpCode));
    cloudConnected = false;
  }
 
  http.end();
}

void blinkLED() {
  digitalWrite(LED_PIN, HIGH);
  delay(50);
  digitalWrite(LED_PIN, LOW);
}

// Web Server Handlers
void handleRoot() {
  String html = "<!DOCTYPE html><html><head>";
  html += "<meta name='viewport' content='width=device-width, initial-scale=1.0'>";
  html += "<meta http-equiv='refresh' content='5'>"; // Auto refresh every 5 seconds
  html += "<style>";
  html += "body { font-family: Arial; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); margin: 0; padding: 20px; color: white; }";
  html += ".container { max-width: 900px; margin: 0 auto; }";
  html += "h1 { text-align: center; font-size: 2.5em; margin-bottom: 10px; text-shadow: 2px 2px 4px rgba(0,0,0,0.3); }";
  html += ".subtitle { text-align: center; font-size: 1.2em; margin-bottom: 30px; opacity: 0.9; }";
  html += ".grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 20px; margin-bottom: 20px; }";
  html += ".card { background: rgba(255,255,255,0.15); backdrop-filter: blur(10px); padding: 20px; border-radius: 15px; box-shadow: 0 8px 32px rgba(0,0,0,0.1); border: 1px solid rgba(255,255,255,0.18); }";
  html += ".card h3 { margin: 0 0 10px 0; font-size: 1.1em; opacity: 0.8; }";
  html += ".value { font-size: 2.5em; font-weight: bold; margin: 10px 0; }";
  html += ".unit { font-size: 0.6em; opacity: 0.8; }";
  html += ".icon { font-size: 2em; margin-bottom: 10px; }";
  html += ".status { text-align: center; background: rgba(255,255,255,0.2); padding: 15px; border-radius: 10px; margin-top: 20px; }";
  html += ".cloud-status { display: inline-block; padding: 5px 15px; border-radius: 20px; margin: 10px; font-size: 0.9em; }";
  html += ".connected { background: #4CAF50; }";
  html += ".disconnected { background: #f44336; }";
  html += ".weather-condition { font-size: 1.5em; margin: 10px 0; }";
  html += "@media (max-width: 600px) { .grid { grid-template-columns: 1fr; } }";
  html += "</style></head><body>";
  html += "<div class='container'>";
  html += "<h1>🌤️ IoT Weather Station</h1>";
  html += "<div class='subtitle'>Real-time Environmental Monitoring</div>";
 
  // Weather Condition Card
  html += "<div class='card' style='text-align: center; background: rgba(255,255,255,0.25);'>";
  html += "<div class='weather-condition'>" + getWeatherIcon() + " " + currentWeather.weatherCondition + "</div>";
  html += "</div>";
 
  // Sensor Grid
  html += "<div class='grid'>";
 
  // Temperature
  html += "<div class='card'>";
  html += "<div class='icon'>🌡️</div>";
  html += "<h3>Temperature</h3>";
  html += "<div class='value'>" + String(currentWeather.temperature, 1) + "<span class='unit'>°C</span></div>";
  html += "</div>";
 
  // Humidity
  html += "<div class='card'>";
  html += "<div class='icon'>💧</div>";
  html += "<h3>Humidity</h3>";
  html += "<div class='value'>" + String(currentWeather.humidity, 1) + "<span class='unit'>%</span></div>";
  html += "</div>";
 
  // Pressure
  html += "<div class='card'>";
  html += "<div class='icon'>🎚️</div>";
  html += "<h3>Pressure</h3>";
  html += "<div class='value'>" + String(currentWeather.pressure, 0) + "<span class='unit'>hPa</span></div>";
  html += "</div>";
 
  // Altitude
  html += "<div class='card'>";
  html += "<div class='icon'>⛰️</div>";
  html += "<h3>Altitude</h3>";
  html += "<div class='value'>" + String(currentWeather.altitude, 0) + "<span class='unit'>m</span></div>";
  html += "</div>";
 
  // Light
  html += "<div class='card'>";
  html += "<div class='icon'>☀️</div>";
  html += "<h3>Light Level</h3>";
  html += "<div class='value'>" + String(currentWeather.lightLevel) + "<span class='unit'>%</span></div>";
  html += "</div>";
 
  // Rain
  html += "<div class='card'>";
  html += "<div class='icon'>🌧️</div>";
  html += "<h3>Rain Level</h3>";
  html += "<div class='value'>" + String(currentWeather.rainLevel) + "<span class='unit'>%</span></div>";
  html += "</div>";
 
  html += "</div>";
 
  // Status
  html += "<div class='status'>";
  html += "<p><strong>Station Status</strong></p>";
  html += "<span class='cloud-status " + String(cloudConnected ? "connected" : "disconnected") + "'>";
  html += cloudConnected ? "☁️ Cloud Connected" : "☁️ Cloud Offline";
  html += "</span>";
  html += "<span class='cloud-status connected'>📡 WiFi: " + WiFi.localIP().toString() + "</span>";
  html += "<p style='margin-top: 10px; font-size: 0.9em;'>Uploads: " + String(uploadCount) + " | Uptime: " + String(millis()/1000) + "s</p>";
  html += "</div>";
 
  html += "</div></body></html>";
 
  server.send(200, "text/html", html);
}

String getWeatherIcon() {
  if (currentWeather.weatherCondition == "Rainy") return "🌧️";
  if (currentWeather.weatherCondition == "Drizzle") return "🌦️";
  if (currentWeather.weatherCondition == "Sunny") return "☀️";
  if (currentWeather.weatherCondition == "Cloudy") return "☁️";
  if (currentWeather.weatherCondition == "Hot") return "🔥";
  if (currentWeather.weatherCondition == "Cold") return "❄️";
  return "🌤️";
}

void handleData() {
  String json = "{";
  json += "\"temperature\":" + String(currentWeather.temperature, 2) + ",";
  json += "\"humidity\":" + String(currentWeather.humidity, 2) + ",";
  json += "\"pressure\":" + String(currentWeather.pressure, 2) + ",";
  json += "\"altitude\":" + String(currentWeather.altitude, 2) + ",";
  json += "\"light\":" + String(currentWeather.lightLevel) + ",";
  json += "\"rain\":" + String(currentWeather.rainLevel) + ",";
  json += "\"condition\":\"" + currentWeather.weatherCondition + "\",";
  json += "\"timestamp\":" + String(currentWeather.timestamp) + ",";
  json += "\"cloudConnected\":" + String(cloudConnected ? "true" : "false");
  json += "}";
 
  server.send(200, "application/json", json);
}

void handleHistory() {
  String json = "{\"temperature\":[";
  for (int i = 0; i < maxDataPoints; i++) {
    json += String(tempHistory[i], 1);
    if (i < maxDataPoints - 1) json += ",";
  }
  json += "],\"humidity\":[";
  for (int i = 0; i < maxDataPoints; i++) {
    json += String(humidityHistory[i], 1);
    if (i < maxDataPoints - 1) json += ",";
  }
  json += "]}";
 
  server.send(200, "application/json", json);
}

void handleAPIWeather() {
  handleData(); // Same as /data endpoint
}

Smart Features:

  •  ThingSpeak Cloud integration (auto-upload every 20s)
  •  Beautiful Web Dashboard with auto-refresh
  •  Data History tracking (50 points)
  •  Auto Weather Detection (Sunny/Rainy/Cloudy/etc.)
  •  RESTful API endpoints (JSON data)
  •  Responsive Design for mobile/desktop

Quick Start (3 Steps):

  1. Go to wokwi.com → New ESP32 Project
  2. Copy the code from weather_station.ino
  3. Paste diagram.json → Click "Start Simulation"
  4. Click the IP address in Serial Monitor to see dashboard!
Diagram.json:
{
  "version": 1,
  "author": "ESP32 IoT Weather Station",
  "editor": "wokwi",
  "parts": [
    {
      "type": "wokwi-esp32-devkit-v1",
      "id": "esp",
      "top": 0,
      "left": 0,
      "attrs": {}
    },
    {
      "type": "wokwi-dht22",
      "id": "dht1",
      "top": -86.4,
      "left": 143.4,
      "attrs": { "temperature": "24", "humidity": "60" }
    },
    {
      "type": "wokwi-bmp280",
      "id": "bmp1",
      "top": -105.6,
      "left": 249.6,
      "attrs": { "i2cAddress": "0x76" }
    },
    {
      "type": "wokwi-ssd1306",
      "id": "oled1",
      "top": 144,
      "left": 288,
      "attrs": { "i2cAddress": "0x3C" }
    },
    {
      "type": "wokwi-potentiometer",
      "id": "ldr1",
      "top": -19.2,
      "left": 364.8,
      "rotate": 180,
      "attrs": { "label": "Light Sensor" }
    },
    {
      "type": "wokwi-potentiometer",
      "id": "rain1",
      "top": 96,
      "left": 364.8,
      "rotate": 180,
      "attrs": { "label": "Rain Sensor" }
    },
    {
      "type": "wokwi-led",
      "id": "led1",
      "top": -124.8,
      "left": 470.4,
      "attrs": { "color": "blue", "lightColor": "blue" }
    },
    {
      "type": "wokwi-resistor",
      "id": "r1",
      "top": -67.2,
      "left": 470.4,
      "rotate": 90,
      "attrs": { "value": "220" }
    }
  ],
  "connections": [
    [ "esp:TX0", "$serialMonitor:RX", "", [] ],
    [ "esp:RX0", "$serialMonitor:TX", "", [] ],
   
    [ "dht1:VCC", "esp:3V3", "red", [ "v0" ] ],
    [ "dht1:GND", "esp:GND.1", "black", [ "v0" ] ],
    [ "dht1:SDA", "esp:D15", "green", [ "v0" ] ],
   
    [ "bmp1:VCC", "esp:3V3", "red", [ "v0" ] ],
    [ "bmp1:GND", "esp:GND.1", "black", [ "v0" ] ],
    [ "bmp1:SDA", "esp:D21", "blue", [ "v0" ] ],
    [ "bmp1:SCL", "esp:D22", "yellow", [ "v0" ] ],
   
    [ "oled1:VCC", "esp:3V3", "red", [ "h0" ] ],
    [ "oled1:GND", "esp:GND.2", "black", [ "h0" ] ],
    [ "oled1:SDA", "esp:D21", "blue", [ "h0" ] ],
    [ "oled1:SCL", "esp:D22", "yellow", [ "h0" ] ],
   
    [ "ldr1:GND", "esp:GND.1", "black", [ "v0" ] ],
    [ "ldr1:VCC", "esp:3V3", "red", [ "v0" ] ],
    [ "ldr1:SIG", "esp:D34", "orange", [ "v0" ] ],
   
    [ "rain1:GND", "esp:GND.2", "black", [ "v0" ] ],
    [ "rain1:VCC", "esp:3V3", "red", [ "v0" ] ],
    [ "rain1:SIG", "esp:D35", "purple", [ "v0" ] ],
   
    [ "led1:A", "esp:D2", "blue", [ "v0" ] ],
    [ "led1:C", "r1:1", "blue", [ "v0" ] ],
    [ "r1:2", "esp:GND.1", "black", [ "v0" ] ]
  ],
  "dependencies": {}
}

 Optional Cloud Setup:

  1. Create free ThingSpeak account at thingspeak.com
  2. Create channel with 6 fields (Temperature, Humidity, Pressure, Light, Rain, Altitude)
  3. Copy your Write API Key
  4. Update in code:
String thingSpeakAPIKey = "YOUR_KEY_HERE";

 Interactive Testing:



  • Adjust DHT22 slider → Watch temp/humidity change
  • Rotate Light Sensor knob → See brightness levels
  • Rotate Rain Sensor knob → Trigger rainy condition
  • Watch OLED → Real-time local display
  • Open Web Dashboard → Beautiful gradient UI with all data!

The web dashboard auto-refreshes every 5 seconds and shows real-time weather conditions with emoji icons! 


ThingSpeak Cloud Setup Guide

Complete step-by-step guide to integrate your ESP32 Weather Station with ThingSpeak cloud platform.

 What is ThingSpeak?

ThingSpeak is a free IoT platform by MathWorks that allows you to:

- Collect sensor data in the cloud

- Visualize data with charts

- Analyze data with MATLAB

- Create alerts and notifications

- Share data publicly or privately

- Access data via RESTful API

Prerequisites

- ThingSpeak account (free)

- ESP32 Weather Station running

- Internet connection

- Valid email address

  Step-by-Step Setup

 Step 1: Create ThingSpeak Account

1. Go to https://thingspeak.com

2. Click **"Get Started For Free"**

3. Sign up with your email or MathWorks account

4. Verify your email address

5. Log in to your account

Step 2: Create a New Channel

1. Click **"Channels"** in the top menu

2. Click **"My Channels"**

3. Click **"New Channel"** button

4. Fill in the channel information:

 Channel Settings:

Name: ESP32 Weather Station

Description: IoT Weather monitoring with temperature, humidity, pressure, light, and rain sensors

☑ Field 1: Temperature

☑ Field 2: Humidity

☑ Field 3: Pressure

☑ Field 4: Light Level

☑ Field 5: Rain Level

☑ Field 6: Altitude

Field 7: (leave blank)

Field 8: (leave blank)

5. Click **"Save Channel"**

Step 3: Get Your API Keys

1. Go to your channel page

2. Click **"API Keys"** tab

3. You'll see two important keys:

Write API Key:

Example: XXXXXXXXXXXXXXXX

This key allows your ESP32 to send data to ThingSpeak.

Read API Key:

Example: YYYYYYYYYYYYYYYY

This key allows reading data from your channel.

Step 4: Configure ESP32 Code

Open your `weather_station.ino` file and update:

ThingSpeak Settings

String thingSpeakAPIKey = "XXXXXXXXXXXXXXXX"; // Your Write API Key

const long thingSpeakChannel = 123456; // Your Channel ID

Where to find Channel ID:

- It's shown at the top of your channel page

- Example: Channel ID: 123456

Step 5: Upload and Test

1. Upload the modified code to your ESP32 (or restart Wokwi simulation)

2. Open Serial Monitor

3. Wait for WiFi connection

4. Look for upload messages:

Uploading to ThingSpeak...

HTTP Response: 200

✓ Data uploaded successfully to cloud!

Total uploads: 1

Step 6: View Your Data

1. Go to ThingSpeak.com

2. Click **"Channels"** → **"My Channels"**

3. Click on your **"ESP32 Weather Station"** channel

4. You should see your data appearing in charts!

Comments