Project 5: OTA-Updatable Smart Home Hub

Project 5: OTA-Updatable Smart Home Hub

Project Overview

Attribute Value
Difficulty Advanced
Time Estimate 1 month+
Main Language C
Alternatives Rust, MicroPython, Arduino C++
Primary Book Making Embedded Systems by Elecia White
Knowledge Areas OTA Updates, Partitions, ESP-NOW, REST API, System Architecture

What Youโ€™ll Build

A central hub that communicates with multiple sensor nodes via ESP-NOW, provides a REST API for integration with Home Assistant, and can update its own firmware over-the-air.

Physical Setup:

  • One ESP32 hub connected to power and WiFi
  • Multiple ESP32 sensor nodes (battery-powered, using ESP-NOW)
  • Hub aggregates data and exposes REST API
  • Push firmware updates without physical access

Home Assistant Dashboard View:

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Smart Home Hub - Living Room           โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚                                         โ”‚
โ”‚ Sensor Nodes (5 active)                 โ”‚
โ”‚   Living Room - Temp: 22.3ยฐC           โ”‚
โ”‚   Bedroom - Motion: Detected 2m ago    โ”‚
โ”‚   Kitchen - Temp: 24.1ยฐC               โ”‚
โ”‚   Front Door - Status: Closed          โ”‚
โ”‚   Garage - Motion: Clear               โ”‚
โ”‚                                         โ”‚
โ”‚ Hub Status                              โ”‚
โ”‚   Uptime: 15d 4h 23m                   โ”‚
โ”‚   WiFi: -42 dBm (Excellent)            โ”‚
โ”‚   Firmware: v2.3.1                      โ”‚
โ”‚   Last Update: 2024-12-20              โ”‚
โ”‚                                         โ”‚
โ”‚ [Update Firmware]  [Restart Hub]       โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Learning Objectives

By completing this project, you will be able to:

  1. Design and implement OTA update systems with rollback capability
  2. Understand ESP32 partition tables and bootloader behavior
  3. Run WiFi and ESP-NOW simultaneously on the same radio
  4. Build REST APIs on embedded systems
  5. Manage concurrent connections with FreeRTOS
  6. Implement production-quality firmware practices
  7. Design state machines for complex device coordination

Deep Theoretical Foundation

ESP32 Flash Partition Architecture

The ESP32โ€™s flash memory is divided into partitions. Understanding this is critical for OTA updates.

Flash Memory Layout (4MB typical):
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ 0x0000 โ”‚ 2nd stage bootloader (0x8000 bytes)                   โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ 0x8000 โ”‚ Partition Table (0x1000 bytes)                        โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ 0x9000 โ”‚ NVS - Non-Volatile Storage (0x6000 bytes)             โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ 0xF000 โ”‚ OTA Data (0x2000 bytes) - which partition to boot     โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ 0x10000โ”‚ ota_0 - First app partition (1.5MB)                   โ”‚
โ”‚        โ”‚ Contains: Application firmware image                   โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ 0x190000โ”‚ ota_1 - Second app partition (1.5MB)                  โ”‚
โ”‚         โ”‚ Contains: OTA update image                            โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ 0x310000โ”‚ SPIFFS/FAT - Filesystem (remaining space)            โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Partition Table Definition

# Name,   Type, SubType, Offset,  Size,    Flags
nvs,      data, nvs,     0x9000,  0x6000,
otadata,  data, ota,     0xF000,  0x2000,
ota_0,    app,  ota_0,   0x10000, 0x180000,
ota_1,    app,  ota_1,   0x190000,0x180000,
storage,  data, spiffs,  0x310000,0xF0000,

OTA Update Mechanism

The OTA process ensures safe firmware updates with automatic rollback.

                    OTA Update Flow

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                       Normal Operation                         โ”‚
โ”‚                                                                โ”‚
โ”‚   Bootloader reads OTA data partition                         โ”‚
โ”‚        โ†“                                                       โ”‚
โ”‚   "Boot from ota_0"                                            โ”‚
โ”‚        โ†“                                                       โ”‚
โ”‚   Load and run firmware from ota_0                            โ”‚
โ”‚                                                                โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                           โ”‚
                    User triggers update
                           โ†“
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                       OTA Update                               โ”‚
โ”‚                                                                โ”‚
โ”‚   1. Get next update partition (ota_1)                        โ”‚
โ”‚   2. Begin OTA: esp_ota_begin()                               โ”‚
โ”‚   3. Download firmware in chunks                              โ”‚
โ”‚   4. Write each chunk: esp_ota_write()                        โ”‚
โ”‚   5. Finalize: esp_ota_end()                                  โ”‚
โ”‚   6. Verify SHA256 checksum                                   โ”‚
โ”‚   7. Set next boot partition: esp_ota_set_boot_partition()    โ”‚
โ”‚   8. Reboot                                                    โ”‚
โ”‚                                                                โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                           โ”‚
                         Reboot
                           โ†“
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                    First Boot (Pending Verify)                 โ”‚
โ”‚                                                                โ”‚
โ”‚   Bootloader loads ota_1 (new firmware)                       โ”‚
โ”‚        โ†“                                                       โ”‚
โ”‚   Firmware runs diagnostic checks                             โ”‚
โ”‚        โ†“                                                       โ”‚
โ”‚   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚
โ”‚   โ”‚ Checks PASS?                                             โ”‚ โ”‚
โ”‚   โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚
โ”‚   โ”‚ YES: esp_ota_mark_app_valid_cancel_rollback()           โ”‚ โ”‚
โ”‚   โ”‚      โ†’ OTA committed, ota_1 is now the boot partition   โ”‚ โ”‚
โ”‚   โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚
โ”‚   โ”‚ NO:  Don't mark valid                                    โ”‚ โ”‚
โ”‚   โ”‚      โ†’ Reboot โ†’ Bootloader sees invalid โ†’ boots ota_0   โ”‚ โ”‚
โ”‚   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
โ”‚                                                                โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Rollback States

esp_ota_img_states_t state;
esp_ota_get_state_partition(running, &state);

switch (state) {
    case ESP_OTA_IMG_NEW:
        // Just written, never booted
        break;
    case ESP_OTA_IMG_PENDING_VERIFY:
        // First boot after OTA, must validate
        if (run_diagnostics()) {
            esp_ota_mark_app_valid_cancel_rollback();
        }
        break;
    case ESP_OTA_IMG_VALID:
        // Confirmed working
        break;
    case ESP_OTA_IMG_INVALID:
        // Boot failed, will rollback
        break;
    case ESP_OTA_IMG_ABORTED:
        // OTA was aborted
        break;
}

WiFi + ESP-NOW Coexistence

ESP32 has a single 2.4GHz radio shared between WiFi and ESP-NOW. They can coexist with constraints.

        Single Radio Sharing

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                         2.4 GHz Radio                            โ”‚
โ”‚                                                                  โ”‚
โ”‚   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”‚
โ”‚   โ”‚                    Time Division                         โ”‚   โ”‚
โ”‚   โ”‚                                                          โ”‚   โ”‚
โ”‚   โ”‚   WiFi TX โ”‚ ESP-NOW โ”‚ WiFi RX โ”‚ ESP-NOW โ”‚ WiFi TX โ”‚...   โ”‚   โ”‚
โ”‚   โ”‚   โ†โ”€โ”€โ”€โ”€โ”€โ†’ โ”‚ โ†โ”€โ”€โ”€โ”€โ”€โ†’ โ”‚ โ†โ”€โ”€โ”€โ”€โ”€โ†’ โ”‚ โ†โ”€โ”€โ”€โ”€โ”€โ†’ โ”‚ โ†โ”€โ”€โ”€โ”€โ”€โ†’ โ”‚      โ”‚   โ”‚
โ”‚   โ”‚                                                          โ”‚   โ”‚
โ”‚   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ”‚
โ”‚                                                                  โ”‚
โ”‚   CRITICAL: Both must use the SAME WiFi channel!                โ”‚
โ”‚                                                                  โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Channel Synchronization

// 1. Connect to WiFi first
esp_wifi_set_mode(WIFI_MODE_STA);
wifi_config_t wifi_config = {
    .sta = {
        .ssid = "YourNetwork",
        .password = "YourPassword",
    },
};
esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config);
esp_wifi_start();
esp_wifi_connect();

// 2. After connection, get the channel
wifi_ap_record_t ap_info;
esp_wifi_sta_get_ap_info(&ap_info);
uint8_t wifi_channel = ap_info.primary;

// 3. ESP-NOW uses same channel automatically
esp_now_init();  // Will use wifi_channel

// 4. Lock WiFi to this channel (prevent roaming)
esp_wifi_set_channel(wifi_channel, WIFI_SECOND_CHAN_NONE);

If WiFi roams to a different channel, ESP-NOW will break! Use esp_wifi_set_channel() to lock it.

REST API Design for Embedded Systems

REST APIs on microcontrollers are simpler than traditional web servers but follow the same principles.

HTTP Methods:

GET    - Retrieve data (read-only)
POST   - Create/trigger action
PUT    - Update resource
DELETE - Remove resource

Endpoints for Smart Hub:

GET  /api/sensors          โ†’ All sensor readings
GET  /api/sensors/{mac}    โ†’ Single sensor
GET  /api/status           โ†’ Hub status
POST /api/ota/update       โ†’ Trigger OTA update
POST /api/hub/restart      โ†’ Restart hub
POST /api/sensors/{mac}/pair โ†’ Pair new sensor

JSON Response Format

// GET /api/sensors
{
  "sensors": [
    {
      "mac": "A8:42:E3:4D:2F:11",
      "name": "Living Room",
      "type": "temperature",
      "temperature": 22.3,
      "humidity": 45,
      "battery": 87,
      "rssi": -45,
      "last_seen": "2024-12-27T16:15:12Z"
    },
    {
      "mac": "A8:42:E3:4D:2F:22",
      "name": "Bedroom",
      "type": "motion",
      "motion": true,
      "last_seen": "2024-12-27T16:15:18Z"
    }
  ],
  "count": 2,
  "hub_uptime": 1324980
}

State Machine Design

Complex embedded systems benefit from explicit state machines.

Hub State Machine:

                    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
         โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ†’โ”‚   BOOTING   โ”‚โ†โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
         โ”‚          โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”˜          โ”‚
         โ”‚                 โ”‚                 โ”‚
         โ”‚    init completeโ”‚                 โ”‚ rollback
         โ”‚                 โ–ผ                 โ”‚
         โ”‚          โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”          โ”‚
         โ”‚          โ”‚ VALIDATING  โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
         โ”‚          โ”‚ (first boot)โ”‚
         โ”‚          โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”˜
         โ”‚                 โ”‚
         โ”‚     validation  โ”‚ pass
         โ”‚                 โ–ผ
         โ”‚          โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
         โ”‚     โ”Œโ”€โ”€โ”€โ†’โ”‚   RUNNING   โ”‚โ†โ”€โ”€โ”€โ”
         โ”‚     โ”‚    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ”‚
         โ”‚     โ”‚           โ”‚           โ”‚
         โ”‚     โ”‚  OTA      โ”‚   WiFi    โ”‚
         โ”‚     โ”‚  request  โ”‚   lost    โ”‚
         โ”‚     โ”‚           โ–ผ           โ”‚
         โ”‚     โ”‚    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”‚
         โ”‚     โ”‚    โ”‚  UPDATING   โ”‚    โ”‚
         โ”‚     โ”‚    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ”‚
         โ”‚     โ”‚           โ”‚           โ”‚
         โ”‚     โ”‚  success  โ”‚   fail    โ”‚
         โ”‚     โ”‚           โ”‚           โ”‚
         โ”‚     โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
         โ”‚                 โ”‚
         โ”‚            reboot
         โ”‚                 โ”‚
         โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Memory Management Considerations

Long-running embedded systems must carefully manage memory.

ESP32 Memory Map:

Total DRAM: 520 KB
โ”œโ”€โ”€ Static allocations (code, globals): ~150 KB
โ”œโ”€โ”€ FreeRTOS heaps: ~50 KB
โ”œโ”€โ”€ WiFi/BLE stacks: ~100 KB
โ”œโ”€โ”€ HTTP server buffers: ~30 KB
โ”œโ”€โ”€ JSON parsing: ~10 KB per request
โ”œโ”€โ”€ Sensor database: ~5 KB
โ””โ”€โ”€ Free heap: ~175 KB

CRITICAL: OTA requires ~50-100KB continuous block!

Heap Fragmentation

Healthy Heap:
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ                    FREE                    โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Fragmented Heap:
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ โ–ˆโ–ˆโ–ˆโ–ˆ FREE โ–ˆ FREE โ–ˆโ–ˆโ–ˆ FREE โ–ˆโ–ˆ FREE โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ FREE โ–ˆโ–ˆโ–ˆ FREE โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
Largest free block might be only 10KB even with 100KB total free!

Prevention:

  • Allocate large buffers at startup
  • Use fixed-size pools for repeated allocations
  • Avoid string manipulation with dynamic allocation

Project Specification

Hardware Requirements

Component Quantity Purpose
ESP32 DevKit (Hub) 1 Central controller
ESP32 DevKit (Nodes) 2-5 Sensor nodes
BME280 Sensors 2-5 Environmental sensing
PIR Motion Sensors 1-2 Motion detection
Door/Window Sensor 1-2 Reed switch + magnet
3.7V LiPo Batteries 2-5 Node power

System Architecture

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                                                                  โ”‚
โ”‚                        Home Network                              โ”‚
โ”‚                                                                  โ”‚
โ”‚    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                                              โ”‚
โ”‚    โ”‚   Router    โ”‚โ—€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”˜                                           โ”‚  โ”‚
โ”‚           โ”‚ WiFi                                              โ”‚  โ”‚
โ”‚           โ”‚                                                   โ”‚  โ”‚
โ”‚    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”       โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”โ”‚  โ”‚
โ”‚    โ”‚             โ”‚       โ”‚      Smart Home Hub               โ”‚โ”‚  โ”‚
โ”‚    โ”‚  Home       โ”‚       โ”‚                                   โ”‚โ”‚  โ”‚
โ”‚    โ”‚  Assistant  โ”‚โ—€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”‚โ”‚  โ”‚
โ”‚    โ”‚             โ”‚ REST  โ”‚  โ”‚WiFi  โ”‚  โ”‚ESP-NOWโ”‚  โ”‚HTTP  โ”‚   โ”‚โ”‚  โ”‚
โ”‚    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ API   โ”‚  โ”‚Stack โ”‚  โ”‚Recv   โ”‚  โ”‚Serverโ”‚   โ”‚โ”‚  โ”‚
โ”‚                          โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ”‚โ”‚  โ”‚
โ”‚                          โ”‚       โ–ฒ                           โ”‚โ”‚  โ”‚
โ”‚                          โ”‚       โ”‚ESP-NOW                    โ”‚โ”‚  โ”‚
โ”‚                          โ”‚       โ”‚                           โ”‚โ”‚  โ”‚
โ”‚                          โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜โ”‚  โ”‚
โ”‚                                  โ”‚                             โ”‚  โ”‚
โ”‚           โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”     โ”‚  โ”‚
โ”‚           โ”‚                      โ”‚                      โ”‚     โ”‚  โ”‚
โ”‚    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”       โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”       โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”โ”‚
โ”‚    โ”‚ Sensor Node โ”‚       โ”‚ Sensor Node โ”‚       โ”‚ Sensor Node โ”‚โ”‚
โ”‚    โ”‚  (Battery)  โ”‚       โ”‚  (Battery)  โ”‚       โ”‚  (Battery)  โ”‚โ”‚
โ”‚    โ”‚             โ”‚       โ”‚             โ”‚       โ”‚             โ”‚โ”‚
โ”‚    โ”‚  BME280     โ”‚       โ”‚  PIR Motion โ”‚       โ”‚  Door Reed  โ”‚โ”‚
โ”‚    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜       โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜       โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜โ”‚
โ”‚                                                                โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

API Endpoints

Endpoint Method Description
/api/sensors GET List all sensors
/api/sensors/{mac} GET Single sensor data
/api/status GET Hub status info
/api/ota/update POST Trigger OTA update
/api/ota/status GET OTA progress
/api/hub/restart POST Restart hub
/api/config GET/PUT Hub configuration

Functional Requirements

  1. ESP-NOW Reception
    • Receive data from up to 20 sensor nodes
    • Support multiple sensor types (temp, motion, door)
    • Track last-seen timestamp for each node
    • Detect offline nodes (>5 minute timeout)
  2. REST API
    • Serve JSON responses
    • Handle concurrent clients
    • CORS headers for browser access
    • Basic authentication (optional)
  3. OTA Updates
    • Download firmware from HTTP URL
    • Verify SHA256 checksum
    • Automatic rollback on boot failure
    • Progress reporting via API
  4. Data Persistence
    • Store sensor names in NVS
    • Preserve configuration across reboots
    • Log recent events to circular buffer
  5. Reliability
    • Watchdog timer for recovery
    • WiFi reconnection handling
    • Graceful degradation under load

Solution Architecture

Task Structure

// Task list and priorities
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Task Name        โ”‚ Priority โ”‚ Core โ”‚ Stack โ”‚ Purpose          โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ wifi_manager     โ”‚    10    โ”‚   0  โ”‚  4KB  โ”‚ Connection mgmt  โ”‚
โ”‚ espnow_receiver  โ”‚     8    โ”‚   0  โ”‚  4KB  โ”‚ Receive sensors  โ”‚
โ”‚ http_server      โ”‚     5    โ”‚   1  โ”‚  8KB  โ”‚ REST API         โ”‚
โ”‚ sensor_manager   โ”‚     4    โ”‚   1  โ”‚  4KB  โ”‚ Data processing  โ”‚
โ”‚ ota_handler      โ”‚     6    โ”‚   1  โ”‚ 12KB  โ”‚ Firmware updates โ”‚
โ”‚ watchdog         โ”‚    15    โ”‚   0  โ”‚  2KB  โ”‚ Health monitoringโ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Data Structures

// Sensor node representation
typedef struct {
    uint8_t mac[6];
    char name[32];
    sensor_type_t type;
    union {
        struct {
            float temperature;
            float humidity;
            float pressure;
        } environmental;
        struct {
            bool motion_detected;
            uint32_t last_motion_time;
        } motion;
        struct {
            bool is_open;
        } door;
    } data;
    uint8_t battery_percent;
    int8_t rssi;
    uint32_t last_seen;
    bool online;
} sensor_node_t;

#define MAX_SENSORS 20
sensor_node_t sensor_db[MAX_SENSORS];

// Hub configuration
typedef struct {
    char hub_name[32];
    uint16_t sensor_timeout_sec;
    bool ota_auto_update;
    char ota_url[128];
} hub_config_t;

// OTA state
typedef struct {
    ota_state_t state;
    uint32_t bytes_written;
    uint32_t total_bytes;
    char error_message[64];
} ota_status_t;

ESP-NOW Protocol

// Sensor data packet (sent from nodes)
typedef struct {
    uint8_t packet_type;
    uint8_t sensor_type;
    uint8_t battery_percent;
    union {
        struct {
            float temperature;
            float humidity;
            float pressure;
        } env;
        struct {
            uint8_t motion;
        } motion;
        struct {
            uint8_t door_open;
        } door;
    } data;
    uint32_t sequence;
} __attribute__((packed)) sensor_packet_t;

// Maximum: 250 bytes per ESP-NOW packet
// This struct: ~20 bytes - plenty of room

Phased Implementation Guide

Phase 1: Basic Hub Structure (Day 1-3)

Goal: WiFi connected hub with REST endpoint

  1. WiFi Connection
    • Connect to network
    • Print IP address
    • Handle disconnections
  2. HTTP Server
    • Start server on port 80
    • Serve /api/status endpoint
    • Return hub uptime and version
  3. Test with curl
    curl http://192.168.1.150/api/status
    # {"version":"1.0.0","uptime":3600,"wifi_rssi":-42}
    

Checkpoint: Hub serves REST API over WiFi

Phase 2: ESP-NOW Reception (Day 4-7)

Goal: Receive data from sensor nodes

  1. ESP-NOW Initialization
    • Initialize ESP-NOW stack
    • Register receive callback
    • Handle channel synchronization with WiFi
  2. Create Sensor Node
    • Simple node firmware (separate project)
    • Read BME280 sensor
    • Send via ESP-NOW every 30 seconds
  3. Parse and Store Data
    • Decode incoming packets
    • Update sensor database
    • Log to serial for debugging
  4. REST Endpoint
    • Add /api/sensors endpoint
    • Return JSON array of sensors

Checkpoint: /api/sensors shows data from sensor node

Phase 3: Sensor Management (Day 8-12)

Goal: Robust multi-sensor handling

  1. Multiple Sensor Types
    • Support temperature, motion, door sensors
    • Different packet parsing per type
    • Unified database structure
  2. Online/Offline Detection
    • Track last_seen timestamp
    • Mark offline after timeout
    • Resume online when data received
  3. Persistence
    • Store sensor names in NVS
    • Load on boot
    • API endpoint to rename sensors
  4. Add More Sensors
    • Flash 2-3 sensor nodes
    • Verify all appear in API
    • Test offline detection

Checkpoint: Multiple sensors visible, offline detection works

Phase 4: OTA Implementation (Day 13-20)

Goal: Remote firmware updates with rollback

  1. Partition Table
    • Configure dual OTA partitions
    • Verify with esptool.py read_flash
  2. OTA Download
    • Accept URL in POST request
    • Download firmware in chunks
    • Write to inactive partition
  3. Verification and Boot
    • Check SHA256 after download
    • Set boot partition
    • Reboot
  4. Rollback Logic
    • Run diagnostics on first boot
    • Mark valid if passing
    • Automatic rollback if not marked valid
  5. API Integration
    • /api/ota/update triggers update
    • /api/ota/status shows progress
    • Test with intentionally broken firmware

Checkpoint: Can update firmware remotely, rollback works

Phase 5: Production Hardening (Day 21-30)

Goal: Reliable long-term operation

  1. Watchdog Timer
    • Enable task watchdog
    • Reset periodically in main loop
    • Test by creating infinite loop
  2. Error Handling
    • Catch and log all errors
    • Graceful degradation
    • Rate limiting for API
  3. Memory Monitoring
    • Log heap usage periodically
    • Alert on low memory
    • Profile for leaks
  4. Home Assistant Integration
    • Configure REST sensor in HA
    • Create dashboard
    • Test automations

Testing Strategy

Unit Tests

Component Test Expected Result
WiFi Connect IP assigned
HTTP GET /api/status Valid JSON
ESP-NOW Receive packet Data in callback
OTA Download file Bytes written
NVS Write/read Same value

Integration Tests

  1. Multi-Node Communication
    • All 5 sensors sending data
    • API shows all sensors
    • No packet loss
  2. OTA Update Cycle
    • Deploy new version remotely
    • Hub updates and reboots
    • New version running
  3. Rollback Scenario
    • Deploy broken firmware
    • Hub auto-rollbacks
    • Previous version restored

Stress Tests

  1. Long Duration
    • Run for 7 days continuous
    • Monitor memory usage
    • Check for WiFi drops
  2. Concurrent Clients
    • 10 clients polling API
    • No timeouts or errors
    • Response time < 500ms

Common Pitfalls and Debugging

OTA Issues

Problem: OTA download fails

  • Check URL is accessible from ESP32
  • Verify firewall allows connection
  • Check available heap (need ~50KB)

Problem: Rollback happens unexpectedly

  • Boot validation not called
  • Diagnostic check failing
  • Power loss during verification window

Problem: Canโ€™t fit firmware in partition

  • Firmware too large
  • Resize partitions
  • Optimize with -Os flag

ESP-NOW Issues

Problem: Packets not received

  • WiFi and ESP-NOW on different channels
  • Sender not added as peer
  • Radio busy with WiFi traffic

Problem: Intermittent reception

  • Signal too weak
  • WiFi traffic saturating radio
  • Reduce WiFi bandwidth

API Issues

Problem: Concurrent request crashes

  • Stack overflow in HTTP task
  • JSON buffer too small
  • Memory exhaustion

Problem: Response too large

  • Enable chunked transfer
  • Paginate results
  • Compress JSON

Extensions and Challenges

Beginner Extensions

  1. Web Dashboard
    • Serve HTML from SPIFFS
    • Real-time updates with WebSocket
    • Mobile-friendly design
  2. Multiple Hubs
    • Mesh of hubs for large homes
    • Synchronized sensor data
    • Failover capability

Intermediate Challenges

  1. Secure OTA
    • HTTPS for firmware download
    • Firmware signature verification
    • Encrypted NVS
  2. MQTT Integration
    • Publish sensor data to MQTT
    • Home Assistant auto-discovery
    • Control devices via MQTT

Advanced Challenges

  1. Full Edge Computing
    • Run automation rules on hub
    • No cloud dependency
    • Local voice control
  2. Commercial Grade
    • Factory provisioning
    • Cloud management portal
    • Mass OTA deployment

Real-World Connections

Commercial Products

Product Your Project Skill
Philips Hue Bridge Hub + sensors, OTA
SmartThings Hub Multi-protocol, REST API
Home Assistant Local control, integration
AWS IoT Greengrass Edge + cloud, OTA

Industry Practices

Practice Where You Applied It
A/B Partitions OTA update scheme
Rollback Boot validation
State Machines Device coordination
REST API External integration
Watchdog Reliability

Resources

Official Documentation

Resource URL
ESP-IDF OTA docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/ota.html
ESP-NOW docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_now.html
Partition Tables docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/partition-tables.html

Books

Book Author Relevant Chapters
Making Embedded Systems Elecia White Ch. 8 (State Machines), Ch. 10 (Updates)
Mastering FreeRTOS FreeRTOS.org All chapters (free PDF)
Design and Build Great Web APIs Mike Amundsen Ch. 1-3: REST principles

Self-Assessment Checklist

Fundamentals

  • I can explain the OTA update flow and rollback mechanism
  • I understand why WiFi and ESP-NOW must share a channel
  • I can design a REST API for embedded systems
  • I know how to prevent heap fragmentation

Implementation

  • Hub receives data from multiple sensor nodes
  • REST API returns sensor data correctly
  • OTA update completes successfully
  • Rollback works when new firmware fails

Production Quality

  • Watchdog prevents permanent hangs
  • Memory usage is stable over 24+ hours
  • System recovers from WiFi disconnections
  • Sensors are properly detected as online/offline

Interview Preparation

Be ready to answer these questions:

  1. โ€œExplain how OTA updates work without bricking the device.โ€
    • Dual partitions, download to inactive, verify, switch boot, rollback on failure
  2. โ€œWhat happens if WiFi and ESP-NOW are on different channels?โ€
    • ESP-NOW packets lost, must lock WiFi channel
  3. โ€œHow do you ensure sensor data isnโ€™t lost during OTA?โ€
    • Brief interruption acceptable, or buffer in NVS
  4. โ€œWalk through the partition table. Whatโ€™s in each partition?โ€
    • Bootloader, partition table, NVS, OTA data, ota_0, ota_1, storage
  5. โ€œHow do you verify firmware integrity?โ€
    • SHA256 hash comparison, optional RSA signature
  6. โ€œWhat causes heap fragmentation and how do you prevent it?โ€
    • Variable-size allocations, use pools, allocate at startup

Complete Project Synthesis

After completing all five projects, youโ€™ll have built:

  1. Environmental Monitor - Core ESP32 skills
  2. BLE Controller - Wireless protocol mastery
  3. Deep Sleep Logger - Battery-powered IoT
  4. Audio Spectrum Analyzer - Real-time DSP
  5. Smart Home Hub - Production firmware

Combined, you can build a Complete Home Automation System:

  • Multiple battery-powered sensors (Project 3)
  • Central hub with web interface (Project 5)
  • Mobile app via BLE (Project 2)
  • Real-time feedback (Project 4)
  • Environmental monitoring (Project 1)

This represents professional-level ESP32 expertise applicable to IoT product development, embedded systems engineering, and smart home technology.


This concludes the ESP32 Programming Learning Projects series.