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:
- 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.
- Software: A lightweight, self-hosted API that handles incoming sensor data (via
POST) and serves it (viaGET) to clients. - 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 lastnreadings 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
nreadings from the API usinguseEffect - 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.