Skip to content

PR-02: pump actuator layer and board abstraction#7

Merged
cryptotomte merged 6 commits into
mainfrom
002-pump-gpio-board
Jun 12, 2026
Merged

PR-02: pump actuator layer and board abstraction#7
cryptotomte merged 6 commits into
mainfrom
002-pump-gpio-board

Conversation

@cryptotomte

Copy link
Copy Markdown
Owner

Summary

Phase 1 driver work per docs/prd/PR-02-pump-gpio-board.md (spec-kit artifacts in specs/002-pump-gpio-board/):

  • Pump actuator layer on native ESP-IDF: all timing/safety logic in a pure C++ WaterPump base (timed runs only, hard 300 s max-runtime enforced in update(), paired output transitions, runtime statistics, observable stop reasons) behind a single virtual applyOutput; GpioWaterPump (active-HIGH MOSFET, glitch-free off-first init, explicit error handling). No indefinite runs — duration 0 / >300 s rejected (deliberate change vs Arduino's uncapped manual runs, parity checklist §4).
  • Concurrency-safe by design: LockedWaterPump decorator serializes access between the esp_console REPL task and the main update loop (caught in review as a real data race, fixed + re-reviewed CLEAN).
  • Rig diagnostics: ws> REPL with pump <plant|reservoir> start <s>|stop|status.
  • Board abstraction completed: LED/button pins on both boards (rev2 provisional, TODO(SYNC1)), compile-time sanity checks (pin distinctness, DE flag/macro consistency) that fail the build instead of producing a wrong binary.
  • Host test suite (new CI gate): 10 Unity tests of the real pump logic on the IDF linux target — exit code fails the PR.
  • Boot fail-safe (pumps off first) unchanged; fixes Arduino QUIRK 2 target (reservoir pump GPIO now actively driven LOW at boot).

Verification

  • Both board variants build green in the pinned container (local, espressif/idf:v6.0.1) with CONFIG_BOARD_* asserted
  • Host tests 10/10, exit 0 (local container)
  • CI: build (rev1_devkit), build (rev2), host-test — on this PR
  • HIL checklist on the rev1 rig (specs/002-pump-gpio-board/checklists/hil.md) — Paul, before or after merge

🤖 Generated with Claude Code

cryptotomte and others added 6 commits June 10, 2026 13:17
…onsole diagnostics

- interfaces component (header-only, zero IDF deps): IActuator, IWaterPump
  (runFor/stop/update contract with StopReason), ITimeProvider
- actuators component: WaterPump base holds ALL timing/safety logic (timed
  runs only, hard 300 s max-runtime enforced in update(), paired output
  transitions, runtime statistics) behind a single virtual applyOutput;
  GpioWaterPump (active-HIGH MOSFET, glitch-free off-first init, explicit
  error handling); EspTimeProvider; header-only test doubles
- LockedWaterPump decorator serializes pump access between the console REPL
  task and the main update loop (review finding C1: unsynchronized state
  would allow a fresh start to be torn down by a concurrent poll)
- app_main wires both pumps behind IWaterPump after the unchanged boot
  fail-safe; esp_console REPL (ws>) with pump start/stop/status for rig HIL
- No indefinite runs: duration 0 and >300 s rejected (deliberate change vs
  Arduino uncapped manual runs, per parity checklist §4)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…nity checks

- status LED 2, manual button 5, config button 18 on both boards (rev2
  provisional, TODO(SYNC1))
- preprocessor sanity block: pin distinctness and RS485 DE flag/macro
  iff-consistency fail the build instead of producing a wrong binary
- firmware docs: pump layer, concurrency rule (LockedWaterPump), console
  diagnostics, host-test commands

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- separate IDF project firmware/test_apps/host (linux preview target,
  bundled Unity, exit code = failure count)
- 10 tests against the REAL WaterPump logic via MockWaterPump +
  FakeTimeProvider: duration self-stop, forced 300 s stop with reason,
  rejections without state change, paired transitions, accumulated runtime,
  single-poll enforcement, LockedWaterPump delegation
- CI: new host-test job (pinned action/IDF version); test failure fails the PR

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Spec, plan, research (6 decisions incl. verified linux-target host-test
mechanism), data model, interface + serial-diagnostic contracts, quickstart,
22-task breakdown, HIL checklist for rig sign-off. .gitignore: checkpoint
dialog docs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The esp-idf-ci-action defaults IDF_TARGET to esp32, which makes
`idf.py --preview set-target linux` abort with "not consistent with
target in the environment" (worked locally because the raw container
has no IDF_TARGET set).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…HIL checklist

Without ota_data_initial.bin at 0xd000 the artifact set was not the
complete flash image idf.py produces. The HIL checklist gains a
step-by-step esptool flashing guide (macOS, no ESP-IDF install needed)
including the boot-banner verification step.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@cryptotomte

Copy link
Copy Markdown
Owner Author

HIL checklist executed on the rev1 bench rig (2026-06-12): all items pass.

  • Flashed from the CI artifact wateringsystem-rev1_devkit per the checklist procedure
  • Pump GPIO behavior, serial diagnostic commands, and fail-safe boot state verified on hardware
  • Full checklist: specs/002-pump-gpio-board/checklists/hil.md

Runner: Paul (project owner). This was the last open gate from Checkpoint 3 — merging.

@cryptotomte cryptotomte merged commit a8bb453 into main Jun 12, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant