# Story 4.2: Config Wipe, Setup Screen & Return to Provisioning Status: done ## Story As a user who has triggered a reset, I want the device to wipe its configuration, show a setup screen on the e-ink display, and restart into the provisioning flow, So that I can re-configure the device from scratch. ## Acceptance Criteria AC1: **Given** `ButtonHoldDetector.check()` returns `True` **When** the reset handler runs **Then** `config.wipe()` is called AC2: **Given** config has been wiped **When** the reset handler continues **Then** `display.show(setup_screen_image)` is called AC3: **Given** setup screen is shown **When** reset handler completes **Then** `os.execvp('planemapper-provision', ['planemapper-provision'])` replaces the current process AC4: **Given** `config.wipe()` raises an unexpected error **When** the reset handler encounters it **Then** ERROR is logged and `os.execvp` is NOT called ## Tasks / Subtasks - [ ] Task 1: Implement `_handle_reset()` and `_make_setup_screen()` in `src/planemapper/main.py` (AC: #1–#4) - [ ] 1.1 Add `import os` to imports - [ ] 1.2 Add `from planemapper.provisioning.config import wipe as wipe_config` - [ ] 1.3 Add `from planemapper.gpio_ctrl import ButtonHoldDetector, LEDController` - [ ] 1.4 Implement `_make_setup_screen() -> Image.Image` - [ ] 1.5 Implement `_handle_reset(display, led) -> None` - [ ] 1.6 Update `main()` to instantiate `ButtonHoldDetector` and `LEDController` - [ ] 1.7 Add reset check at top of loop - [ ] Task 2: Write tests in `tests/test_reset.py` (AC: #1–#4) - [ ] Task 3: Run quality gates - [ ] 3.1 `python -m pytest tests/` — all tests pass - [ ] 3.2 `python -m ruff check .` — zero violations - [ ] 3.3 `python -m ruff format --check .` — no formatting issues ## Implementation Notes ### `_handle_reset` flow 1. `led.on()` — immediate LED feedback before any wipe attempt 2. `wipe_config()` — deletes config file; on failure, log ERROR, call `led.off()`, return 3. `display.show(_make_setup_screen())` — render "Resetting..." screen 4. `os.execvp("planemapper-provision", ["planemapper-provision"])` — replaces process (never returns) ### `_make_setup_screen()` Returns a white 800×480 PIL Image with "Resetting..." text. Same pattern as `_make_startup_screen()`. ### main() loop update `ButtonHoldDetector` and `LEDController` are instantiated once in `main()` before the loop. Inside the loop, `button.check()` is called once per cycle (non-blocking). If `True`, `_handle_reset` is called (which never returns on success). ### TID251 per-file-ignore `main.py` already has `TID251` in per-file-ignores in `pyproject.toml`, so importing from `planemapper.provisioning.config` is allowed. ### Patching in tests - `wipe_config` is patched at `planemapper.main.wipe_config` - `os.execvp` is patched at `planemapper.main.os.execvp` ### Files changed | File | Change | |---|---| | `src/planemapper/main.py` | Add `import os`, new imports, `_make_setup_screen()`, `_handle_reset()`, update `main()` | | `tests/test_reset.py` | New file with 3 tests |