This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
LISYclock is an ESP32-S3 firmware for a pinball/arcade-themed clock. It drives 4× TM1637 6-digit LED displays, a programmable LED strip, audio playback (MP3 + TTS via Wit.ai), and syncs time via NTP and a DS3231 RTC. Configuration and audio files are stored on SD card.
Framework: ESP-IDF 5.5.1 with CMake + Ninja. All builds are done through ESP-IDF toolchain.
# Configure (first time or after sdkconfig changes)
idf.py set-target esp32s3
# Build
idf.py build
# Flash
idf.py -p <PORT> flash
# Monitor serial output
idf.py -p <PORT> monitor
# Flash + monitor combined
idf.py -p <PORT> flash monitorThere are no unit tests in this project.
The hardware version is selected at compile time by commenting/uncommenting #define LISYCLOCK2 in main/gpiodefs.h:
- HW v1.xx (default,
LISYCLOCK2not defined) — version stringv1.43 - HW v2.xx (
#define LISYCLOCK2 TRUE) — version stringv2.43
All GPIO assignments for both versions are in main/gpiodefs.h.
app_main() initializes all subsystems in order: NVS, SD card, config, GPIO, I2C/RTC, displays, LEDs, buttons, WiFi, SNTP, audio, FTP server, then enters the main loop which updates the display and fires scheduled events.
| File | Responsibility |
|---|---|
main/lisyclock.cpp |
Entry point, display rendering, main loop |
main/event.cpp / event.h |
Time-based event scheduling (MP3, TTS, LED patterns) |
main/audio.cpp / audio.h |
MP3 playback from SD + TTS via Wit.ai REST API |
main/leds.c / leds.h |
RMT-driven LED strip (up to 31 LEDs), GI and attract modes |
main/config.c / config.h |
Parses config.txt from SD card |
main/ds3231.c / ds3231.h |
I2C driver for DS3231 RTC |
main/buttons.c |
ADJUST/SET buttons + DIP switch reading |
main/ftp.c |
FTP server for SD card access over WiFi |
main/sdcard.c |
SPI SD card mount |
main/sntp.c |
NTP time sync |
main/fupdate.c |
OTA firmware update from SD card |
main/typedefs.h |
Shared structs (LED config, event types) |
main/gpiodefs.h |
All GPIO pin assignments (both HW versions) |
components/arduino/— arduino-esp32 framework + added libraries:libraries/TM1637TinyDisplay/— display driverlibraries/BackgroundAudio/— audio mixinglibraries/ESP32-audioI2S/— I2S audiolibraries/WitAITTS/— Wit.ai Text-to-Speech
managed_components/— ESP-IDF managed dependencies (wifi-manager, led_strip, button, mp3 decoder, etc.)
Two OTA partitions (partitions_two_ota.csv). OTA firmware updates are loaded from SD card via fupdate.c.
Runtime config is read from config.txt on the SD card at boot. Timezone and other compile-time settings are in sdkconfig.
Der Config Editor befindet sich in config_editor/LISYclock_config_editor.html. Es ist eine eigenständige Browser-App ohne Build-Schritt — direkt in Chrome oder Edge öffnen.
Alle Logik liegt im <script>-Block der HTML-Datei, in klar benannten Abschnitten:
| Section | Purpose |
|---|---|
| STATE | state-Objekt + resetState() |
| CONFIG PARSER | parseConfig(text) — liest config.txt in state |
| CONFIG GENERATOR | generateConfig() — serialisiert state zurück in config.txt |
| FILE I/O | Open/Save/SaveAs/New via File System Access API mit Fallback |
| RENDER: TTS | TTS-Tab befüllen, Input-Listener verdrahten |
| RENDER: GENERAL | General-Tab (FTP, Timezone, Weekday-Felder) |
| LED ROW HELPER | createLedRow(ledObj, onRemove) — geteilt von GI LEDs und Attract-Tabs |
| RENDER: GI LEDs | Rendert state.gi_leds-Array |
| RENDER: ATTRACT MODE | Bootstrap-Accordion für AT1–AT5-Gruppen |
| RENDER: EVENTS | Rendert state.events-Array |
config.txt text → parseConfig() → state → renderAll() → DOM
user edits DOM → event listeners mutate state in-place
Save button → generateConfig() → state → config.txt text
Render-Funktionen sind destruktiv (innerHTML = '' und Neuaufbau aus state). DOM-Listener mutieren die state-Property direkt — kein Two-Way-Binding-Framework.
state = {
tts: { wit_token, voice, style, speed, pitch, gain, sfx_char, sfx_env },
events: [{ type, time, value }], // type = 'TTS'|'MP3'|'BATCH'|'DISPLAY'|'TIME'|'GI_LEDS'|'ATTRACT_LEDS'
general: {
disp_bright,
ftp_enabled, ftp_user, ftp_pwd,
timezone_enabled, timezone,
days_enabled, days: { sun, mon, tue, wed, thu, fri, sat }
},
gi_leds: [{ led, r, g, b, intensity }],
attract: [5x { blink_rate, rand_enabled, rand, leds: [{ led, r, g, b, intensity }] }],
_fileHandle: null // FileSystemFileHandle für Save (non-null nach Open/SaveAs)
}API.md ist die einzige, autoritative Kopie des HTTP-API-Vertrags zwischen Firmware und Config Editor. Beide Komponenten liegen in diesem Repository — keine Synchronisierung nötig.
Regeln:
- Wenn du einen Endpunkt in
main/httpserver.cänderst oder hinzufügst, mussAPI.mdaktualisiert werden. - Bei Breaking Changes (geänderte Response-Felder, entfernte Endpunkte):
HTTP_API_VERSIONinmain/httpserver.herhöhen undapi_versioninAPI.mderhöhen. - Nicht-breaking Additions (neue optionale Felder, neue Endpunkte) erfordern keine Versionserhöhung.
- Nach API-Änderungen muss der Config Editor (
config_editor/LISYclock_config_editor.html) angepasst werden.