Project 1: Environmental Monitor with Web Dashboard

Project 1: Environmental Monitor with Web Dashboard

Project Overview

Attribute Value
Difficulty Beginner-Intermediate
Time Estimate 1-2 weeks
Main Language C
Alternatives MicroPython, Rust, Arduino C++
Primary Book Making Embedded Systems by Elecia White
Knowledge Areas Embedded Systems, GPIO, WiFi, I2C, HTTP

What Youโ€™ll Build

A sensor station that reads temperature, humidity, and air quality, serves a real-time web dashboard over WiFi, and logs data to flash storage.

Physical Setup:

  • ESP32 development board on a breadboard
  • BME280 sensor (I2C) or DHT22 sensor (GPIO) for temperature and humidity
  • Optional: MQ-135 air quality sensor (analog ADC)
  • LED indicator for WiFi status
  • Powered via USB cable

Web Dashboard Preview:

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  Environmental Monitor - Living Room    โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚                                         โ”‚
โ”‚  Temperature:  22.3ยฐC  (72.1ยฐF)         โ”‚
โ”‚  Humidity:     45%                      โ”‚
โ”‚  Air Quality:  Good (385 ppm)           โ”‚
โ”‚                                         โ”‚
โ”‚  Last Updated: 2 seconds ago            โ”‚
โ”‚  Auto-refresh: ON                       โ”‚
โ”‚                                         โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”‚
โ”‚  โ”‚ Temperature (Last 24 Hours)    โ”‚    โ”‚
โ”‚  โ”‚      โ•ญโ”€โ”€โ•ฎ                      โ”‚    โ”‚
โ”‚  โ”‚  โ•ญโ”€โ”€โ”€โ•ฏ  โ•ฐโ”€โ”€โ•ฎ                   โ”‚    โ”‚
โ”‚  โ”‚โ”€โ”€โ•ฏ         โ•ฐโ”€โ”€                 โ”‚    โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ”‚
โ”‚                                         โ”‚
โ”‚  Device Uptime: 3 days, 14 hours       โ”‚
โ”‚  Readings Stored: 4,320 (72 hours)     โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Learning Objectives

By completing this project, you will be able to:

  1. Configure and use I2C communication to read data from sensors
  2. Set up ESP32 as a WiFi station and handle connection/disconnection gracefully
  3. Implement an HTTP server on embedded hardware to serve web pages
  4. Use Non-Volatile Storage (NVS) to persist data across reboots
  5. Read analog sensors using ADC and understand voltage conversion
  6. Create concurrent tasks with FreeRTOS for sensor reading and web serving

Deep Theoretical Foundation

I2C Communication Protocol

I2C (Inter-Integrated Circuit) is a synchronous, multi-master, multi-slave serial communication protocol invented by Philips in 1982. Understanding I2C is fundamental to embedded systems because most sensors, displays, and peripheral chips use it.

The Two-Wire Interface

I2C uses only two wires:

  • SDA (Serial Data): Bidirectional data line
  • SCL (Serial Clock): Clock signal generated by the master

Both lines are โ€œopen-drainโ€ with pull-up resistors (typically 4.7kฮฉ), meaning devices can only pull the line LOWโ€”they release it to go HIGH. This design enables multiple devices to share the bus without conflicts.

I2C Timing and Signaling

       โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
       โ”‚                    I2C Transaction                    โ”‚
       โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

SDA:   โ”€โ”€โ”€โ”€โ”€โ”     โ”Œโ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”     โ”Œโ”€โ”€โ”€โ”€โ”€
            โ”‚ S   โ”‚ A6  โ”‚ A5  โ”‚ ... โ”‚ A0  โ”‚ R/W โ”‚ ACK โ”‚ ... โ”‚ P
            โ””โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”˜     โ””โ”€โ”€โ”€โ”€โ”€

SCL:   โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ” โ”Œโ”€โ” โ”Œโ”€โ”       โ”Œโ”€โ” โ”Œโ”€โ” โ”Œโ”€โ” โ”Œโ”€โ”       โ”Œโ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€
             โ””โ”€โ”˜ โ””โ”€โ”˜ โ””โ”€โ”˜ โ””โ”€ ... โ”€โ”˜ โ””โ”€โ”˜ โ””โ”€โ”˜ โ””โ”€โ”˜ โ””โ”€ ... โ”€โ”˜ โ””โ”€โ”˜

       START  โ”‚โ† 7-bit Address โ†’โ”‚R/Wโ”‚ACKโ”‚โ† Data bytes โ†’โ”‚STOP

START Condition: SDA goes LOW while SCL is HIGH STOP Condition: SDA goes HIGH while SCL is HIGH Data Transfer: Each bit is read when SCL is HIGH; SDA must be stable

I2C Addressing

Every I2C device has a unique 7-bit address (some use 10-bit). The BME280 sensor uses address 0x76 or 0x77 depending on the SDO pin connection.

Address Byte: | A6 | A5 | A4 | A3 | A2 | A1 | A0 | R/W |
              |โ†โ”€โ”€โ”€โ”€โ”€โ”€ 7-bit address โ”€โ”€โ”€โ”€โ”€โ”€โ†’|    โ””โ”€โ”€ 0=Write, 1=Read

Why this matters: If two devices share the same address, youโ€™ll get communication errors. Before adding any I2C device, check its address doesnโ€™t conflict with existing devices.

Clock Stretching

Some slow devices need more time to process data. They can hold SCL LOW to โ€œstretchโ€ the clock, pausing the master until ready. The BME280 uses clock stretching during temperature conversion.

GPIO (General Purpose Input/Output)

GPIO pins are the fundamental interface between your microcontroller and the physical world. Understanding their electrical characteristics prevents damage and enables reliable designs.

Pin Modes

Mode Description Use Case
Input Reads external voltage (HIGH/LOW) Buttons, switches, digital sensors
Output Drives voltage HIGH (3.3V) or LOW (0V) LEDs, relays, enable signals
Input Pullup Input with internal pull-up resistor Buttons without external resistor
Input Pulldown Input with internal pull-down resistor Detecting active-high signals
Analog Reads voltage as continuous value Potentiometers, analog sensors

ESP32 ADC Characteristics

The ESP32โ€™s ADC (Analog-to-Digital Converter) has important limitations:

  • Resolution: 12-bit (0-4095 digital values)
  • Voltage Range: 0 to 3.3V (with attenuation)
  • Non-linearity: ESP32โ€™s ADC is notoriously inaccurate at extremes
  • Noise: Expect ยฑ10 LSB noise on readings
Attenuation Settings:
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Attenuation     โ”‚ Measurable Range  โ”‚ Recommended For โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ 0 dB            โ”‚ 0 - 1.1V          โ”‚ Low voltage     โ”‚
โ”‚ 2.5 dB          โ”‚ 0 - 1.5V          โ”‚                 โ”‚
โ”‚ 6 dB            โ”‚ 0 - 2.2V          โ”‚                 โ”‚
โ”‚ 11 dB           โ”‚ 0 - 3.3V          โ”‚ Most sensors    โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

WiFi on ESP32

The ESP32 includes a complete WiFi stack supporting both 2.4GHz 802.11 b/g/n and Bluetooth. Understanding the different modes is essential for IoT projects.

WiFi Station Mode vs Access Point Mode

Station Mode (STA):                    Access Point Mode (AP):

Your Phone โ†’ Router โ†’ Internet         Your Phone โ†’ ESP32
                โ†‘                                      โ”‚
             ESP32                      No internet access
                                       Direct connection

Station Mode (used in this project): ESP32 connects to your existing WiFi router, getting an IP address via DHCP. This allows internet access and integration with your home network.

Access Point Mode: ESP32 creates its own WiFi network. Devices connect directly to the ESP32. Useful for configuration or when no router is available.

WiFi Connection Process

1. esp_wifi_init()      โ†’ Initialize WiFi driver
2. esp_wifi_set_mode()  โ†’ Choose STA, AP, or STA+AP
3. esp_wifi_set_config()โ†’ Set SSID and password
4. esp_wifi_start()     โ†’ Start WiFi hardware
5. esp_wifi_connect()   โ†’ Begin connection (STA mode)
       โ†“
   [Scanning for SSID]
       โ†“
   [Association with AP]
       โ†“
   [WPA2 4-way handshake]
       โ†“
   [DHCP IP acquisition]
       โ†“
   WIFI_EVENT_STA_CONNECTED (callback fires)

Connection typically takes 2-5 seconds. During this time, your code should show a โ€œconnectingโ€ state (e.g., blinking LED).

HTTP Protocol Basics

HTTP (Hypertext Transfer Protocol) is the foundation of web communication. Your ESP32 will act as an HTTP server, responding to requests from web browsers.

Request/Response Model

Browser                                    ESP32
   โ”‚                                         โ”‚
   โ”‚โ”€โ”€โ”€โ”€โ”€ GET / HTTP/1.1 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ†’โ”‚
   โ”‚      Host: 192.168.1.150                โ”‚
   โ”‚                                         โ”‚
   โ”‚โ†โ”€โ”€โ”€โ”€ HTTP/1.1 200 OK โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚
   โ”‚      Content-Type: text/html            โ”‚
   โ”‚      Content-Length: 3245               โ”‚
   โ”‚                                         โ”‚
   โ”‚      <html>...</html>                   โ”‚
   โ”‚                                         โ”‚

Common HTTP Methods

Method Purpose Example
GET Retrieve data Load web page
POST Send data Submit form
PUT Update data Update sensor config
DELETE Remove data Clear logs

For this project, youโ€™ll primarily use GET to serve the dashboard and a JSON API endpoint.

Non-Volatile Storage (NVS)

NVS is ESP32โ€™s key-value storage system designed for flash memory. Unlike RAM, NVS data survives reboots and power cycles.

Flash Memory Characteristics

Flash Memory Structure:
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Sector 0 โ”‚ Sector 1 โ”‚ Sector 2 โ”‚ ... โ”‚ Sector N    โ”‚
โ”‚  (4KB)   โ”‚  (4KB)   โ”‚  (4KB)   โ”‚     โ”‚   (4KB)     โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

- Write: Can only change 1โ†’0 (not 0โ†’1)
- Erase: Must erase entire sector (all bitsโ†’1)
- Endurance: ~100,000 erase cycles per sector

Why NVS instead of raw flash: NVS handles wear leveling automatically, spreading writes across multiple sectors to extend flash lifetime.

NVS Namespaces and Keys

// Open namespace "sensor_data"
nvs_open("sensor_data", NVS_READWRITE, &handle);

// Write key-value pairs
nvs_set_float(handle, "last_temp", 22.3);
nvs_set_i32(handle, "reading_count", 1542);

// Commit changes to flash
nvs_commit(handle);

Best Practice: Batch multiple writes and commit once to reduce flash wear.

FreeRTOS Tasks

ESP32 runs FreeRTOS, a real-time operating system that enables concurrent execution through tasks. Each task is like a separate program running simultaneously.

Task Lifecycle

                    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
        create      โ”‚ Created โ”‚
     โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ†’ โ””โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”˜
                         โ”‚ start
                         โ–ผ
                    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ†’โ”‚  Ready  โ”‚โ†โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
    โ”‚               โ””โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”˜              โ”‚
    โ”‚                    โ”‚ scheduler picks   โ”‚ preempted
    โ”‚                    โ–ผ                   โ”‚
    โ”‚               โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”              โ”‚
    โ”‚               โ”‚ Running โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
    โ”‚               โ””โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”˜
    โ”‚                    โ”‚ wait/delay
    โ”‚                    โ–ผ
    โ”‚               โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚ Blocked โ”‚ (waiting for event/time)
                    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Task Priorities

Higher priority tasks preempt lower priority tasks. For this project:

  • High Priority: WiFi handling (networking is time-sensitive)
  • Medium Priority: HTTP server (respond quickly to requests)
  • Low Priority: Sensor reading (can tolerate delays)

Project Specification

Hardware Requirements

Component Quantity Purpose
ESP32 DevKit 1 Main microcontroller
BME280 Sensor 1 Temperature, humidity, pressure
Breadboard 1 Prototyping
Jumper Wires 6+ Connections
LED (optional) 1 WiFi status indicator
220ฮฉ Resistor 1 LED current limiting

Wiring Diagram

ESP32 DevKit                    BME280
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚        3.3V โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚ VCC    โ”‚
โ”‚         GND โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚ GND    โ”‚
โ”‚      GPIO21 โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚ SDA    โ”‚
โ”‚      GPIO22 โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚ SCL    โ”‚
โ”‚             โ”‚                โ”‚ CSB    โ”‚โ”€โ”€โ”€โ”€ VCC (I2C mode)
โ”‚             โ”‚                โ”‚ SDO    โ”‚โ”€โ”€โ”€โ”€ GND (addr 0x76)
โ”‚             โ”‚                โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ”‚             โ”‚
โ”‚       GPIO2 โ”‚โ”€โ”€โ”€โ”€[220ฮฉ]โ”€โ”€โ”€โ”€LEDโ”€โ”€โ”€โ”€GND
โ”‚             โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Functional Requirements

  1. Sensor Reading
    • Read temperature, humidity, and pressure every 10 seconds
    • Support both BME280 (I2C) and DHT22 (GPIO) sensors
    • Handle sensor initialization failures gracefully
  2. WiFi Connectivity
    • Connect to configured WiFi network on startup
    • Automatically reconnect on disconnection
    • Indicate connection status via LED
  3. Web Dashboard
    • Serve HTML dashboard on port 80
    • Display current sensor readings
    • Show 24-hour historical data graph
    • Auto-refresh every 5 seconds via JavaScript
  4. Data Logging
    • Store readings in NVS every 10 seconds
    • Maintain 72 hours of historical data
    • Implement circular buffer to prevent flash exhaustion
  5. API Endpoints
    • GET / - HTML dashboard
    • GET /api/readings - Current readings (JSON)
    • GET /api/history - Historical data (JSON)

Solution Architecture

System Block Diagram

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                         ESP32 System                             โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚                                                                  โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”      โ”‚
โ”‚  โ”‚   Sensor     โ”‚    โ”‚    WiFi      โ”‚    โ”‚    HTTP      โ”‚      โ”‚
โ”‚  โ”‚    Task      โ”‚    โ”‚   Manager    โ”‚    โ”‚   Server     โ”‚      โ”‚
โ”‚  โ”‚              โ”‚    โ”‚              โ”‚    โ”‚              โ”‚      โ”‚
โ”‚  โ”‚ - Read I2C   โ”‚    โ”‚ - Connect    โ”‚    โ”‚ - Route /    โ”‚      โ”‚
โ”‚  โ”‚ - Update     โ”‚โ”€โ”€โ”€โ†’โ”‚ - Reconnect  โ”‚    โ”‚ - Route /api โ”‚      โ”‚
โ”‚  โ”‚   globals    โ”‚    โ”‚ - Events     โ”‚    โ”‚ - Serve HTML โ”‚      โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜      โ”‚
โ”‚         โ”‚                                       โ”‚               โ”‚
โ”‚         โ–ผ                                       โ–ผ               โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                      โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”        โ”‚
โ”‚  โ”‚   Global     โ”‚โ†โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚    JSON      โ”‚        โ”‚
โ”‚  โ”‚   Sensor     โ”‚                      โ”‚  Generator   โ”‚        โ”‚
โ”‚  โ”‚    Data      โ”‚                      โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜        โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                                               โ”‚
โ”‚         โ”‚                                                       โ”‚
โ”‚         โ–ผ                                                       โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                                               โ”‚
โ”‚  โ”‚    NVS       โ”‚                                               โ”‚
โ”‚  โ”‚   Storage    โ”‚                                               โ”‚
โ”‚  โ”‚              โ”‚                                               โ”‚
โ”‚  โ”‚ - Save every โ”‚                                               โ”‚
โ”‚  โ”‚   10 seconds โ”‚                                               โ”‚
โ”‚  โ”‚ - Circular   โ”‚                                               โ”‚
โ”‚  โ”‚   buffer     โ”‚                                               โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                                               โ”‚
โ”‚                                                                  โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Data Flow

1. Sensor Task (every 10s):
   BME280 โ†’ I2C Read โ†’ Parse Raw Data โ†’ Apply Calibration โ†’ Update Global

2. Storage Flow:
   Global Data โ†’ Format โ†’ NVS Write (with index rotation)

3. HTTP Request Flow:
   Browser โ†’ GET /api/readings โ†’ Read Global โ†’ JSON Format โ†’ Response

4. Dashboard Flow:
   Browser โ†’ GET / โ†’ Serve HTML โ†’ JavaScript fetch() โ†’ Update DOM

Key Data Structures

// Sensor reading structure
typedef struct {
    float temperature;    // Celsius
    float humidity;       // Percentage
    float pressure;       // hPa
    uint32_t timestamp;   // Unix timestamp
} sensor_reading_t;

// Global state
typedef struct {
    sensor_reading_t current;
    bool wifi_connected;
    uint32_t uptime_seconds;
    uint32_t readings_stored;
} system_state_t;

// NVS storage uses circular buffer with index
// Key format: "rd_0000" to "rd_8639" (24h * 360 readings/hour)

Phased Implementation Guide

Phase 1: Hardware Verification (Day 1)

Goal: Verify ESP32 and sensor are working

  1. Blink LED Test
    • Write simple blink program
    • Verify upload and serial monitor work
    • If LED doesnโ€™t blink: Check COM port, board selection, boot mode
  2. I2C Scanner
    • Scan I2C bus for devices
    • BME280 should appear at 0x76 or 0x77
    • If not found: Check wiring, pull-up resistors, sensor power
  3. Sensor Raw Reading
    • Use BME280 library to read values
    • Print to serial monitor
    • Verify readings are reasonable (not 0 or NaN)

Checkpoint: Serial monitor shows valid temperature/humidity readings

Phase 2: WiFi Connection (Day 2-3)

Goal: Reliable WiFi with reconnection handling

  1. Basic Connection
    • Connect to WiFi with hardcoded credentials
    • Print IP address on success
    • Add LED indication (blink while connecting, solid when connected)
  2. Event Handling
    • Register WiFi event handlers
    • Handle disconnection events
    • Implement reconnection logic with exponential backoff
  3. Robustness Testing
    • Power cycle router while ESP32 is connected
    • Verify automatic reconnection
    • Test with wrong password (should report error, not hang)

Checkpoint: ESP32 maintains WiFi connection through router restarts

Phase 3: HTTP Server (Day 4-5)

Goal: Serve web content from ESP32

  1. Minimal Server
    • Start HTTP server on port 80
    • Serve โ€œHello Worldโ€ on root path
    • Access from browser using ESP32โ€™s IP
  2. Static HTML Dashboard
    • Create HTML template with placeholder values
    • Embed HTML in C code using raw string literals
    • Serve complete HTML page
  3. API Endpoint
    • Add /api/readings route
    • Return JSON with current sensor values
    • Test with curl command
  4. Auto-Refresh
    • Add JavaScript to dashboard
    • Fetch from API every 5 seconds
    • Update DOM without page reload

Checkpoint: Dashboard shows live sensor data updating automatically

Phase 4: Data Persistence (Day 6-7)

Goal: Store and retrieve historical data

  1. NVS Basics
    • Open NVS namespace
    • Write and read test values
    • Verify data survives reboot
  2. Circular Buffer
    • Implement index rotation (0-8639)
    • Store readings with timestamp keys
    • Handle wraparound gracefully
  3. History API
    • Add /api/history endpoint
    • Return last 24 hours of data
    • Format as JSON array
  4. Dashboard Graph
    • Add simple ASCII or Canvas graph
    • Fetch history data on page load
    • Display temperature trend

Checkpoint: Dashboard shows 24-hour temperature graph that persists across reboots

Phase 5: Polish and Testing (Day 8+)

Goal: Production-ready behavior

  1. Error Handling
    • Handle sensor read failures
    • Handle NVS full condition
    • Add watchdog timer for recovery
  2. Memory Optimization
    • Check heap usage with esp_get_free_heap_size()
    • Ensure no memory leaks over time
    • Optimize HTML/JSON string handling
  3. Configuration
    • Move WiFi credentials to NVS
    • Add configuration page for settings
    • Store sensor calibration offsets

Testing Strategy

Unit Tests

Component Test Expected Result
I2C Scan for device at 0x76 Device found
Sensor Read temperature 15-35ยฐC (room temp)
WiFi Connect with correct password IP assigned
WiFi Connect with wrong password Error event
HTTP GET / 200 OK + HTML
HTTP GET /api/readings Valid JSON
NVS Write then read Same value

Integration Tests

  1. Long-Running Stability
    • Run for 24 hours minimum
    • Monitor heap usage (should be stable)
    • Check for WiFi disconnection/reconnection events
  2. Power Cycle Recovery
    • Store some data
    • Power off/on
    • Verify data is still accessible
  3. Multi-Client Access
    • Open dashboard from multiple devices
    • All should see same data
    • No crashes or hangs

Performance Benchmarks

Metric Target How to Measure
Sensor read time < 100ms esp_timer_get_time()
HTTP response time < 50ms Browser dev tools
NVS write time < 10ms Timer around nvs_commit
Memory usage < 100KB heap esp_get_free_heap_size()

Common Pitfalls and Debugging

I2C Issues

Problem: Sensor not detected

  • Check wiring (SDA to GPIO21, SCL to GPIO22)
  • Verify 3.3V power to sensor
  • Try both addresses (0x76 and 0x77)
  • Add pull-up resistors if using long wires

Problem: Garbage readings

  • Check I2C clock speed (start with 100kHz)
  • Verify sensor is genuine (counterfeit BME280s exist)
  • Add delay after sensor power-on (100ms)

WiFi Issues

Problem: Connection fails immediately

  • Verify SSID and password are correct (case-sensitive)
  • Check router isnโ€™t at device limit
  • Try static IP if DHCP fails

Problem: Frequent disconnections

  • Check signal strength (WiFi.RSSI())
  • Reduce distance to router
  • Check for 2.4GHz interference

HTTP Server Issues

Problem: Browser canโ€™t connect

  • Verify ESP32 IP address
  • Check firewall on computer
  • Ensure server started successfully

Problem: Partial page loads

  • Increase HTTP response buffer size
  • Check for memory exhaustion
  • Split large pages into smaller chunks

Memory Issues

Problem: Crash after running for hours

  • Memory leak in HTTP handlers (forgetting to free JSON strings)
  • Stack overflow in tasks (increase stack size)
  • Use heap tracing to find leaks

Extensions and Challenges

Beginner Extensions

  1. Multi-Room Monitoring
    • Add second sensor on different I2C address
    • Show both locations on dashboard
  2. Email Alerts
    • Send email when temperature exceeds threshold
    • Use SMTP library or webhook service
  3. CSV Export
    • Add button to download data as CSV
    • Implement streaming response for large files

Intermediate Challenges

  1. mDNS Discovery
    • Register as envmonitor.local
    • Access without knowing IP address
  2. HTTPS Support
    • Generate self-signed certificate
    • Enable TLS on HTTP server
  3. MQTT Integration
    • Publish readings to MQTT broker
    • Compatible with Home Assistant

Advanced Challenges

  1. Custom PCB Design
    • Design PCB with ESP32 module
    • Add battery charging circuit
    • Weatherproof enclosure for outdoor use
  2. Machine Learning
    • Train model to predict temperature trends
    • Run inference on ESP32 (TensorFlow Lite Micro)
  3. Mesh Network
    • Multiple sensors using ESP-NOW
    • One hub aggregates all data

Real-World Connections

Industry Applications

Industry Application Your Project Skill
Smart Buildings HVAC monitoring Sensor + WiFi
Agriculture Greenhouse control Environmental sensing
Cold Chain Food transport monitoring Data logging
Data Centers Server room monitoring Web dashboard

Commercial Products Using Similar Technology

  • Ecobee Thermostat: Environmental sensing + WiFi + cloud
  • AirThings Wave: Air quality monitoring with web dashboard
  • Nest Temperature Sensors: Battery-powered I2C sensors

Career Paths

Skills from this project apply to:

  • IoT Developer: Building connected devices
  • Embedded Systems Engineer: Low-level firmware development
  • Full-Stack IoT: Device + Cloud + Mobile app development

Resources

Official Documentation

Resource URL
ESP-IDF GPIO API docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/gpio.html
ESP-IDF I2C API docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/i2c.html
ESP-IDF WiFi API docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_wifi.html
ESP-IDF NVS API docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/storage/nvs_flash.html

Books

Book Author Relevant Chapters
Making Embedded Systems, 2nd Ed Elecia White Ch. 5, 6, 10
IoT Product Development Using ESP32 Sai Yamanoor WiFi chapter
HTTP: The Definitive Guide David Gourley Ch. 1-3

Libraries

Library Purpose Platform
Adafruit BME280 Sensor driver Arduino
ESPAsyncWebServer HTTP server Arduino
ArduinoJson JSON handling Arduino
cJSON JSON handling ESP-IDF

Self-Assessment Checklist

Fundamentals

  • I can explain how I2C addressing works
  • I understand the difference between WiFi STA and AP modes
  • I can describe how HTTP GET requests work
  • I know why NVS uses wear leveling

Implementation

  • My sensor reads are accurate within ยฑ1ยฐC
  • WiFi reconnects automatically after router restart
  • Dashboard updates without page refresh
  • Data persists across power cycles

Code Quality

  • No compiler warnings
  • Heap usage is stable over 24 hours
  • Error conditions are handled gracefully
  • Code is organized into logical functions

Understanding

  • I can modify the sensor reading interval without bugs
  • I can add a new API endpoint
  • I understand why we use FreeRTOS tasks
  • I can explain the data flow from sensor to browser

Interview Preparation

Be ready to answer these questions:

  1. โ€œExplain how I2C communication works. What are the key signals?โ€
    • SDA (data), SCL (clock), start/stop conditions, addressing, ACK/NACK
  2. โ€œWhy use I2C instead of SPI for the BME280 sensor?โ€
    • I2C uses 2 wires vs 4+ for SPI; I2C is simpler for short distances
  3. โ€œHow does WiFi station mode differ from access point mode?โ€
    • Station connects to existing WiFi; AP creates WiFi hotspot
  4. โ€œWhat is NVS and why not use a regular file system?โ€
    • NVS is key-value storage optimized for flash wear leveling
  5. โ€œHow would you handle WiFi disconnection gracefully?โ€
    • Retry with exponential backoff, blink LED, continue sensor logging offline
  6. โ€œWhat is the ESP32โ€™s ADC resolution and voltage range?โ€
    • 12-bit (0-4095), 0-3.3V with 11dB attenuation

Next Project: P02-ble-remote-control.md - Bluetooth Low Energy Remote Control