ESP32 Firmware Hacking
Resources for customizing ESP32 CSI firmware.
Directory Structure
esp32-hacking/
├── get-started/ # Basic CSI examples (CURRENTLY USED)
│ ├── csi_recv_router/ # <-- OUR FIRMWARE (modified for UDP)
│ ├── csi_recv/ # Basic receiver (serial output)
│ ├── csi_send/ # CSI transmitter
│ └── tools/ # Python CSI parsing tools
├── esp-radar/ # Advanced presence detection
│ ├── console_test/ # Interactive CSI testing console
│ └── connect_rainmaker/ # IoT cloud integration
├── esp-crab/ # Dual-antenna experiments
│ ├── master_recv/ # Master receiver
│ ├── slave_recv/ # Slave receiver
│ └── slave_send/ # Slave transmitter
└── README.md # This file
Current Firmware
Source: get-started/csi_recv_router/
Origin: Espressif esp-csi example, modified for UDP output
Deployed on: 3x ESP32-DevKitC V1
What It Does
- Connects to WiFi router as station
- Pings gateway at 100 Hz to generate CSI frames
- On each CSI callback, formats data as text
- Sends via UDP to Pi (port 5500)
Key Settings (sdkconfig.defaults)
| Setting | Value | Purpose |
|---|---|---|
CONFIG_ESP32_WIFI_CSI_ENABLED |
y | Enable CSI extraction |
CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED |
(empty) | Disable TX aggregation |
CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM |
128 | Large RX buffer |
CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ |
240 | Max CPU speed |
CONFIG_FREERTOS_HZ |
1000 | 1ms tick resolution |
CONFIG_ESP_TASK_WDT_TIMEOUT_S |
30 | Watchdog timeout |
CONFIG_COMPILER_OPTIMIZATION_PERF |
y | Performance optimization |
Custom Config (Kconfig.projbuild)
| Config | Description |
|---|---|
CONFIG_CSI_UDP_TARGET_IP |
Pi's IP address (192.168.129.11) |
CONFIG_CSI_UDP_TARGET_PORT |
UDP port (5500) |
CSI Data Format
CSI_DATA,<seq>,<mac>,<rssi>,<rate>,<sig_mode>,<mcs>,<cwb>,<smoothing>,
<not_sounding>,<aggregation>,<stbc>,<fec_coding>,<sgi>,<noise_floor>,
<ampdu_cnt>,<channel>,<secondary_channel>,<timestamp>,<ant>,<sig_len>,
<rx_state>,<len>,<first_word_invalid>,"[csi_values]"
Build & Flash
source ~/esp/esp-idf/export.sh
cd ~/esp/esp-csi/examples/get-started/csi_recv_router
idf.py menuconfig # Change WiFi SSID/password, UDP target IP
idf.py build
idf.py -p /dev/ttyUSB0 flash
idf.py -p /dev/ttyUSB0 monitor # View serial output
Firmware Modification Ideas
1. Remote Commands (UDP bidirectional)
Add a UDP listener on the ESP32 to receive commands from the Pi.
// Commands to implement:
// REBOOT - restart ESP32
// IDENTIFY - blink onboard LED for 5 seconds
// STATUS - reply with uptime, free heap, RSSI, chip temp
// RATE <n> - change ping/CSI rate (packets per second)
// OTA <url> - trigger OTA firmware update
Complexity: Low Impact: High - enables remote management without USB
2. Adaptive Sampling Rate
Reduce packet rate when no presence detected, increase on motion.
// Idle: 10 pkt/s (saves power, bandwidth)
// Active: 100 pkt/s (full resolution)
// Trigger: wander threshold on-device
Complexity: Medium (needs on-device wander calculation) Impact: Medium - reduces Pi CPU load by ~90% when idle
3. On-Device CSI Processing
Pre-compute amplitude on ESP32, send only metrics.
// Instead of raw CSI (128 int16 values per packet = 256 bytes):
// Send: "METRICS,<seq>,<rssi>,<wander>,<jitter>,<amplitude_mean>"
// ~50 bytes per packet instead of ~500
Complexity: Medium Impact: High - 80% bandwidth reduction
4. LED Status Indicator
Use onboard LED (GPIO2 on most DevKitC) for status.
// Off: No WiFi connection
// Slow blink: Connected, no CSI activity
// Fast blink: Sending CSI data
// Solid: Identify mode (triggered by command)
Complexity: Low Impact: Low - quality of life
5. BLE Scanning
ESP32 has Bluetooth. Scan for nearby BLE devices.
// Periodically scan for BLE advertisements
// Report: MAC, RSSI, device name
// Use for: phone/wearable proximity detection
// Complements CSI: confirms person is home (phone detected)
Complexity: Medium Impact: High - adds a second detection method
6. OTA (Over-The-Air) Updates
Flash new firmware via WiFi without USB.
// ESP-IDF has built-in OTA support
// Pi serves firmware binary via HTTP
// ESP32 downloads and flashes
// Requires dual OTA partition scheme
Complexity: Medium (partition table change needed) Impact: High - no more USB flashing
7. ESP-NOW Mesh
Direct ESP32-to-ESP32 communication without router.
// Active CSI: ESP32-A sends, ESP32-B measures CSI
// More reliable than passive router beacon monitoring
// Can work even if WiFi router goes down
Complexity: High (requires re-architecting firmware) Impact: High - better CSI quality
8. Temperature Reporting
ESP32 has internal temperature sensor.
// Read chip temperature
// Send with CSI data or as separate status packet
// Useful for monitoring device health
Complexity: Low Impact: Low - monitoring
9. mDNS Auto-Discovery
Announce device on network, no need for static IPs.
// Register as: <device-name>.local
// Pi discovers sensors automatically
// No manual IP configuration needed
Complexity: Low Impact: Medium - easier deployment
10. Watchdog + Auto-Recovery
Better error handling and self-healing.
// Monitor WiFi connection, reconnect on drop
// Monitor UDP send failures
// Track heap fragmentation
// Reboot if stuck for >60 seconds
Complexity: Low Impact: Medium - reliability
Priority Order (Recommended)
| Priority | Feature | Why |
|---|---|---|
| 1 | Remote commands | Remote reboot + identify = essential |
| 2 | LED status | Easy win, helps debugging |
| 3 | OTA updates | Stop walking to each sensor with USB |
| 4 | Adaptive rate | Save CPU/power when idle |
| 5 | mDNS | Easier deployment |
| 6 | BLE scanning | Second detection method |
| 7 | On-device processing | Bandwidth optimization |
| 8 | Temperature | Nice to have |
| 9 | ESP-NOW mesh | Major rewrite, big payoff |
| 10 | Watchdog improvements | Production hardening |
ESP-CSI Tools
Python CSI Parser (get-started/tools/)
csi_data_read_parse.py- PyQt5 GUI for live CSI visualization- Shows amplitude and phase plots in real-time
ESP Radar Console (esp-radar/console_test/)
- Interactive console for testing CSI features
- Includes
esp_csi_tool.pyCLI and GUI tools - Built-in presence detection algorithms