IoT Weather Monitoring using ESP32

Loading chart...

Introduction

Here I’ll document how I created a room weather monitoring station with minimal cost and power usage.

There are three main components to this project:

  1. Hardware: The device that gathers data, built using an ESP32 microcontroller and a DHT22 sensor for temperature and humidity. Optionally, an OLED screen can be attached for local readout.
  2. Software: A lightweight, self-hosted API that handles incoming sensor data (via POST) and serves it (via GET) to clients.
  3. Dashboard: A real-time web-based dashboard that visualizes the latest readings from the API.

As an added challenge, I am self-hosting this entire setup on an AWS EC2 instance, avoiding platforms like Vercel or Heroku because I hate myself.

Hardware Setup

Components

  • ESP32 Wroom
  • DHT22 Temperature + Humidity Sensor
  • Breadboard + jumper wires
  • 10000mAh power bank for mobility
  • (Optional) 0.96" I2C OLED display (SSD1306)

Code Overview

The ESP32 reads temperature and humidity from the DHT22 sensor, optionally displays it on the OLED screen, and sends a POST request with the data every 30 minutes to the self-hosted API using WiFiClientSecure.

Server & API

The backend is built with FastAPI, chosen for its simplicity and low memory usage. It exposes two main endpoints:

  • POST /v1/data: Accepts JSON payloads from ESP32.
  • GET /v1/data/{n}: Returns the last n readings as JSON for the dashboard.

Example POST payload:

{
  "temperature": 27.4,
  "humidity": 61.2
}

The server appends each reading with a UTC timestamp to a local JSON file (data.json). For now, this acts as a simple persistent database.

Hosting the API

I used an AWS EC2 t2.micro instance running Debian. The FastAPI app runs under uvicorn, reverse-proxied by nginx, and served securely via HTTPS using certbot.

Dashboard

The dashboard is built using Next.js and React, served from the same VPS.

Features

  • Fetches latest n readings from the API using useEffect
  • Displays temperature and humidity on a Chart.js dual-axis line graph
  • Shows timestamp of latest reading
  • Optimized for mobile and desktop

Power Optimization

Using deep sleep on ESP32 between readings drastically improves battery life. For a 10000mAh power bank:

  • Active mode: ~80–100mA (5–10s per reading)
  • Deep sleep: ~0.01mA
  • Estimated runtime: ~6–8 weeks before recharge

Future Improvements

  • Add CO₂ or VOC sensor for indoor air quality
  • Switch to SQLite or InfluxDB for scalable storage
  • Offline data caching on ESP32 (in case of network drop)
  • Graph daily/weekly trends

Final Thoughts

This project demonstrates how much can be accomplished with minimal hardware, a bit of Python, and a self-hosted server.