ESP32 IoT Weather Station

IoT Projects Beginner Intermediate Advanced

Build a connected weather station — log temperature and humidity locally, then publish readings to a web dashboard.

Overview

This beginner stage of ESP32 IoT Weather Station focuses on the essentials: read BME280 sensor data, compare it to a simple threshold, and switch the OLED display on or off. No Wi-Fi required — perfect for your first working prototype on a breadboard.

Components
  • ESP32 DevKit (30-pin)
  • ESP32 DevKit (30-pin)
  • Breadboard
  • Breadboard
  • Jumper wires
  • Jumper wires
  • USB cable (5 V power)
  • USB cable (5 V power)
  • Bme280 Sensor
  • Bme280 Sensor
  • Oled Display
  • Oled Display
  • 1-channel relay module (if driving AC/high current)
  • 1-channel relay module (if driving AC/high current)
Wiring
Component PinESP32 PinNotes
Bme280 Sensor GPIO21 Digital I/O
Cloud Dashboard GPIO22 Digital I/O
Status Led SDA GPIO21 I2C bus
SCL GPIO22 I2C bus
VCC 3.3V/5V Power rail
GND GND Common ground
Arduino Code
esp32-iot-weather-station_beginner.ino
// ESP32 IoT Weather Station — Beginner
const int SENSOR_PIN = 21;
const int OUTPUT_PIN = 22;
const int THRESHOLD = 1800;
const int SAMPLE_DELAY_MS = 500;

void setup() {
  Serial.begin(115200);
  pinMode(OUTPUT_PIN, OUTPUT);
  pinMode(SENSOR_PIN, INPUT);
  Serial.println("Beginner stage ready");
}

void loop() {
  int reading = analogRead(SENSOR_PIN);
  Serial.print("BME280 sensor: ");
  Serial.println(reading);
  bool active = reading > THRESHOLD;
  digitalWrite(OUTPUT_PIN, active ? HIGH : LOW);
  delay(SAMPLE_DELAY_MS);
}
How It Works
01

The ESP32 reads the BME280 sensor on GPIO21.

02

Firmware compares the reading against THRESHOLD in the sketch.

03

When the condition is met, GPIO22 drives the OLED display HIGH.

04

Serial Monitor at 115200 baud shows live values for calibration.

Applications
  • First iot projects prototype on a breadboard
  • Classroom demo of sense → decide → act
  • Bench testing before permanent wiring
Troubleshooting

Serial Monitor shows no output

Check USB cable, correct COM port, and baud rate 115200. Press EN/RST on the board after upload.

Sensor readings stuck at 0 or 4095

Verify GPIO21 wiring, sensor VCC at 3.3 V, and that the module GND ties to ESP32 GND.

Output never turns on

Lower THRESHOLD after logging normal vs trigger readings in Serial Monitor.

Upgrades
  • Move to intermediate stage for OLED and manual/auto mode
  • Add deep sleep between samples to save power
  • Enclose in project box with labeled terminals
FAQ

You need an ESP32 DevKit, BME280 sensor, OLED display, a breadboard, jumper wires, and a USB cable for power and programming.

Only the Advanced stage uses Wi-Fi. Beginner and Intermediate builds run offline on the ESP32 with USB power.

Start with Beginner if you are new to IoT Projects. Use Intermediate for OLED feedback and Advanced for dashboards or connected monitoring.

Overview

The intermediate stage adds calibration, an OLED status screen, and manual/auto mode. You will tune thresholds from real readings, show live values on the display, and harden the sketch with clearer error handling before adding connectivity.

Components
  • ESP32 DevKit (30-pin)
  • ESP32 DevKit (30-pin)
  • Breadboard
  • Breadboard
  • Jumper wires
  • Jumper wires
  • USB cable (5 V power)
  • USB cable (5 V power)
  • Bme280 Sensor
  • Bme280 Sensor
  • Oled Display
  • Oled Display
  • Relay module
  • Relay module
  • 0.96" I2C OLED display
  • 0.96" I2C OLED display
  • Tactile push button
  • Tactile push button
  • 10 kΩ resistor (pull-up if needed)
  • 10 kΩ resistor (pull-up if needed)
Wiring
Component PinESP32 PinNotes
Bme280 Sensor GPIO21 Digital I/O
Cloud Dashboard GPIO22 Digital I/O
Status Led SDA GPIO21 I2C bus
SCL GPIO22 I2C bus
VCC 3.3V/5V Power rail
GND GND Common ground
Mode button GPIO0 Boot button — manual/auto toggle
Arduino Code
esp32-iot-weather-station_intermediate.ino
// ESP32 IoT Weather Station — Intermediate
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

const int SENSOR_PIN = 21;
const int OUTPUT_PIN = 22;
const int BUTTON_PIN = 0;
const int THRESHOLD = 1800;
const int HYSTERESIS = 80;
bool autoMode = true;

Adafruit_SSD1306 display(128, 64, &Wire, -1);

void setup() {
  Serial.begin(115200);
  pinMode(OUTPUT_PIN, OUTPUT);
  pinMode(SENSOR_PIN, INPUT);
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  Wire.begin(21, 22);
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  display.display();
}

void loop() {
  if (!digitalRead(BUTTON_PIN)) {
    autoMode = !autoMode;
    delay(250);
  }
  int reading = analogRead(SENSOR_PIN);
  bool active = autoMode ? (reading > THRESHOLD) : false;
  if (autoMode && reading < THRESHOLD - HYSTERESIS) active = false;
  digitalWrite(OUTPUT_PIN, active ? HIGH : LOW);
  display.clearDisplay();
  display.setTextSize(1);
  display.setCursor(0, 0);
  display.print(autoMode ? "AUTO" : "MANUAL");
  display.print("  Val:");
  display.println(reading);
  display.display();
  delay(300);
}
How It Works
01

On boot, the sketch loads saved calibration offsets and shows status on the OLED.

02

Sensor samples on GPIO21; display updates every loop with current value and mode.

03

Press the mode button to toggle manual override vs automatic threshold control.

04

Watchdog-style checks prevent relay chatter when readings hover near the cutoff.

Applications
  • Field trial with visible OLED feedback
  • Manual override for maintenance or testing
  • Calibrated setup for daily use
Troubleshooting

Serial Monitor shows no output

Check USB cable, correct COM port, and baud rate 115200. Press EN/RST on the board after upload.

Sensor readings stuck at 0 or 4095

Verify GPIO21 wiring, sensor VCC at 3.3 V, and that the module GND ties to ESP32 GND.

OLED stays blank

Confirm I2C address (usually 0x3C), SDA on GPIO21, SCL on GPIO22, and 3.3 V power.

Relay chatters near threshold

Add hysteresis in code or increase SAMPLE_DELAY_MS slightly.

Upgrades
  • Jump to advanced stage for Wi-Fi dashboard and alerts
  • Store calibration in EEPROM or Preferences library
  • Add physical override switch on a dedicated GPIO
FAQ

You need an ESP32 DevKit, BME280 sensor, OLED display, a breadboard, jumper wires, and a USB cable for power and programming.

Only the Advanced stage uses Wi-Fi. Beginner and Intermediate builds run offline on the ESP32 with USB power.

Start with Beginner if you are new to IoT Projects. Use Intermediate for OLED feedback and Advanced for dashboards or connected monitoring.

Overview

The advanced stage connects ESP32 IoT Weather Station to your network: live dashboard or mobile-friendly monitoring, alert notifications, CSV-style logging, and automation rules you can adjust remotely.

Components
  • ESP32 DevKit (30-pin)
  • ESP32 DevKit (30-pin)
  • Breadboard
  • Breadboard
  • Jumper wires
  • Jumper wires
  • USB cable (5 V power)
  • USB cable (5 V power)
  • Bme280 Sensor
  • Bme280 Sensor
  • Oled Display
  • Oled Display
  • Relay module
  • Relay module
  • I2C OLED display
  • I2C OLED display
  • microSD module (optional logging)
  • microSD module (optional logging)
  • Stable 5 V supply for field deployment
  • Stable 5 V supply for field deployment
Wiring
Component PinESP32 PinNotes
Bme280 Sensor GPIO21 Digital I/O
Cloud Dashboard GPIO22 Digital I/O
Status Led SDA GPIO21 I2C bus
SCL GPIO22 I2C bus
VCC 3.3V/5V Power rail
GND GND Common ground
Alert LED GPIO2 Notification indicator
Wi-Fi Built-in 2.4 GHz — no extra wiring
Arduino Code
esp32-iot-weather-station_advanced.ino
// ESP32 IoT Weather Station — Advanced
#include <WiFi.h>
#include <WebServer.h>

const char* WIFI_SSID = "YOUR_SSID";
const char* WIFI_PASS = "YOUR_PASSWORD";
const int SENSOR_PIN = 21;
const int OUTPUT_PIN = 22;
const int THRESHOLD = 1800;
WebServer server(80);
unsigned long lastAlert = 0;

void handleRoot() {
  int v = analogRead(SENSOR_PIN);
  String body = "<h1>ESP32 IoT Weather Station</h1><p>Reading: " + String(v) + "</p>";
  body += "<p>Output: " + String(digitalRead(OUTPUT_PIN) ? "ON" : "OFF") + "</p>";
  server.send(200, "text/html", body);
}

void setup() {
  Serial.begin(115200);
  pinMode(OUTPUT_PIN, OUTPUT);
  pinMode(SENSOR_PIN, INPUT);
  WiFi.begin(WIFI_SSID, WIFI_PASS);
  while (WiFi.status() != WL_CONNECTED) delay(300);
  server.on("/", handleRoot);
  server.begin();
  Serial.println(WiFi.localIP());
}

void loop() {
  server.handleClient();
  int reading = analogRead(SENSOR_PIN);
  bool active = reading > THRESHOLD;
  digitalWrite(OUTPUT_PIN, active ? HIGH : LOW);
  if (active && millis() - lastAlert > 60000UL) {
    Serial.println("ALERT: threshold crossed");
    lastAlert = millis();
  }
  delay(200);
}
How It Works
01

ESP32 joins Wi-Fi and exposes readings through a lightweight web page or MQTT topic.

02

Local GPIO21 sensing still runs on-device — cloud is optional for resilience.

03

Rules engine evaluates thresholds, quiet hours, and repeat-alert intervals.

04

Logs append timestamped events you can download or forward to Home Assistant.

Applications
  • Remote monitoring from phone or laptop
  • Automated alerts when limits are crossed
  • Long-term trend logging for optimization
Troubleshooting

Serial Monitor shows no output

Check USB cable, correct COM port, and baud rate 115200. Press EN/RST on the board after upload.

Sensor readings stuck at 0 or 4095

Verify GPIO21 wiring, sensor VCC at 3.3 V, and that the module GND ties to ESP32 GND.

Wi-Fi connection fails

Use 2.4 GHz SSID, check password in sketch, and ensure router allows new devices.

Dashboard loads but values frozen

Confirm loop still reads sensor; avoid blocking HTTP handlers — use async or periodic refresh.

Upgrades
  • Integrate with Home Assistant or MQTT broker
  • Add OTA firmware updates for remote fixes
  • Ship on custom PCB with regulated power supply
FAQ

You need an ESP32 DevKit, BME280 sensor, OLED display, a breadboard, jumper wires, and a USB cable for power and programming.

Only the Advanced stage uses Wi-Fi. Beginner and Intermediate builds run offline on the ESP32 with USB power.

Start with Beginner if you are new to IoT Projects. Use Intermediate for OLED feedback and Advanced for dashboards or connected monitoring.