Navoin added

This commit is contained in:
XPS\Micro 2026-02-13 20:24:52 +01:00
parent 520bcf7d7f
commit 38f75232e0
4 changed files with 179 additions and 5 deletions

173
AGENTS.md Normal file
View File

@ -0,0 +1,173 @@
# AGENTS.md
## Project Overview
ESP8266 PlatformIO firmware for a German word clock (Wortuhr). An 11×11 WS2812B LED matrix (121 LEDs) displays time as illuminated German words. WiFi-controllable with AP mode for configuration and Station mode for NTP time sync.
## Build Commands
```bash
# Build (default environment: esp8266clone)
pio run
# Build for specific environment
pio run -e esp8266clone
pio run -e d1_mini
# Build and upload
pio run --target upload
# Serial monitor (115200 baud)
pio device monitor
# Clean build
pio run --target clean
# Update libraries
pio lib update
```
### Pre-build Script
`html_to_header.py` runs automatically before each build. It converts `html/index.html` into gzip-compressed C header `include/html.h`. Do not edit `html.h` directly — edit `html/index.html` instead.
## Testing
There is no unit test framework. Testing is done on-device:
```bash
# Run black box test (upload to device, output on serial)
# Edit lib/CharGraphTimeLogic/blackboxtest/config.h to configure:
# - testpatterns[]: 110-char grid patterns
# - hourStart/hourEnd, minuteStart/minuteEnd, hops
# Then upload the blackboxtest.ino sketch
# Enable word test mode via build flag in platformio.ini:
# -DTEST_ALLTHETIME=true
```
### Debug Flags (platformio.ini build_flags)
- `DEBUG_SOURCE=true` — Enable serial debug output
- `USE_RTC=false` — Disable RTC (DS1307) functionality
- `TEST_RGB_ONLY=false` — Run only RGB LED test on boot
- `TEST_ALLTHETIME=false` — Run word-finding test for all times
- `POWERLOSSDETECT=false` — Enable power loss detection
- `CHARGRAPH_DEBUG` — Enable CharGraphTimeLogic debug output
## Architecture
### File Organization
- `src/main.cpp` — All application logic (~2660 lines): setup/loop, web handlers, EEPROM, NTP, OTA, WiFi, charsoap management
- `include/common.inc` — Central include hub; imports all dependencies
- `include/defines.inc` — Hardware defines, debug macros, EEPROM address map
- `include/vars.inc` — Global variable definitions (also includes `html.h` at bottom)
- `include/extern.inc``extern` declarations for cross-module globals
- `include/charPattern.inc` — Default character pattern (PROGMEM), test words, MINUTE_LEDS
- `include/WordFinder.h` — Unified word search (PROGMEM + string, forward/backward)
- `lib/rgbPanel/` — LED matrix control, word finding/highlighting, fade effects
- `lib/CharGraphTimeLogic/` — Time-to-words conversion engine with validation
- `lib/PowerOnDetector/` — Boot reason analysis, power loss detection
- `lib/info/` — Serial connection status display
### Include System
`main.cpp` includes `common.inc`, which chains: `extern.inc``defines.inc``version.inc``vars.inc` → library headers. `vars.inc` includes `html.h` at bottom. `charPattern.inc` is included only by `rgbPanel.cpp`.
### EEPROM Layout
512 bytes total. All addresses are `#define`d in `defines.inc` with `ADDR_` prefix. Magic bytes (e.g., `0xAA`, `0xBB`) are used as "configured" flags. Always call `EEPROM.commit()` after writes.
## Code Style Guidelines
### Indentation and Formatting
- **Indentation**: Mixed — mostly 4 spaces; some files use 2-space indent inside `#ifndef` guards. Use 4 spaces for new code.
- **Brace style**: Allman style (opening brace on its own line) for function definitions; K&R style (opening brace on same line) for `if`/`for`/`while`/`switch`. Both appear in the codebase — follow the style of the surrounding code.
- **Line length**: No strict limit; keep reasonable (~120 chars).
- **Section headers**: Use decorated comment blocks:
```cpp
// ════════════════════════════════════════════════════════════════
// SECTION NAME
// ════════════════════════════════════════════════════════════════
```
### Naming Conventions
- **Functions**: `camelCase``loadCharsoap()`, `setRunningFlag()`, `findWord()`, `displayTime()`
- **Global variables**: `camelCase``bootCounter`, `ntpEnabled`, `lastSyncTime`, `autoBrightnessMin`
- **Constants**: `UPPER_SNAKE_CASE``NUM_LEDS`, `MAX_BRIGHTNESS`, `ADDR_CHARSOAP`
- **Macros/defines**: `UPPER_SNAKE_CASE``DEBUG_PRINTLN`, `RUNNING_FLAG_MAGIC`
- **Structs**: `PascalCase``ValidationResult`, `RuleContext`, `CharGraphTimeWords`, `TestStats`
- **Struct members**: `camelCase``wordCount`, `ledHex`, `fallbackLevel`
- **Header guards**: `_NAME_H_` for legacy files, `NAME_H` for newer CharGraphTimeLogic files
### Types
- Prefer Arduino/fixed-width types: `uint8_t`, `uint16_t`, `uint32_t`, `int8_t`, `int16_t`
- Use `bool` for flags
- Use `CRGB` for LED colors (FastLED)
- Use `char[]` / `char*` for strings — `String` class is used sparingly (only `otaError`)
- Use `const char*` with `PROGMEM` for flash-stored constant strings
- Use `unsigned char` when doing byte-level operations (UTF-8 handling)
### Comments
- Comments are a mix of German and English. German is predominant in older code (`main.cpp`, `rgbPanel`, `PowerOnDetector`). English is used in newer `CharGraphTimeLogic` library.
- Use `//` for inline comments; `/** ... */` Javadoc-style for function documentation in CharGraphTimeLogic
- Commented-out code is common (debug prints, alternative patterns) — leave existing commented code in place
### Error Handling
- Functions return `-1` or `false` on failure, valid values on success
- `getCharGraphWords()` returns `int8_t`: positive = success, 0 or negative = error
- Pattern validation returns `ValidationResult` struct with `bool valid` and `const char* reason`
- Debug output via macros: `DEBUG_PRINT(x)`, `DEBUG_PRINTLN(x)`, `DEBUG_PRINTF(...)` — these compile to no-ops when `DEBUG_SOURCE` is false
- Use `yield()` in long loops to prevent watchdog resets
- Always check `EEPROM.commit()` after EEPROM writes
### PROGMEM Usage
- Store constant strings and large data in flash with `PROGMEM`
- Read PROGMEM strings with `pgm_read_byte()`, `strcpy_P()`, `pgm_read_ptr()`
- Pattern strings are 110 characters (11 cols × 10 rows, row 11 is minute LEDs)
### Include Patterns
Library headers include their own dependencies:
```cpp
#include <Arduino.h> // Always first
#include <FastLED.h> // Hardware libraries
#include <EEPROM.h>
#include <defines.inc> // Project includes use angle brackets
#include <extern.inc>
#include "Types.h" // Intra-library includes use quotes
```
### Web Server Handlers
Handlers in `main.cpp` follow this pattern:
```cpp
server.on("/endpoint", []() {
// Parse server.arg("paramName")
// Process request
// EEPROM.write(...) + EEPROM.commit() for persistence
server.send(200, "application/json", "{\"status\":\"ok\"}");
});
```
### Hardware Constraints
- ESP8266 has ~40KB usable RAM — avoid dynamic allocation, prefer stack buffers
- LED updates require interrupt protection: call `noInterrupts()` before `FastLED.show()`, `interrupts()` after
- LED index 2 is always off (photoresistor position)
- Zigzag LED mapping: even rows left-to-right, odd rows right-to-left
- Call `yield()` or `delay()` in loops to feed the watchdog and allow WiFi processing
### Key Domain Knowledge
- "charsoap" = the 110-character letter grid that defines which words can be displayed
- Umlauts Ä→a, Ö→o, Ü→u in charsoap (stored as lowercase: `FuNF` = FÜNF, `ZWoLF` = ZWÖLF)
- Words list format: dash-separated string `"ES-IST-HALB-UHR-..."`
- Time display advances hour at minute >= 20 (German convention: "zehn vor drei" at 2:50)

View File

@ -3,7 +3,8 @@
//Hier Umlaute wie Ö und Ü bereits durch o und u wegen UTF8 ersetzen!!!! //Hier Umlaute wie Ö und Ü bereits durch o und u wegen UTF8 ersetzen!!!!
const char DEFAULT_CHARSOAP[] PROGMEM = "ESPISTGZEHNFuNFVIERTELVORNACHBALDHALBGZWEINSWCDLZIAXMTVZEHNEUNACHTELFuNFZWoLFSECHSIEBENBGDREIVIERZECRPFACWLUHR";//DLZIAX const char DEFAULT_CHARSOAP[] PROGMEM = "ESMISTMZEHNFuNFVIERTELVORNACHBALDHALBQZWEINSBDREINVIERONAJAMHNAVINELFuNFZWoLFZEHNEUNACHTWSECHSIEBENDPAUSEBDUHR"; //NAVIN
//"ESPISTGZEHNFuNFVIERTELVORNACHBALDHALBGZWEINSWCDLZIAXMTVZEHNEUNACHTELFuNFZWoLFSECHSIEBENBGDREIVIERZECRPFACWLUHR";//DLZIAX
//"ESYISTHZEHNFuNFVIERTELVORNACHBALDHALBUZWEINSDG6MSMARTINZEHNEUNACHTELFuNFZWoLFSECHSIEBENBXDREIVIERLUWRNFACWFUHR";//DG6MS //"ESYISTHZEHNFuNFVIERTELVORNACHBALDHALBUZWEINSDG6MSMARTINZEHNEUNACHTELFuNFZWoLFSECHSIEBENBXDREIVIERLUWRNFACWFUHR";//DG6MS
//"ESYISTMZEHNFuNFVIERTELVORNACHBALDHALBDZWEINSNZUXHAUSEMZZEHNEUNACHTELFuNFZWoLFSECHSIEBENHXDREIVIERKNOTPAUSECUHR";//Böcker //"ESYISTMZEHNFuNFVIERTELVORNACHBALDHALBDZWEINSNZUXHAUSEMZZEHNEUNACHTELFuNFZWoLFSECHSIEBENHXDREIVIERKNOTPAUSECUHR";//Böcker
//"ESQISTFZEHNFuNFVIERTELVORNACHBALDHALBFYZWEITJEGARTNERVDELFuNFZWoLFZEHNEUNACHTXDREINSVIERSECHSIEBENCRWDSIMONUHR";//GARTNERSIMON //"ESQISTFZEHNFuNFVIERTELVORNACHBALDHALBFYZWEITJEGARTNERVDELFuNFZWoLFZEHNEUNACHTXDREINSVIERSECHSIEBENCRWDSIMONUHR";//GARTNERSIMON

View File

@ -17,8 +17,8 @@ int8_t isConfigured = 0xFF;
const unsigned long AP_TIMEOUT = 300000; const unsigned long AP_TIMEOUT = 300000;
bool powerLossDetected = false; //Flag für Stromausfall bool powerLossDetected = false; //Flag für Stromausfall
char AP_SSID[AP_SSID_LENGHT] = "CharGraph\0"; char AP_SSID[AP_SSID_LENGHT] = "Wortuhr2026\0";
char AP_PASSWORD[AP_PASSWORD_LENGTH] = "CharGraph\0"; char AP_PASSWORD[AP_PASSWORD_LENGTH] = "Wortuhr2026\0";
uint16_t bootCounter = 0; uint16_t bootCounter = 0;

View File

@ -16,8 +16,8 @@ bool customCharsoap = false;
// ── Konfiguration für Spezialanzeige ── // ── Konfiguration für Spezialanzeige ──
// MAXWORDS ist in defines.inc definiert // MAXWORDS ist in defines.inc definiert
// Platzhalter - werden dynamisch aus EEPROM oder Defaults geladen (siehe loadSpecialWords() in main.cpp) // Platzhalter - werden dynamisch aus EEPROM oder Defaults geladen (siehe loadSpecialWords() in main.cpp)
char SPECIAL_WORD[MAXWORDS][13] = {"DLZIAX\0", //max 11 Zeichen, \0 wird automatisch angefügt! char SPECIAL_WORD[MAXWORDS][13] = {"NAJAMHNAVIN\0", //max 11 Zeichen, \0 wird automatisch angefügt!
"FACW\0", "\0",
"\0" }; //Text der ein- bzw. ausgeblendet werden soll "\0" }; //Text der ein- bzw. ausgeblendet werden soll
const uint16_t SPECIAL_HOLD_MS = 5000; // Anzeigedauer des Spezialworts const uint16_t SPECIAL_HOLD_MS = 5000; // Anzeigedauer des Spezialworts