Compact reference for agents working in this repo. For full architecture and hardware context see CLAUDE.md.
WellD — ESP32-C6 battery-powered well-level monitor. ESP-IDF v6.0.1 only. One app_main() = one wakeup → read sensors → Zigbee report → deep sleep.
# First-time setup
idf.py set-target esp32c6
cp sdkconfig.defaults.local.example sdkconfig.defaults.local
# Build / flash / monitor
idf.py build
idf.py -p /dev/ttyUSB0 flash monitor
idf.py menuconfig # WellD Configuration submenu
idf.py fullclean # nukes build/ and managed_components/
# Host tests (no ESP-IDF, runs in CI)
cmake -S test/host -B test/host/build
cmake --build test/host/build
ctest --test-dir test/host/build --output-on-failure
# On-device tests (needs hardware; CI only builds them)
idf.py -C test/sensor build flash monitor
idf.py -C test/welld_core build flash monitor
# Zigbee2MQTT converter tests
cd zigbee2mqtt && npm test- Sensor reads must precede
zigbee_send()— the ADC is sensitive to 802.15.4 RF interference. - GPIO5 (VLOOP) HIGH ≥ 10 ms before 4–20 mA read, LOW immediately after. Max ON time 100 ms. (12 V rail settles through the Q3 load-disconnect P-FET into C20/C22.)
- All power-control GPIOs (4, 5, 15) must be held LOW through deep sleep via
esp_sleep_gpio_isolate(). zigbee_send()blocks until radio idle (success/timeout/OTA). Caller must wait forSTOPPED_BITbeforeesp_deep_sleep()so the radio is fully released.- 5 consecutive Zigbee failures → next boot erases NVS and forces fresh join (namespace
"welld", key"zb_fails"). - OTA_FW_VERSION is derived from
PROJECT_VERin rootCMakeLists.txtat build time. To release: bumpPROJECT_VERonly; never editOTA_FW_VERSIONdirectly. - OTA manufacturer/image type are hardcoded (
0x1234/0x0001incomponents/zigbee/zigbee.c). Do not wildcard to0xFFFF.
- Host tests reuse on-device test sources.
test/host/CMakeLists.txtcompiles them with-DHOST_BUILD, which swapsapp_main()formain()via#ifdef HOST_BUILDat the bottom of each test file. - Pure helpers only in
sensor_pure.candwelld_core.c. These files must stay free of NVS/ADC/log/freertos calls so they compile on any host. test/host/stub_sdkconfig/sdkconfig.hmirrors Kconfig defaults. Keep it in sync ifcomponents/sensor/Kconfigdefaults change.- On-device test apps must use
EXTRA_COMPONENT_DIRS = "../../components/<component>"(specific component path, not the wholecomponents/dir) — otherwise ESP-IDF discovers sibling components likezigbeeand tries to build them outside their managed-dependency context. - Guard hardware-only test cases with
#ifndef HOST_BUILD.
- Exact
==pins incomponents/sensor/idf_component.ymlandcomponents/zigbee/idf_component.yml. Bump one at a time and run a hardware build; expect API renames. - Config layering:
sdkconfig.defaults— committed, holds invariant settings (flash size, Zigbee role).sdkconfig.defaults.local— gitignored, user overrides.sdkconfig— committed and regenerated bymenuconfig. Updates land via PRs.
- New tunables go in
main/Kconfig.projbuildwith arangeclause.
| Directory | Ownership |
|---|---|
main/ |
Wake orchestration, NVS fail counter, RTC history |
components/sensor/ |
ADC, DS18B20, battery divider, GPIO power control |
components/zigbee/ |
esp-zigbee-lib wrapper, OTA client, BDB task |
components/welld_core/ |
Pure helpers: rate-of-change, adaptive sleep, ZCL encoding |
zigbee2mqtt/ |
External converter (welld.js) and its Node tests |
test/host/ |
Host CMake test runner (Unity v2.6.0) |
test/sensor/, test/welld_core/ |
Standalone ESP-IDF test apps for on-device hardware |
- One
static const char *TAGper.cfile, named for the component ("main","sensor","zigbee"). - Component
REQUIRESlists are minimal and explicit; prefer adding toREQUIRESover transitive includes. - Guard ESP32-C6-specific code with
CONFIG_IDF_TARGET_ESP32C6.
- Parallel (no shared files):
firmware+test+z2m-converter+case - Sequential:
pcb→firmware(pin map) →case(dimensions) - Handoff contract: PCB GPIO changes must update
components/sensor/sensor.c,main/Kconfig.projbuilddefaults, andCLAUDE.mdbefore any case work begins.
.github/workflows/build.yml runs six jobs:
- ESP-IDF build (esp32c6, v6.0.1) — builds firmware and OTA image (no artifact uploads — no third-party actions policy)
- C static analysis (cppcheck) — fails on any warning across
main/andcomponents/ - Version bump check (PR-only) — fails if firmware sources changed without bumping
PROJECT_VER - Host unit tests (plain ubuntu-latest, ctest) — no ESP-IDF or hardware required
- On-device test build (compile-only for
test/sensorandtest/welld_core) - Zigbee2MQTT converter tests (Node 20,
npm test)