A low-power environmental monitoring firmware built with native ESP-IDF v5.x and PlatformIO (no Arduino framework). Wakes from Deep Sleep, reads sensors, evaluates a configurable soil moisture threshold, dispatches alerts over one or more webhook channels, and returns to sleep.
An on-demand SoftAP Web Portal ā launched by holding a physical button ā handles all runtime configuration without serial re-flashing.
Hardware & Screenshots
| Web Configurator UI | Hardware MVP | Wiring Schematic |
|---|---|---|
![]() |
![]() |
![]() |
Features
- Pure ESP-IDF v5.x ā no Arduino wrappers, no bloat.
- Deep Sleep ā timer wakeup via RTC; configurable interval (
DEFAULT_SLEEP_SEC, default 30 min). - On-Demand Web Portal ā hold
GPIO9(BOOT button) ā„ 3 s to launch the SoftAP configurator at192.168.4.1. Live sensor telemetry updates every 7 s while the portal is open. - Multi-Channel Alerts ā Telegram Bot API, Discord Webhook, and Custom JSON Webhook. Each channel is independent; a failed channel does not block the others.
- Configurable Threshold ā soil alert threshold (%) stored in NVS, adjustable via the portal.
- NVS Persistence ā Wi-Fi credentials, notification tokens/URLs, ADC calibration bounds, and alert threshold survive power cycles.
- Sensors ā capacitive soil moisture (ADC), BMP280 (I²C, temperature + pressure), DHT22 (1-Wire, temperature + humidity).
Target Hardware
| Parameter | Value |
|---|---|
| MCU | ESP32-C3 (esp32-c3-devkitm-1) |
| Flash | 2 MB, DIO mode |
| Framework | ESP-IDF 5.x |
| Toolchain | PlatformIO |
GPIO assignments are defined in include/config.h and selectable per target via build_flags in platformio.ini.
| Signal | ESP32-C3 GPIO |
|---|---|
| Soil sensor power gate | GPIO7 |
| Soil sensor ADC | GPIO2 (ADC CH1) |
| BMP280 SDA | GPIO8 |
| BMP280 SCL | GPIO9 |
| DHT22 data | GPIO10 |
| Config button (BOOT) | GPIO9 |
Strapping pin note: GPIO2 on ESP32-C3 controls boot mode. Pulling it LOW during power-on enters JTAG/download mode. Use GPIO9 (BOOT button) for the config trigger instead ā it is safe to hold LOW at any time.
Quick Start
Prerequisites
- PlatformIO Core or the VS Code PlatformIO extension
- USB cable to ESP32-C3 dev board
Build
git clone https://github.com/your-username/ESP32_EnvironmentalNode.git
cd ESP32_EnvironmentalNode
pio run --environment esp32_c3
Upload & Monitor
pio run --target upload --target monitor --environment esp32_c3
Monitor baud rate: 115200.
First-Time Setup
- Flash the firmware. On first boot
is_configured = false, so the device immediately launches the SoftAP. - Connect a phone or laptop to Wi-Fi SSID
d7main_sensor(password:admin123). - Open
http://192.168.4.1in a browser. - Fill in the form and click Write to NVS & Reboot:
| Field | Required | Notes |
|---|---|---|
| Wi-Fi SSID | Yes | Your router SSID |
| Wi-Fi Password | No | Leave blank for open networks |
| Telegram Bot Token | No | Skip to disable Telegram alerts |
| Telegram Chat ID | No | Skip to disable Telegram alerts |
| Discord Webhook URL | No | Skip to disable Discord alerts |
| Custom Webhook URL | No | Skip to disable custom alerts |
| Soil Alert Threshold (%) | No | Default: 30% |
| Dry Air (mV) | Yes | Calibration ā see below |
| Water (mV) | Yes | Calibration ā see below |
To re-enter the portal at any time: hold GPIO9 (BOOT button) for ā„ 3 seconds.
Sensor Calibration
The moisture percentage is computed linearly from two ADC calibration points:
moisture_pct = (v_dry - soil_mv) * 100 / (v_dry - v_wet)
| Step | Action |
|---|---|
| v_dry | Expose the sensor to dry open air. Read soil_mv from the Live Telemetry card in the portal, or from the serial monitor. Enter that value. |
| v_wet | Submerge the sensor tip ~1 cm in water. Read and enter soil_mv. |
Typical values: v_dry ā 2600 mV, v_wet ā 1200 mV (varies by sensor and supply voltage).
Alert Channels
Telegram
Requires a bot token and chat ID. Alert text is sent as a text message via sendMessage.
Discord Webhook
POST to the configured URL with:
{ "content": "<alert message>" }
Custom Webhook
POST to the configured URL with a full sensor payload:
{
"event": "alert",
"message": "Low soil moisture alert!\nMoisture: 18% ...",
"soil_mv": 2350,
"temp": 23.1,
"humidity": 58.0
}
All channels: Content-Type: application/json, 6-second timeout per request.
Firmware Boot Cycle
Power on / Deep Sleep wakeup
ā
āā NVS init ā load config
āā is_configured?
ā āā No ā launch SoftAP + Web Portal (blocks until form submit + reboot)
ā āā Yes ā
ā āā Spawn button monitor task (GPIO9 hold = portal escape hatch)
ā āā Read sensors (soil ADC, BMP280, DHT22)
ā āā Calculate moisture %
ā āā Connect Wi-Fi STA
��� ā āā moisture < threshold ā sys_alerts_send() [Telegram / Discord / Custom]
ā ā āā moisture OK ā log, skip alerts
ā āā Deep Sleep (DEFAULT_SLEEP_SEC = 1800 s)
NVS Key Map
| Key | Type | Field |
|---|---|---|
ssid |
str | wifi_ssid |
pass |
str | wifi_pass |
tg_tok |
str | tg_token |
tg_chat |
str | tg_chat_id |
disc_url |
str | discord_webhook_url |
cust_url |
str | custom_webhook_url |
v_dry |
i16 | v_dry_mv |
v_wet |
i16 | v_wet_mv |
soil_th_pct |
u8 | soil_alert_threshold_pct |
conf |
u8 | is_configured |
NVS namespace: storage (see NVS_NAMESPACE in config.h).
Project Structure
ESP32_EnvironmentalNode/
āāā include/
ā āāā config.h # GPIO map, sleep interval, AP credentials
ā āāā sys_nvs.h # Config struct + NVS API
ā āāā sys_wifi.h # Wi-Fi, Web Portal, sys_alerts_send()
ā āāā hal_bmp280.h
ā āāā hal_dht22.h
ā āāā hal_i2c.h
ā āāā hal_moisture.h
āāā src/
ā āāā main.c # App entry, boot cycle, operational loop
ā āāā sys_nvs.c # NVS load/save
ā āāā sys_wifi.c # AP/STA, HTTP server, alert dispatch
ā āāā hal_bmp280.c
ā āāā hal_dht22.c
ā āāā hal_i2c.c
ā āāā hal_moisture.c
āāā partitions.csv # Custom partition table (2 MB flash)
āāā platformio.ini



Comments