Files
klubhaus-doorbell/AGENTS.md
T
david 6f9d2912d3 feat: add BUILD_TOKEN to firmware and consolidate build system
- Generate BUILD_TOKEN from 'git describe --always --dirty'
- Include via -include flag in justfile compile recipe
- Print BUILD_TOKEN in boot banners (DoorbellLogic + uno-r4-wifi)
- Remove all [tasks] from mise.toml; keep only [tools] + [env]
- Update AGENTS.md to use just commands as single source of truth
- Add 'just full' recipe (compile -> upload -> monitor -> watch)
- Switch BOARD var to env_var_or_default for mise set compatibility
- DRY clean/clean-temp with wildcard patterns
2026-05-29 20:17:42 -07:00

5.8 KiB

AGENTS.md — Klubhaus Doorbell

Multi-target Arduino/ESP32 doorbell alert system using ntfy.sh. Default BOARD: esp32-s3-lcd-43.

Build Commands

# All tasks use just (see justfile). Default BOARD: esp32-s3-lcd-43

# Set target board
just BOARD=esp32-32e-4 compile   # ESP32-32E 4" (320x480 ST7796)
just BOARD=esp32-32e compile     # ESP32-32E 3.5" (320x240 ILI9341)
just BOARD=esp32-s3-lcd-43 compile # ESP32-S3-Touch-LCD-4.3 (800x480 RGB)
just BOARD=uno-r4-wifi compile   # Arduino Uno R4 WiFi (12x8 LED matrix)

# Core commands
just compile              # compile for current BOARD
just upload               # upload (auto-kills monitor first)
just monitor              # start JSON monitor daemon (background)
just kill                 # kill monitor/release serial port
just full                 # compile + upload + monitor + log-tail (full feedback loop)
just watch                # tail colored logs

# Formatting & cleanup
just format               # format code with clang-format
just clean                # remove build artifacts
just clean-temp           # remove monitor logs/FIFOs/state files

# Debugging
just cmd dashboard        # send command to device
just state                # show device state
just monitor-raw           # raw serial monitor (115200 baud)
just monitor-tio           # show tio command for terminal UI

# Install dependencies
just install-libs-shared  # shared libs (ArduinoJson, NTPClient)
just install              # shared + board-specific libs

# LSP / IDE
just gen-compile-commands # generate compile_commands.json
just gen-crush-config     # generate .crush.json for BOARD

Serial debug commands (115200 baud): alert, silence, dashboard, off, status, reboot

No unit tests exist — verify changes by compiling and deploying to hardware.

Code Style

Formatting (.clang-format)

  • BasedOnStyle: WebKit
  • 4-space indentation, no tabs
  • Column limit: 100
  • Opening brace on same line (BreakBeforeBraces: Attach)
  • Run just format to format code

Header Guards

Use #pragma once (not #ifndef guards).

Naming Conventions

Type Convention Example
Classes PascalCase DisplayManager, IDisplayDriver
Constants/enums SCREAMING_SNAKE POLL_INTERVAL_MS, ScreenState::DASHBOARD
Variables/functions camelCase currentState, updateDisplay
Member variables _ prefix _screenWidth, _isConnected

Types

  • Use fixed-width types for protocol/serialization (uint8_t, not byte)
  • Use size_t for sizes and array indices
  • Avoid bool for pin states — use uint8_t or int

Imports Organization (in order)

  1. Arduino core (Arduino.h)
  2. Standard C/C++ (<cstdint>, <String>, <vector>)
  3. Third-party libs (TFT_eSPI.h, ArduinoJson.h)
  4. Local project ("Config.h", "ScreenState.h")

Error Handling

  • Serial logging: Serial.println("[ERROR] message")
  • Use Serial.printf() for formatted debug
  • Return error codes, not exceptions
  • Log state: [STATE] → DASHBOARD

Architecture Patterns

Display Driver Interface

  • Pure virtual IDisplayDriver in shared KlubhausCore
  • Each board implements concrete driver (DisplayDriverTFT, DisplayDriverGFX)
  • DisplayManager delegates to IDisplayDriver — no display-lib coupling in shared code

Arduino Patterns

  • setup() — call begin() on managers
  • loop() — call update() on managers
  • Use millis() for timing (not delay())
  • Serial baud: 115200

Style System

  • Style constants in board's board_config.h: STYLE_SPACING_X, STYLE_COLOR_BG, etc.
  • Font abstraction via IDisplayDriver: setTitleFont(), setBodyFont(), etc.
  • Layout helpers in KlubhausCore/src/Style.h

Key Files

libraries/KlubhausCore/src/
├── KlubhausCore.h      # Umbrella include
├── Config.h            # Timing, WiFiCred struct
├── ScreenState.h       # State enums/structs
├── IDisplayDriver.h   # Pure virtual interface
├── DisplayManager.h    # Delegates to IDisplayDriver
├── NetManager.*        # WiFi, HTTP, NTP
└── DoorbellLogic.*     # State machine, ntfy polling

boards/{BOARD}/
├── {BOARD}.ino         # Main sketch
├── board_config.h      # Board-specific config (ESP32 boards)
├── secrets.h          # WiFi credentials (optional, use env vars)
├── tft_user_setup.h   # TFT_eSPI config (TFT boards)
└── DisplayDriver*.{h,cpp}  # Concrete IDisplayDriver (ESP32 boards)

boards/uno-r4-wifi/           # Uno R4 WiFi (LED matrix display)
├── uno-r4-wifi.ino           # Main sketch (standalone)
├── test_messages.sh          # Test script to send ntfy messages
└── README.md                 # Quick start guide

Gotchas

  1. secrets.h: Boards with -DLOCAL_SECRETS use local secrets.h; others use KlubhausCore/src/secrets.h
  2. Vendored libs: Each board links only its display lib — never TFT_eSPI + LovyanGFX together
  3. LSP errors: Run just gen-compile-commands then restart LSP; build works regardless
  4. Serial port: upload/monitor auto-depend on kill to release port
  5. State tags: Use [STATE] → DASHBOARD, [ADMIN], [TOUCH], [ALERT] for monitor parsing

Config Constants (Config.h)

Constant Default Description
FW_VERSION "5.1" Firmware version
POLL_INTERVAL_MS 15000 ntfy.sh poll interval
ALERT_TIMEOUT_MS 120000 Auto-clear alert
INACTIVITY_TIMEOUT_MS 30000 Display off timeout
HOLD_TO_SILENCE_MS 3000 Hold to silence
WIFI_CONNECT_TIMEOUT_MS 15000 WiFi timeout
HTTP_TIMEOUT_MS 10000 HTTP request timeout

Screen States

  • BOOT — Initializing
  • DASHBOARD — Normal operation
  • ALERT — Doorbell ring detected
  • OFF — Display backlight off (polling continues)