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 đ
Tier 4
33 views
1 follower
Timeline
CAN âĄđ
approved ESP32 Weather Station ago
Tickets awarded: 70 tickets
Tier: 4
CAN âĄđ
submitted ESP32 Weather Station for review ago
Saurabh đ
submitted ESP32 Weather Station for review ago
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

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.

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.

The server has two endpoints
-
/serves the HTML dashboard -
/datareturns 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!!!

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();
}
}

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 đ
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)
and my PIR Sensor (which came with BROKEN PINS and NO LABELS FOR THE PINS)


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

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

PIR Sensor Pinouts

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 đ
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(" %");
}
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


Output
Here is the Output

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.

Workflow
I decided to create a workflow that also acts like a banner hehe
Saurabh đ
started ESP32 Weather Station ago


