Blueprint

ESP32 Weather Station

A smart esp32 weather station to calculate temp and humidity using sensors and showing the data on a webpage also a OLED display to show the same data and ip of the website.

Created by Saurabh Saurabh 🚀

Tier 4

33 views

1 follower

Timeline

CAN CAN ⚡🚀 approved ESP32 Weather Station ago

Tickets awarded: 70 tickets

Tier: 4

CAN CAN ⚡🚀 submitted ESP32 Weather Station for review ago

Saurabh Saurabh 🚀 submitted ESP32 Weather Station for review ago

Saurabh Saurabh 🚀 added to the journal ago

Completed Documentation and finalized the project

Bill Of Material and Documentation

So this project is finally complete i created the BOM.csv and BOM-International.csv the cost of this project came to be about 7.5 to 20 dollars based on where you live.

also completed the readme you can visit the repo at LINK

image

Saurabh Saurabh 🚀 added to the journal ago

Final Weather Station and Web Dashboard Build

ESP32 Weather Station Completed

Alright so ig this is it GOT EVERYTHING WORKING TOGETHER finally phew the ESP32 runs a web server now and hosts a web dashboard (more on that later) that shows live temperature and humidity from the DHT11 sensor Also the OLED display shows the temp and humidity data as well along wiht the IP address of the website.

weatherstation2

Wiring

So heres how everything connects together (pretty simple honestly also the images wires were changed in between)

DHT11 Sensor

  • VCC - 3.3V
  • DATA - GPIO 18
  • GND - GND

OLED Display (I2C)

  • VCC - 3.3V
  • GND - GND
  • SDA - GPIO 21
  • SCL - GPIO 22

How It Actually Works

So the ESP32 connects to WiFi first and starts a web server Every 2 seconds it reads the DHT11 and updates the OLED display and stores the values When you go to the IP address on your phone or laptop you get this clean dashboard that refreshes itself every 3 seconds.

displayoutput

The server has two endpoints

  • / serves the HTML dashboard
  • /data returns JSON so the frontend can fetch new readings

The Dashboard

so i went with a super minimal look black background white text Poppins font No emojis no gradients no colors just clean boxes with simple SVG icons (idk fontawesome cdn was not working) Looks good on mobile too!!!

webpage

The Code

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

const char* ssid = "YourWifiNameHereIAintGivingMine";
const char* password = "idkmansomelameahhpassword";

#define DHTPIN 18
#define DHTTYPE DHT11
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#define SCREEN_ADDRESS 0x3C

DHT dht(DHTPIN, DHTTYPE);
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
WebServer server(80);

float temperature = 0;
float humidity = 0;
unsigned long lastRead = 0;
const long readInterval = 2000;

const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Weather Station</title>
  <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap" rel="stylesheet">
  <style>
    * { margin: 0; padding: 0; box-sizing: border-box; }
    body {
      font-family: 'Poppins', sans-serif;
      background: #000;
      min-height: 100vh;
      color: #fff;
      padding: 40px 20px;
    }
    .container { max-width: 720px; margin: 0 auto; }
    header { text-align: center; margin-bottom: 60px; }
    h1 { font-size: 1.5rem; font-weight: 600; letter-spacing: -0.5px; margin-bottom: 8px; }
    .status { font-size: 0.75rem; color: #666; font-weight: 300; }
    .status span { color: #fff; }
    .cards { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }
    @media (max-width: 500px) { .cards { grid-template-columns: 1fr; } }
    .card {
      border: 1px solid #222;
      padding: 40px 30px;
      text-align: center;
    }
    .card-icon { margin-bottom: 20px; }
    .card-icon svg { width: 32px; height: 32px; stroke: #fff; fill: none; stroke-width: 1.5; }
    .card-label {
      font-size: 0.7rem;
      text-transform: uppercase;
      letter-spacing: 2px;
      color: #666;
      margin-bottom: 12px;
      font-weight: 400;
    }
    .card-value { font-size: 3rem; font-weight: 300; }
    .card-unit { font-size: 1rem; color: #666; margin-left: 4px; font-weight: 300; }
    .update {
      text-align: center;
      margin-top: 40px;
      font-size: 0.7rem;
      color: #444;
      font-weight: 300;
    }
    footer {
      text-align: center;
      margin-top: 60px;
      font-size: 0.7rem;
      color: #333;
      font-weight: 300;
    }
  </style>
</head>
<body>
  <div class="container">
    <header>
      <h1>Weather Station</h1>
      <p class="status">ESP32 <span>Online</span></p>
    </header>
    <div class="cards">
      <div class="card">
        <div class="card-icon">
          <svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
            <path d="M12 2v20M12 2a4 4 0 0 1 4 4v10a4 4 0 1 1-8 0V6a4 4 0 0 1 4-4z"/>
            <circle cx="12" cy="16" r="2"/>
          </svg>
        </div>
        <div class="card-label">Temperature</div>
        <div class="card-value"><span id="temp">--</span><span class="card-unit">C</span></div>
      </div>
      <div class="card">
        <div class="card-icon">
          <svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
            <path d="M12 2v6M12 22a6 6 0 1 1 0-12 6 6 0 0 1 0 12z"/>
            <path d="M12 8a6 6 0 0 0-6 6c0 3.3 2.7 6 6 6"/>
          </svg>
        </div>
        <div class="card-label">Humidity</div>
        <div class="card-value"><span id="humid">--</span><span class="card-unit">%</span></div>
      </div>
    </div>
    <p class="update">Updated <span id="time">--</span></p>
    <footer>Saurabh / Hack Club Blueprint</footer>
  </div>
  <script>
    async function fetchData() {
      try {
        const r = await fetch('/data');
        const d = await r.json();
        document.getElementById('temp').textContent = d.temperature.toFixed(1);
        document.getElementById('humid').textContent = d.humidity.toFixed(1);
        document.getElementById('time').textContent = new Date().toLocaleTimeString();
      } catch (e) { console.error(e); }
    }
    fetchData();
    setInterval(fetchData, 3000);
  </script>
</body>
</html>
)rawliteral";

void updateDisplay() {
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(20, 0);
  display.println("WEATHER STATION");
  display.drawLine(0, 10, 128, 10, SSD1306_WHITE);
  display.setTextSize(1);
  display.setCursor(0, 18);
  display.print("Temp:");
  display.setTextSize(2);
  display.setCursor(40, 15);
  display.print(temperature, 1);
  display.setTextSize(1);
  display.print(" C");
  display.setTextSize(1);
  display.setCursor(0, 40);
  display.print("Humid:");
  display.setTextSize(2);
  display.setCursor(40, 37);
  display.print(humidity, 1);
  display.setTextSize(1);
  display.print(" %");
  display.setTextSize(1);
  display.setCursor(0, 56);
  display.print("IP:");
  display.print(WiFi.localIP());
  display.display();
}

void readSensor() {
  float h = dht.readHumidity();
  float t = dht.readTemperature();

  if (!isnan(h) && !isnan(t)) {
    humidity = h;
    temperature = t;
    Serial.printf("Temp: %.1f°C | Humidity: %.1f%%\n", temperature, humidity);
  } else {
    Serial.println("DHT11 read failed!");
  }
}

void handleRoot() {
  server.send(200, "text/html", index_html);
}

void handleData() {
  String json = "{\"temperature\":" + String(temperature) + 
                ",\"humidity\":" + String(humidity) + "}";
  server.send(200, "application/json", json);
}
void setup() {
  Serial.begin(115200);
  Serial.println("\n=== ESP32 Weather Station ===");
  dht.begin();
  Serial.println("DHT11 initialized");
  if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    Serial.println("OLED failed!");
    while (1);
  }
  display.clearDisplay();
  display.setTextColor(SSD1306_WHITE);
  display.setTextSize(1);
  display.setCursor(10, 25);
  display.println("Connecting WiFi...");
  display.display();
  Serial.println("OLED initialized");
  WiFi.begin(ssid, password);
  Serial.print("Connecting to WiFi");

  int attempts = 0;
  while (WiFi.status() != WL_CONNECTED && attempts < 30) {
    delay(500);
    Serial.print(".");
    attempts++;
  }

  if (WiFi.status() == WL_CONNECTED) {
    Serial.println("\nWiFi connected!");
    Serial.print("IP Address: ");
    Serial.println(WiFi.localIP());
  } else {
    Serial.println("\nWiFi connection failed!");
  }
  server.on("/", handleRoot);
  server.on("/data", handleData);
  server.begin();
  Serial.println("Web server started");
  readSensor();
  updateDisplay();
}

void loop() {
  server.handleClient();
  if (millis() - lastRead >= readInterval) {
    lastRead = millis();
    readSensor();
    updateDisplay();
  }
}

weatherstation1

Full code is on the GitHub repo in main.ino

Libraries

  • WiFi.h and WebServer.h (built into ESP32)
  • DHT.h from Adafruit
  • Adafruit_GFX.h
  • Adafruit_SSD1306.h

Saurabh Saurabh 🚀 added to the journal ago

Tried Motion Detection Using PIR Motion Sensor (Failed)

HC-SR501 PIR Motion Sensor Test with ESP32

So i was waiting for all my stuff to arrive and now that i have it i started working on testing them the PIR motion sensor which is a mojor part of our project which will help us reduce the risk of damaging our OLED 0.96inch display from screenburn and only show the data when there is a motion on it like waving a hand otherwise just black screen.

The Test Setup

So i took my ESP 32 (im adding the pinouts and the real image just so you could understand it better)


pinoutspirtest1

and my PIR Sensor (which came with BROKEN PINS and NO LABELS FOR THE PINS)


pirtest3pirtest2


Um as we can see there are no labels or prints on the board about the pinouts like what is the VCC? Or Ground? i had no idea so this was a guessing game for me i tried All the Combinations
(we know that data is most prob the middle one)

  • VCC Data GND
  • GND Data VCC

The connections were on 3.3V it read No Motion on my simple test code


pirtest4


Code

#define PIR_PIN 18

void setup() {
  Serial.begin(115200);
  pinMode(PIR_PIN, INPUT);
  Serial.println("Wait 30–60s");
}

void loop() {
  int motion = digitalRead(PIR_PIN);

  if (motion) {
    Serial.println("MOTION!");
  } else {
    Serial.println("No motion");
  }

  delay(300);
}


Switching from 3.3V to 5.0V

yeah so i thought lets switch to VIN (5V) AND IT WAS ALWAYS HIGH Like MOTION DETECTED spam on the serial monitor i searched for a bit and found this
pirtest5

PIR Sensor Pinouts


image


And now it was clear that the pins are broken and there is some problem with the connections too I'm really frustrated right now and i might not use the motion sensors!

Saurabh Saurabh 🚀 added to the journal ago

Tested the DHT11 Sensor

DHT 11 Temperature and Humidity Sensor Test

So i was wondering if the sensor even actually work i tried to code a simple script to display the data from the sensor to the serial monitor of Arduino IDE the code is in Firmware/dht11test.ino in the github repository here is the code with the image

Code

#include <DHT.h>

// Pin and sensor type
#define DHTPIN 18        // GPIO 18 on ESP32
#define DHTTYPE DHT11    // DHT11 sensor

DHT dht(DHTPIN, DHTTYPE);

void setup() {
  Serial.begin(115200);
  Serial.println("DHT11 Sensor Test with ESP32 (GPIO 18)");
  dht.begin();
}

void loop() {
  delay(2000);  // Wait 2 seconds between readings

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

  if (isnan(humidity) || isnan(temperature)) {
    Serial.println("Failed to read from DHT11 sensor!");
    return;
  }

  Serial.print("Temperature: ");
  Serial.print(temperature);
  Serial.print(" °C  |  Humidity: ");
  Serial.print(humidity);
  Serial.println(" %");
}

DHT11test

Connections

The connections are Pretty simple ive added images as well as the connections below

DHT11 Pin → ESP32 Pin → Description

VCC → 3.3V → Powers the DHT11 (works on 3.3V too)
DATA → GPIO 18 → Data signal pin (you can use any GPIO, here we use 18)
GND → GND → Common ground connection

DHT11test3

DHT11test4

Output

Here is the Output
DHT11test2

Saurabh Saurabh 🚀 added to the journal ago

Setting Up Things to start the project repo files etc.

Setting Things Up

So I created the GitHub repo and started a new project on Blueprint.


image


Workflow

I decided to create a workflow that also acts like a banner hehe


weatherstation

Saurabh Saurabh 🚀 started ESP32 Weather Station ago