← Hardware Guide | Contents | Next: Commissioning →
2. Compilation
ACRouter v2.0 builds with ESP-IDF 5.5 using idf.py. It runs on two targets and ships in one
of three compile profiles — pick the one that matches your chip and how you want to control the
device.
2.1 Toolchain
- ESP-IDF 5.5 (5.5.1) — the firmware is built with ESP-IDF (
idf.py), not the Arduino IDE or PlatformIO. - Python 3.8+ and CMake 3.16+ (bundled with the ESP-IDF installer).
- Managed components are resolved automatically by the IDF Component Manager from
main/idf_component.ymlon the firstset-target/reconfigure— notably Arduino Core 3.x (espressif/arduino-esp32) and ArduinoJson v7 (bblanchon/arduinojson). ACRouter uses the Arduino API (String,millis(), …) on top of the ESP-IDF build system.
Install ESP-IDF
mkdir -p ~/esp && cd ~/esp
git clone -b v5.5.1 --recursive https://github.com/espressif/esp-idf.git
cd esp-idf
./install.sh esp32,esp32c2 # install both target toolchains
. ~/esp/esp-idf/export.sh # activate the environment (each shell)Then clone the firmware and enter it:
git clone https://github.com/robotdyn-dimmer/ACRouter.git
cd ACRouterOn Windows, use the ESP-IDF PowerShell/CMD environment and export.ps1.
2.2 Two Targets, Three Profiles
| Target | Chip | Cores | Default profile |
|---|---|---|---|
| esp32 | ESP32 (WROOM/WROVER) | dual-core | ESP32 full |
| esp32c2 | ESP32-C2 / ESP8684 | single-core, RAM-limited | one interface per build |
Each build carries exactly one compile profile:
| Profile | Target | HTTP/REST + WS | MQTT | OTA | For |
|---|---|---|---|---|---|
| ESP32 full | esp32 | ✅ | ✅ | ✅ | Full build: web + MQTT + OTA, dual-core, ESP-NOW |
| C2-HTTP | esp32c2 | ✅ | ❌ | ❌ | Web control on the C2 (REST/WS); no MQTT/OTA |
| C2-MQTT | esp32c2 | ❌ | ✅ | ❌ | Headless: MQTT only, provisioned over MQTT; no web server |
🔴 Why the tiering? The ESP32-C2 has ~272 KB RAM — not enough to hold HTTP + MQTT + TLS at once. So a C2 build carries exactly one remote interface (HTTP xor MQTT), chosen at compile time. The ESP32 has the headroom to carry both. On C2-MQTT there is no HTTP server at all — the device is reached only through the broker.
2.3 Profile Flags (Kconfig)
A profile is a set of Kconfig options, resolved from an sdkconfig.defaults layer:
| Option | Meaning |
|---|---|
CONFIG_ACROUTER_HTTP_SERVER |
HTTP/REST + WebSocket server |
CONFIG_ACROUTER_MQTT_CLIENT |
MQTT client |
CONFIG_ACROUTER_OTA |
OTA update subsystem |
CONFIG_ACROUTER_RBAMP_SOURCE |
rbAmp I2C sensing source |
CONFIG_ACROUTER_MQTT_BOOTSTRAP |
config-over-MQTT provisioning (C2-MQTT) |
On the C2 the HTTP-on / MQTT-off / OTA-off defaults are applied automatically
(default n if IDF_TARGET_ESP32C2).
🔴 Gotcha — keep profile flags in an
sdkconfig.defaultslayer, not in a hand-editedsdkconfig.idf.py set-targetregeneratessdkconfigfrom the defaults and discards manual edits. That is exactly why the headless profile ships as a separatesdkconfig.defaults.c2mqttlayer.
2.4 Build & Flash
Use a separate build directory per target so the ESP32 and C2 builds don't clobber each other.
<PORT> is COM3 (Windows) or /dev/ttyUSB0 (Linux).
ESP32 full
idf.py set-target esp32
idf.py build
idf.py -p <PORT> flashC2-HTTP
idf.py -B build_c2 -D SDKCONFIG=sdkconfig.c2 set-target esp32c2
idf.py -B build_c2 -D SDKCONFIG=sdkconfig.c2 build
idf.py -B build_c2 -D SDKCONFIG=sdkconfig.c2 -p <PORT> flashC2-MQTT (headless)
idf.py -B build_c2mqtt \
-D SDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.defaults.c2mqtt" \
set-target esp32c2
idf.py -B build_c2mqtt -D SDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.defaults.c2mqtt" build
idf.py -B build_c2mqtt -D SDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.defaults.c2mqtt" -p <PORT> flashLarge OTA-over-WiFi is impractical on the C2 — flash the C2 over serial.
Monitor
idf.py -p <PORT> monitor # picks the correct baud automatically; Ctrl-] to exitPartitions & OTA
The flash layout is dual-OTA — two app slots (app0, app1) so firmware can update over the air,
plus nvs (configuration) and otadata (which slot is active). There is no SPIFFS/web-UI
partition — the UI is external in v2.0. Exact slot sizes vary by target; the layout is defined in the
repo's partitions.csv.
2.5 Capability-Aware Runtime
A build advertises what it carries at runtime — GET /api/info returns a features object
(http, mqtt, ota, github_ota, tls). The same web app works against every profile and simply
shows only what the build supports. Gate features on these flags, never on the chip name.
{ "chip": "ESP32-C2", "features": { "http": true, "mqtt": false, "ota": false, "github_ota": false, "tls": false } }2.6 Manual Flashing (esptool)
For normal flashing use idf.py -p <PORT> flash — it already knows the right offsets. To flash without
idf.py (e.g. from another machine), match --chip to your target (esp32 or esp32c2) and use the
artifacts from the corresponding build directory:
esptool.py --chip esp32 --port <PORT> --baud 921600 \
--before default_reset --after hard_reset write_flash -z \
0x0 build/bootloader/bootloader.bin \
0x8000 build/partition_table/partition-table.bin \
0xf000 build/ota_data_initial.bin \
0x20000 build/ACRouter-project.binThe app binary is
ACRouter-project.binat offset0x20000(custom partition table). Rather than copy offsets by hand, take the exactesptool.py write_flash …line thatidf.py buildprints at the end of a build for your target.
2.7 Common Build Issues
- Wrong target / stale sdkconfig. If a C2 build behaves like an ESP32 build (or vice-versa),
your
sdkconfigwas regenerated from the wrong defaults — see the §2.3 gotcha. Use the right-B <dir>+SDKCONFIG_DEFAULTSand re-runset-target. - ESP-IDF version mismatch.
idf.py --versionmust report v5.5.x. Re-install 5.5.1 if it differs. - Dependency not found. Run
idf.py reconfigureto re-resolve managed components. - App partition too small. Ensure your build directory matches the target; a C2 image flashed against an ESP32 partition layout (or vice-versa) will not fit.
2.8 Pre-Built Binaries
Planned. Pre-built v2.0 binaries are not published yet — for now, build from source as above. When v2.0 is released, per-target/profile archives (ESP32 / C2-HTTP / C2-MQTT) with a flash script will be posted on the GitHub Releases page.