diff --git a/.crushmemory b/.crushmemory index 9655860..b0b7e58 100644 --- a/.crushmemory +++ b/.crushmemory @@ -16,7 +16,6 @@ BOARD=esp32-32e-4 mise run install # Install libs (shared + board) ## Files - `mise.toml` - Tasks (compile, upload, monitor, log-tail, cmd, state, install, clean) -- `scripts/lockfile.sh` - Lockfile functions (acquire_lock, kill_locked) - `scripts/monitor-agent.py` - Serial monitor with JSON log + command FIFO - `scripts/install-shared.sh` - Shared Arduino libs (ArduinoJson, NTPClient) - `boards/{BOARD}/install.sh` - Board-specific vendor libs diff --git a/.markdownlint-cli2.jsonc b/.markdownlint-cli2.jsonc new file mode 100644 index 0000000..f283069 --- /dev/null +++ b/.markdownlint-cli2.jsonc @@ -0,0 +1,5 @@ +{ + "MD013": false, + "MD060": false, + "MD025": false +} diff --git a/.markdownlint.json b/.markdownlint.json new file mode 100644 index 0000000..f283069 --- /dev/null +++ b/.markdownlint.json @@ -0,0 +1,5 @@ +{ + "MD013": false, + "MD060": false, + "MD025": false +} diff --git a/AGENTS.md b/AGENTS.md index e29e9b7..b0dd17a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -84,6 +84,7 @@ Each board directory contains `board-config.sh` which defines: | `OPTS` | Additional compiler flags (e.g., `-DDEBUG_MODE`) | **Example** (`boards/esp32-32e-4/board-config.sh`): + ```bash FQBN="esp32:esp32:esp32:FlashSize=4M,PartitionScheme=default" PORT="/dev/ttyUSB0" @@ -97,7 +98,7 @@ OPTS="-DDEBUG_MODE -DBOARD_HAS_PSRAM" ## Project Structure -``` +```text libraries/KlubhausCore/src/ Shared Arduino library ├── KlubhausCore.h Umbrella include (board sketches use this) ├── Config.h Constants, timing, WiFiCred struct @@ -111,19 +112,19 @@ boards/ ├── esp32-32e/ │ ├── esp32-32e.ino Main sketch │ ├── board_config.h Board-specific config -│ ├── secrets.h WiFi creds (gitignored, copy from .example) +│ ├── secrets.h.example WiFi creds template (copy to secrets.h) │ ├── tft_user_setup.h TFT_eSPI config │ └── DisplayDriverTFT.* Concrete IDisplayDriver for TFT ├── esp32-32e-4/ │ ├── esp32-32e-4.ino Main sketch │ ├── board_config.h Board-specific config -│ ├── secrets.h WiFi creds (gitignored, copy from .example) +│ ├── secrets.h.example WiFi creds template (copy to secrets.h) │ ├── tft_user_setup.h TFT_eSPI config │ └── DisplayDriverTFT.* Concrete IDisplayDriver for TFT └── esp32-s3-lcd-43/ ├── esp32-s3-lcd-43.ino Main sketch ├── board_config.h Board-specific config - ├── secrets.h WiFi creds (gitignored, copy from .example) + ├── secrets.h.example WiFi creds template (copy to secrets.h) ├── LovyanPins.h Pin definitions └── DisplayDriverGFX.* Concrete IDisplayDriver for LovyanGFX @@ -136,20 +137,52 @@ vendor/ Vendored display libs (recreated by install-libs) ## Code Patterns ### Header Guards + Use `#pragma once` (not `#ifndef` guards). ### Formatting + - 4-space indentation, no tabs - WebKit-based style (see `.clang-format`) - Column limit: 100 - Opening brace stays on same line (`BreakBeforeBraces: Attach`) +### Naming Conventions + +- Classes: `PascalCase` (e.g., `DisplayManager`, `IDisplayDriver`) +- Constants/enums: `SCREAMING_SNAKE` (e.g., `POLL_INTERVAL_MS`, `ScreenState::DASHBOARD`) +- Variables/functions: `camelCase` (e.g., `currentState`, `updateDisplay`) +- Member variables: prefix with `_` (e.g., `_screenWidth`, `_isConnected`) + +### Types + +- Arduino types: `int`, `uint8_t`, `uint16_t`, `size_t` +- Use fixed-width types for protocol/serialization (`uint8_t`, not `byte`) +- Avoid `bool` for pin states - use `uint8_t` or `int` +- Use `size_t` for sizes and array indices + +### Imports Organization + +- Arduino core headers first (`Arduino.h`) +- Standard C/C++ library (``, ``, ``) +- Third-party libraries (e.g., `TFT_eSPI.h`, `ArduinoJson.h`) +- Local project headers (e.g., `"Config.h"`, `"ScreenState.h"`) + +### Error Handling + +- Serial logging pattern: `Serial.println("[ERROR] message")` +- Use `Serial.printf()` for formatted debug output +- Return error codes, not exceptions (exceptions not available in Arduino) +- Log state transitions with `[STATE] → STATE` tags + ### Class Design + - Pure virtual `IDisplayDriver` interface in shared library - Each board implements a concrete driver (e.g., `DisplayDriverTFT`, `DisplayDriverGFX`) - `DisplayManager` delegates to `IDisplayDriver` — no display-lib coupling in shared code ### Arduino Patterns + - `setup()` runs once at boot — call `begin()` on managers - `loop()` runs continuously — call `update()` on managers - Use `millis()` for timing (not `delay()`) @@ -157,6 +190,13 @@ Use `#pragma once` (not `#ifndef` guards). ## Testing/Debugging +**No unit tests exist** - This is an embedded Arduino sketch. Verify changes by building and deploying to hardware: + +```bash +BOARD=esp32-s3-lcd-43 mise run compile # compile for default board +BOARD=esp32-32e-4 mise run compile # compile for ESP32-32E-4" +``` + **Serial commands** (type into serial monitor at 115200 baud): | Command | Action | @@ -169,6 +209,7 @@ Use `#pragma once` (not `#ifndef` guards). | `reboot` | Restart device | **Touch Test Commands** (ESP32-S3-LCD-4.3 only): + | Command | Action | |---------|--------| | `TEST:touch X Y press` | Inject synthetic press at raw panel coords (X,Y) | @@ -176,6 +217,7 @@ Use `#pragma once` (not `#ifndef` guards). | `TEST:touch clear` | Clear test mode (required between touch sequences) | Note: The S3 touch panel is rotated 180° relative to the display. Use raw panel coordinates: + - Display (100,140) → Raw (700, 340) - Display (700,140) → Raw (100, 340) @@ -201,6 +243,7 @@ The monitor daemon automatically starts after upload and is killed before upload ## Gotchas 1. **secrets.h is gitignored**: Copy from `.example` before building: + ```bash cp boards/esp32-32e/secrets.h.example boards/esp32-32e/secrets.h cp boards/esp32-32e-4/secrets.h.example boards/esp32-32e-4/secrets.h @@ -217,9 +260,9 @@ The monitor daemon automatically starts after upload and is killed before upload 6. **WiFi credentials are per-board**: Each board directory has its own `secrets.h` because boards may be on different networks. -7. **Use BOARD environment variable**: All build commands require the `BOARD` environment variable (e.g., `BOARD=esp32-32e mise run compile`). The default BOARD is `esp32-32e-4` (set in mise.toml). +7. **Use BOARD environment variable**: All build commands require the `BOARD` environment variable (e.g., `BOARD=esp32-32e mise run compile`). The default BOARD is `esp32-s3-lcd-43` (set in mise.toml). -8. **Lockfile system**: The build system uses lockfiles (`/tmp/doorbell-$BOARD.lock`) to prevent concurrent upload/monitor operations. Use `mise run kill` to clean up stuck processes. +8. **Serial port contention**: The `upload`, `monitor`, and `monitor-raw` tasks automatically depend on `kill` which uses `fuser` to terminate any process using the serial port before starting. 9. **Monitor state parsing**: The monitor-agent parses serial output for state updates: - `[STATE] → DASHBOARD` → updates state file to `"screen":"DASHBOARD"` @@ -230,7 +273,7 @@ The monitor daemon automatically starts after upload and is killed before upload 10. **Serial baud rate**: All serial communication uses 115200 baud. -11. **Lockfile mechanism**: The build system uses `/tmp/doorbell-$BOARD.lock` to prevent concurrent operations. The lockfile script (`scripts/lockfile.sh`) provides `acquire_lock()` and `release_lock()` functions. Use `FORCE=1` to override locks. +11. **Serial port contention**: The `kill` task uses `fuser` to release the serial port. Both `upload` and `monitor` tasks depend on `kill` to ensure the port is free. ## Config Constants @@ -245,6 +288,14 @@ Key timing and configuration values in `Config.h`: | `INACTIVITY_TIMEOUT_MS` | 30000 | Turn off display after 30s of inactivity | | `HOLD_TO_SILENCE_MS` | 3000 | Hold duration to silence alert | | `LOOP_YIELD_MS` | 10 | Yield to prevent Task Watchdog (configurable) | +| `BOOT_GRACE_MS` | 5000 | Grace period at boot before polling starts | +| `SILENCE_DISPLAY_MS` | 10000 | How long to show silence confirmation | +| `WIFI_CONNECT_TIMEOUT_MS` | 15000 | WiFi connection timeout | +| `HTTP_TIMEOUT_MS` | 10000 | HTTP request timeout | +| `HINT_ANIMATION_MS` | 2000 | Hint animation duration | +| `HINT_MIN_BRIGHTNESS` | 30 | Minimum brightness for hints | +| `HINT_MAX_BRIGHTNESS` | 60 | Maximum brightness for hints | +| `TOUCH_DEBOUNCE_MS` | 100 | Touch debounce delay | ## Screen States @@ -288,6 +339,7 @@ Track changes that were reverted to avoid flapping: ## Documentation Lookup Rule When uncertain about CLI tool flags or argument syntax: + 1. Run the tool with `-h` or `--help` first 2. If unclear, search for official documentation matching the tool version 3. Prefer checking the tool's own help/docs over guessing @@ -312,11 +364,13 @@ The project uses clangd for C++ and arduino-language-server for Arduino. The `.c ``` **Generate compile_commands.json** for accurate IDE diagnostics: + ```bash BOARD=esp32-32e-4 mise run gen-compile-commands ``` **Generate static .crush.json** for a specific board: + ```bash BOARD=esp32-32e-4 mise run gen-crush-config ``` @@ -325,7 +379,7 @@ BOARD=esp32-32e-4 mise run gen-crush-config ### Hosyond ESP32-32E 4" (320x480) - Planned -**Source**: https://www.lcdwiki.com/4.0inch_ESP32-32E_Display +**Source**: | Spec | Value | |------|-------| @@ -348,7 +402,153 @@ BOARD=esp32-32e-4 mise run gen-crush-config | Touch IRQ | 36 | **Quirks**: + - SPI pins shared between LCD and touch - Touch IRQ on IO36 (input-only) triggers LOW on touch - Backlight on IO27 (HIGH = on) - Common anode RGB LEDs on IO16, IO17, IO22 (LOW = on) + +# RTK (Rust Token Killer) - Token-Optimized Commands + +## Golden Rule + +**Always prefix commands with `rtk`**. If RTK has a dedicated filter, it uses it. If not, it passes through unchanged. This means RTK is always safe to use. + +**Important**: Even in command chains with `&&`, use `rtk`: + +```bash +# ❌ Wrong +git add . && git commit -m "msg" && git push + +# ✅ Correct +rtk git add . && rtk git commit -m "msg" && rtk git push +``` + +## RTK Commands by Workflow + +### Build & Compile (80-90% savings) + +```bash +rtk cargo build # Cargo build output +rtk cargo check # Cargo check output +rtk cargo clippy # Clippy warnings grouped by file (80%) +rtk tsc # TypeScript errors grouped by file/code (83%) +rtk lint # ESLint/Biome violations grouped (84%) +rtk prettier --check # Files needing format only (70%) +rtk next build # Next.js build with route metrics (87%) +``` + +### Test (90-99% savings) + +```bash +rtk cargo test # Cargo test failures only (90%) +rtk vitest run # Vitest failures only (99.5%) +rtk playwright test # Playwright failures only (94%) +rtk test # Generic test wrapper - failures only +``` + +### Git (59-80% savings) + +```bash +rtk git status # Compact status +rtk git log # Compact log (works with all git flags) +rtk git diff # Compact diff (80%) +rtk git show # Compact show (80%) +rtk git add # Ultra-compact confirmations (59%) +rtk git commit # Ultra-compact confirmations (59%) +rtk git push # Ultra-compact confirmations +rtk git pull # Ultra-compact confirmations +rtk git branch # Compact branch list +rtk git fetch # Compact fetch +rtk git stash # Compact stash +rtk git worktree # Compact worktree +``` + +Note: Git passthrough works for ALL subcommands, even those not explicitly listed. + +### GitHub (26-87% savings) + +```bash +rtk gh pr view # Compact PR view (87%) +rtk gh pr checks # Compact PR checks (79%) +rtk gh run list # Compact workflow runs (82%) +rtk gh issue list # Compact issue list (80%) +rtk gh api # Compact API responses (26%) +``` + +### JavaScript/TypeScript Tooling (70-90% savings) + +```bash +rtk pnpm list # Compact dependency tree (70%) +rtk pnpm outdated # Compact outdated packages (80%) +rtk pnpm install # Compact install output (90%) +rtk npm run