Files
klubhaus-doorbell/AGENTS.md

5.2 KiB

AGENTS.md — Klubhaus Doorbell

Multi-target Arduino/ESP32 doorbell alert system using ntfy.sh.

Project Overview

Three board targets share business logic via a common library:

Board Display Library Build Target
ESP32-32E SPI TFT 320x240 (ILI9341) TFT_eSPI compile-32e
ESP32-32E-4" SPI TFT 320x480 (ST7796) TFT_eSPI compile-32e-4
ESP32-S3-Touch-LCD-4.3 800x480 RGB parallel LovyanGFX compile-s3-43

Essential Commands

All commands run via mise:

# Install all dependencies (shared libs + vendored display libs)
mise run install-libs

# Build ESP32-32E
mise run compile-32e
mise run upload-32e
mise run monitor-32e

# Build ESP32-S3-LCD-4.3
mise run compile-s3-43
mise run upload-s3-43
mise run monitor-s3-43

# Format code
mise run format

# Clean build artifacts
mise run clean

Upload port override: PORT=/dev/ttyXXX mise run upload-32e

Prerequisites: arduino-cli with esp32:esp32 platform installed, mise.

Project Structure

libraries/KlubhausCore/src/     Shared Arduino library
├── KlubhausCore.h             Umbrella include (board sketches use this)
├── Config.h                   Constants, timing, WiFiCred struct
├── ScreenState.h              State enums/structs
├── IDisplayDriver.h           Pure virtual display interface
├── DisplayManager.h           Thin wrapper delegating to IDisplayDriver
├── NetManager.*               WiFi, HTTP, NTP
└── DoorbellLogic.*            State machine, ntfy polling

boards/
├── esp32-32e/
│   ├── esp32-32e.ino          Main sketch
│   ├── board_config.h         Board-specific config
│   ├── secrets.h              WiFi creds (gitignored, copy from .example)
│   ├── 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)
    ├── LovyanPins.h           Pin definitions
    └── DisplayDriverGFX.*    Concrete IDisplayDriver for LovyanGFX

vendor/                        Vendored display libs (recreated by install-libs)
├── esp32-32e/TFT_eSPI/
└── esp32-s3-lcd-43/LovyanGFX/

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)

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())
  • Serial console at 115200 baud for debug commands

Testing/Debugging

Serial commands (type into serial monitor at 115200 baud):

Command Action
alert Trigger a test alert
silence Silence current alert
dashboard Show dashboard screen
off Turn off display
status Print state + memory info
reboot Restart device

Gotchas

  1. secrets.h is gitignored: Copy from .example before building:

    cp boards/esp32-32e/secrets.h.example boards/esp32-32e/secrets.h
    cp boards/esp32-s3-lcd-43/secrets.h.example boards/esp32-s3-lcd-43/secrets.h
    
  2. Display libs are vendored: Each board uses a different display library. The build system uses --libraries to link only the board's vendored lib — never link both TFT_eSPI and LovyanGFX in the same build.

  3. No unit tests: This is an embedded Arduino sketch — no test suite exists. Verify changes by building and deploying to hardware.

  4. LSP errors are expected: The LSP cannot find Arduino.h because it requires arduino-cli to resolve. Ignore clangd/IntelliSense errors about missing Arduino types; builds work correctly via arduino-cli.

  5. Build artifacts in board dirs: Build output goes to boards/[board]/build/ — cleaned by mise run clean.

  6. WiFi credentials are per-board: Each board directory has its own secrets.h because boards may be on different networks.

Hardware Research Log

Hosyond ESP32-32E 4" (320x480) - Planned

Source: https://www.lcdwiki.com/4.0inch_ESP32-32E_Display

Spec Value
Display Controller ST7796S
Resolution 320x480
Touch XPT2046 (resistive)
Library TFT_eSPI V2.5.43 (same as 32E)

GPIO Pinout:

Function GPIO
LCD CS 15
LCD DC 2
LCD MOSI 13
LCD SCLK 14
LCD RST EN
LCD BL 27
Touch CS 33
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)