Files
klubhaus-doorbell/AGENTS.md

5.3 KiB

AGENTS.md — Klubhaus Doorbell

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

Build Commands

# Set target board
mise set BOARD=esp32-32e-4    # ESP32-32E 4" (320x480 ST7796)
mise set BOARD=esp32-32e      # ESP32-32E 3.5" (320x240 ILI9341)
mise set BOARD=esp32-s3-lcd-43 # ESP32-S3-Touch-LCD-4.3 (800x480 RGB)

# Core commands
mise run compile              # compile for current BOARD
mise run upload               # upload (auto-kills monitor first)
mise run monitor              # start JSON monitor daemon
mise run kill                 # kill monitor/release serial port

# Formatting & cleanup
mise run format               # format code with clang-format
mise run clean                # remove build artifacts

# Debugging
mise run log-tail             # tail colored logs
mise run cmd COMMAND=dashboard # send command to device
mise run state                # show device state
mise run monitor-raw           # raw serial monitor (115200 baud)
mise run monitor-tio           # show tio command for terminal UI

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

# LSP / IDE
mise run gen-compile-commands  # generate compile_commands.json
mise run 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 mise run 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
├── secrets.h          # WiFi credentials
├── tft_user_setup.h   # TFT_eSPI config (TFT boards)
└── DisplayDriver*.{h,cpp}  # Concrete IDisplayDriver

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 mise run 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)