Harvests verified facts about espressif/esp-idf and espressif/arduino-esp32 directly from their real git history — instead of hand-typed tables that go stale and get guessed at. Three axes, four harvesters, real provenance on every fact.
New here? Read ABOUT.md first — it explains the problem this solves and why it matters, with a real historical example of what happens without it.
| Axis | Question | Answered by |
|---|---|---|
| Version | Since which ESP-IDF release does enum member X exist? | esp_reset_reason_t, esp_sleep_source_t harvesters |
| Target | Does this chip's hardware actually support this feature? | soc_caps.h harvester |
| Framework | Does Arduino-ESP32 support this chip, and which ESP-IDF does it pin? | idf_component.yml harvester |
A #ifdef check can only ever answer one of these at a time — and picking the wrong one is exactly how projects end up with silently-broken guards. See ABOUT.md for the historical case that motivated this.
The harvested facts are already in data/*.yaml — you don't need Python or network access just to read them.
cat data/esp_sleep_source_t.harvested.yamlEach file has the same shape:
enum: esp_sleep_source_t
header: components/esp_hw_support/include/esp_sleep.h
repo: https://github.com/espressif/esp-idf
harvested_tags: [ ... ] # every ref actually checked, with commit SHA
members:
ESP_SLEEP_WAKEUP_VAD:
first_seen_tag: v5.4
first_seen_commit: 67c1de1eebe095d554d281952fde63c16ee2dca0
source_url: https://raw.githubusercontent.com/espressif/esp-idf/v5.4/...Every fact traces back to a specific commit you can go look at yourself.
Each harvester is a standalone script. Running it re-fetches from the real GitHub repos and rewrites its data/*.yaml output.
cd tools
pip install pyyaml --break-system-packages # only dependency
python3 harvest_reset_enum.py
python3 harvest_wakeup_enum.py
python3 harvest_soc_caps.py
python3 harvest_arduino_targets.pyEach prints a summary table to stdout before writing its YAML — useful for a quick sanity check without opening the file.
To extend a harvester to a new tag, target, or macro: edit the relevant list near the top of the script (TAGS_IN_ORDER, TARGETS, or MACROS_OF_INTEREST) and re-run. The parsing logic doesn't need to change.
examples/generate_capability_header/ is a worked reference, not a one-size-fits-all tool — copy and adapt it, don't import it as-is. It shows the full pipeline: read data/*.yaml → emit #if/#define guards with the correct mechanism per axis.
cd examples/generate_capability_header
python3 generate_capability_header.pyThe critical detail worth copying exactly, not just the output: which C preprocessor mechanism applies to which axis.
// Axis 1 (version) — enum members are NOT preprocessor-visible.
// #ifdef/#if defined() on an enum member ALWAYS evaluates false,
// silently, on every target and every ESP-IDF version. Use a numeric
// version comparison instead:
#if defined(ESP_IDF_VERSION) && ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 4, 0)
#define MY_HAS_WAKEUP_VAD 1
#else
#define MY_HAS_WAKEUP_VAD 0
#endif
// Axis 2 (target) — soc_caps.h macros ARE real #defines, #if defined() works:
#if defined(SOC_BOD_SUPPORTED)
#define MY_HAS_BOD 1
#else
#define MY_HAS_BOD 0
#endif
// Axis 3 (framework) — __has_include, not #ifdef ESP32. The latter is not
// auto-defined under "Arduino as an ESP-IDF component," a documented,
// officially-supported build path (needed for esp32c2/esp32c61) where
// <Arduino.h> is genuinely includable but ARDUINO/ESP32 build macros are not:
#if __has_include(<Arduino.h>)
#define MY_FRAMEWORK_ARDUINO 1
#else
#define MY_FRAMEWORK_ARDUINO 0
#endifMixing these up — testing an enum member with #ifdef, or testing framework presence with a macro that isn't reliably auto-defined — is precisely how the historical failure in ABOUT.md happened.
Don't trust that generated #if logic is correct just because it compiles — a guard that's silently always false still compiles cleanly. verify/verify_generated.cpp proves the guards evaluate correctly by simulating two different ESP_IDF_VERSION values and checking the resulting macro values are exactly what's expected:
cd verify
g++ -std=c++17 -DTEST_V5_3 -I fake_arduino verify_generated.cpp -o verify_v53 && ./verify_v53
# expect: WAKEUP_VAD=0 WAKEUP_VBAT_UNDER_VOLT=0 WAKEUP_UART1=0 WAKEUP_UART2=0
g++ -std=c++17 -DTEST_V6_0 -I fake_arduino verify_generated.cpp -o verify_v60 && ./verify_v60
# expect: WAKEUP_VAD=1 WAKEUP_VBAT_UNDER_VOLT=1 WAKEUP_UART1=1 WAKEUP_UART2=1No real ESP32 hardware or toolchain needed — this runs on any machine with a C++17 compiler. It doesn't validate real-hardware behavior, only that the preprocessor logic itself is internally consistent and version-gated correctly.
Known limitations (stated plainly, not hidden)
- Target-axis coverage is partial.
soc_caps.hhas hundreds of macros;harvest_soc_caps.pycurrently checks a curated list (seeMACROS_OF_INTERESTin the script), not the whole file. - Textual "first appears," not semantic diffing. The version-axis harvesters detect the first tag where a member's name textually appears. A member removed and later re-added under the same name would be misreported as "always present." Not observed in practice, not structurally ruled out.
masteris a moving target. Any fact whosefirst_seen_tagismasterreflects an unreleased, unstable state — the commit SHA recorded is a snapshot; re-running later may find more (or find the member has moved into an actual release, and get a proper version number instead).- Not wired into CI. Harvesting is currently a manual, on-demand step, not a scheduled job that would catch drift automatically as upstream releases happen.
- GitHub REST API rate limits. Commit SHA resolution uses
git ls-remote --tagsinstead ofapi.github.com, specifically because the REST API got rate-limited during development on a shared IP. If you have API access with a token, that path is faster but isn't wired up here.
ESP-IDF-SoC-Check already solves the target axis well — it's the tool that prompted checking harvest_soc_caps.py's method against a second, independent implementation in the first place. If you're maintaining that tool and see a way the two could share data or cross-validate results, an issue or PR here is welcome. See ABOUT.md for the fuller context on how this project relates to it.
For repository discoverability once this is pushed:
esp32 esp-idf arduino-esp32 esp32-arduino embedded iot
soc-caps chip-capabilities provenance data-harvesting
fact-checking build-tools code-generation verification
MIT — see LICENSE.
See CRA-EXEMPTION.md — short version: this is a build-time tool, never shipped as part of a product, and the EU Cyber Resilience Act does not apply to it.