A production-style embedded IoT system built on the ESP32-WROOM-32 using ESP-IDF, featuring real-time sensing, persistent configuration, and a lightweight HTTP interface.
-
π‘ Wi-Fi connectivity (STA mode) with event-driven handling
-
π Embedded HTTP server
/dataendpoint returns live soil moisture in JSON
-
π SSD1306 OLED display (I2C)
- Custom framebuffer + bitmap font rendering
-
π‘οΈ ADC-based soil moisture sensing
- Averaged sampling for stability
-
πΎ Non-Volatile Storage (NVS)
- Stores Wi-Fi credentials persistently
-
βοΈ FreeRTOS-based execution
- Deterministic periodic sampling loop
-
π§ Clean modular architecture
- Separation of drivers, networking, storage, and application logic
+----------------------+
| Soil Sensor |
| (Analog Output) |
+----------+-----------+
|
v
+----------------------+
| ADC (Oneshot) |
| Averaging Filter |
+----------+-----------+
|
v
+----------------------+
| Application Logic |
| (main.c loop) |
+----+-----------+-----+
| |
v v
+----------------+ +------------------+
| OLED Display | | HTTP Server |
| (SSD1306 I2C) | | /data endpoint |
+----------------+ +------------------+
|
v
+------------------+
| Wi-Fi Stack |
| (Event Driven) |
+------------------+
|
v
+------------------+
| NVS Storage |
| (SSID/PASSWORD) |
+------------------+
Returns current soil moisture:
{
"status": "ok",
"sensor_value": 0
}- ESP32-WROOM-32
- Capacitive Soil Moisture Sensor
- SSD1306 OLED Display (128x64, I2C)
- Breadboard + jumper wires
- Pull up resistors
| Component | ESP32 Pin |
|---|---|
| Soil Sensor | GPIO34 (ADC1_CH6) |
| OLED SDA | GPIO21 |
| OLED SCL | GPIO22 |
- Uses oneshot mode instead of continuous
- 32 samples averaged to reduce noise
- Controlled delay ensures stable readings
- Full framebuffer implementation
- Manual pixel control
- Scaled bitmap font rendering (no external libs)
-
Uses ESP-IDF event loop
-
Handles:
- Connection
- Disconnection
- Auth failures
-
Tracks state via FreeRTOS Event Groups
- SSID & password stored in flash
- Abstracted via
storage.c - Safe open/read/write pattern with fallback init
- Based on
esp_http_server - Minimal memory footprint
- Shared state via controlled setter (
set_moisture())
Boot
βββ Initialize NVS
βββ Store Wi-Fi credentials
βββ Connect to Wi-Fi
βββ Initialize ADC
βββ Initialize OLED
βββ Start HTTP server
βββ Loop:
βββ Sample ADC (32 samples)
βββ Compute moisture %
βββ Update display
βββ Update HTTP state
βββ Maintain Wi-Fi connection
βββ Delay (~3.3s)
| Key | Type | Description |
|---|---|---|
ssid |
string | Wi-Fi SSID |
password |
string | Wi-Fi password |
storage_write_string() β nvs_set_str() β nvs_commit()
storage_read_string() β nvs_get_str()
- Lazy initialization handled internally
- Default fallback values supported
- Clean handle lifecycle (open β use β close)
- β Direct ESP-IDF usage
- β Understanding of embedded memory (NVS, buffers)
- β RTOS-aware design patterns
- β Driver-level hardware control
- β Networking stack integration
- No HTTPS (currently HTTP only)
- No OTA updates
- No sensor calibration curve (linear approximation used)
- Web UI could be added (currently API only)
- ADC calibration using eFuse could improve accuracy
Using PlatformIO:
pio run
pio run --target upload
pio device monitor