{
  "id": "fennek",
  "name": "Fennek",
  "type": "fork",
  "maintainer": "danst0",
  "description": "An alternative open-source firmware for the LilyGO T-Deck Pro — music, audiobooks, eBooks and LoRa mesh chat via MeshCore. Features a homescreen launcher, touch and physical keyboard support, EPUB reader, audiobook player, and PCM5102A DAC audio output.\n",
  "repository": "https://github.com/danst0/fennek",
  "license": "GPL-3.0",
  "status": "active",
  "scope": "device-specific",
  "lifecycle": "active",
  "maturity": "beta",
  "distribution": "community",
  "lineage": {
    "kind": "fork",
    "upstreamFirmwareId": "meshcore",
    "upstreamRepository": "https://github.com/meshcore-dev/MeshCore"
  },
  "runtime": {
    "framework": "arduino",
    "language": "cpp"
  },
  "roles": [
    "companion",
    "standalone-ui"
  ],
  "features": [
    "Homescreen launcher",
    "Music playback (PCM5102A DAC)",
    "Audiobook player",
    "EPUB and TXT reader with page-index cache",
    "LoRa mesh chat via MeshCore",
    "Touch + physical keyboard support",
    "Per-book reading position"
  ],
  "capabilities": {
    "protocol": {
      "meshcoreCompatible": true
    },
    "transports": {
      "ble": true,
      "usbSerial": true,
      "nativeTcp": true,
      "wifiAp": true
    },
    "operations": {
      "ota": false,
      "webFlasher": false
    },
    "networking": {
      "repeater": false,
      "roomServer": false,
      "observer": false,
      "kissModem": false
    },
    "hardware": {
      "gps": true,
      "display": true,
      "sensors": false,
      "lowPowerRx": false
    }
  },
  "devices": [
    {
      "id": "lilygo-tdeck-pro",
      "status": "supported"
    }
  ],
  "popularity": {
    "githubStars": 6,
    "githubForks": 0,
    "githubWatchers": 0,
    "githubOpenIssues": 0,
    "githubContributors": 101,
    "releaseDownloads": 25,
    "latestReleaseDownloads": 4,
    "lastChecked": "2026-08-05"
  },
  "verification": {
    "sourceAvailable": true,
    "releasesAvailable": true,
    "ciBuilds": false,
    "lastChecked": "2026-08-05"
  },
  "source": {
    "path": "data/firmwares/fennek/firmware.yaml",
    "updatedAt": "2026-08-05T08:12:38Z"
  },
  "latest_version": "2.7.4",
  "released": "2026-07-22",
  "releases": [
    {
      "version": "v2.7.4",
      "name": "v2.7.4",
      "datetime": "2026-07-22T17:34:34Z",
      "url": "https://github.com/danst0/fennek/releases/tag/v2.7.4",
      "prerelease": false,
      "notes": "IJKL geräteweit als Alias zu WASD: alle Apps akzeptieren zusätzlich I/J/K/L (hoch/links/runter/rechts). Mesh- und Schach-Kollisionen sauber gelöst; mathquiz-Keypad und Sudoku-Zifferneingabe unangetastet.",
      "notesHtml": "<p>IJKL geräteweit als Alias zu WASD: alle Apps akzeptieren zusätzlich I/J/K/L (hoch/links/runter/rechts). Mesh- und Schach-Kollisionen sauber gelöst; mathquiz-Keypad und Sudoku-Zifferneingabe unangetastet.</p>\n"
    },
    {
      "version": "v2.7.3",
      "name": "v2.7.3",
      "datetime": "2026-07-22T15:50:34Z",
      "url": "https://github.com/danst0/fennek/releases/tag/v2.7.3",
      "prerelease": false,
      "notes": "Sudoku: Ziffern ohne Alt-Taste (Numpad-Aufdruck W E R / S D F / Z X C = 1..9), Cursor auf IJKL umgestellt.",
      "notesHtml": "<p>Sudoku: Ziffern ohne Alt-Taste (Numpad-Aufdruck W E R / S D F / Z X C = 1..9), Cursor auf IJKL umgestellt.</p>\n"
    },
    {
      "version": "v2.7.1",
      "name": "v2.7.1",
      "datetime": "2026-07-19T07:33:31Z",
      "url": "https://github.com/danst0/fennek/releases/tag/v2.7.1",
      "prerelease": false,
      "notes": "Schach-Trainer-Modus: neuer Gegner bewertet jeden Zug offline (Einstufung + Begründung + Empfehlung). Zentraler WLAN-Multiprofil-Service (services/wifi.*) ersetzt die duplizierte WiFi.begin-Sequenz in 9 Diensten und wählt per Scan das stärkste bekannte Netz.",
      "notesHtml": "<p>Schach-Trainer-Modus: neuer Gegner bewertet jeden Zug offline (Einstufung + Begründung + Empfehlung). Zentraler WLAN-Multiprofil-Service (services/wifi.*) ersetzt die duplizierte WiFi.begin-Sequenz in 9 Diensten und wählt per Scan das stärkste bekannte Netz.</p>\n"
    },
    {
      "version": "v2.7.0",
      "name": "v2.7.0",
      "datetime": "2026-07-19T06:29:18Z",
      "url": "https://github.com/danst0/fennek/releases/tag/v2.7.0",
      "prerelease": false,
      "notes": "Schach: Stufenname im Serial-Log wird jetzt übersetzt (i18n::tr statt Enum-Wert an %s).",
      "notesHtml": "<p>Schach: Stufenname im Serial-Log wird jetzt übersetzt (i18n::tr statt Enum-Wert an %s).</p>\n"
    },
    {
      "version": "v2.6.9",
      "name": "v2.6.9",
      "datetime": "2026-07-19T06:28:17Z",
      "url": "https://github.com/danst0/fennek/releases/tag/v2.6.9",
      "prerelease": false,
      "notes": "Sperrbildschirm als Vollbild (große exakte Uhr, Datum, Akku, Now-Playing, Entsperr-Hinweis) + informativeres Standby-Banner (grobe Uhr \"Nach HH:xx\", nächster Wecker, Akku-Ladeanzeige). Wake-/Entsperr-Hinweise nennen den oberen Knopf.",
      "notesHtml": "<p>Sperrbildschirm als Vollbild (große exakte Uhr, Datum, Akku, Now-Playing, Entsperr-Hinweis) + informativeres Standby-Banner (grobe Uhr \"Nach HH:xx\", nächster Wecker, Akku-Ladeanzeige). Wake-/Entsperr-Hinweise nennen den oberen Knopf.</p>\n"
    },
    {
      "version": "v2.6.5",
      "name": "v2.6.5",
      "datetime": "2026-07-14T11:26:25Z",
      "url": "https://github.com/danst0/fennek/releases/tag/v2.6.5",
      "prerelease": false,
      "notes": "feat(calibre): E-Book-Pull-Sync von Calibre-Web via OPDS\n\n- Neuer Service services/calibre_books: zieht das Buecherregal \"Fennek\" (Shelf, Name oder ID) von Calibre-Web via OPDS und laedt neue EPUBs nach /books (Basic-Auth, Dateiname aus Content-Disposition)\n- Nur-hinzufuegend: Manifest /.fennek/calibre.tsv, max. 8 Downloads/Lauf\n- Auto-Sync vor dem Auto-Standby hoechstens alle 6 h + RTC-Back-off\n- Konsole: calibre url/user/pass/shelf/on/off/sync + Status\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)",
      "notesHtml": "<p>feat(calibre): E-Book-Pull-Sync von Calibre-Web via OPDS</p>\n<ul>\n<li>Neuer Service services/calibre_books: zieht das Buecherregal \"Fennek\" (Shelf, Name oder ID) von Calibre-Web via OPDS und laedt neue EPUBs nach /books (Basic-Auth, Dateiname aus Content-Disposition)</li>\n<li>Nur-hinzufuegend: Manifest /.fennek/calibre.tsv, max. 8 Downloads/Lauf</li>\n<li>Auto-Sync vor dem Auto-Standby hoechstens alle 6 h + RTC-Back-off</li>\n<li>Konsole: calibre url/user/pass/shelf/on/off/sync + Status</li>\n</ul>\n<p>🤖 Generated with <a href=\"https://claude.com/claude-code\" target=\"_blank\" rel=\"noopener noreferrer\">Claude Code</a></p>\n"
    },
    {
      "version": "v2.6.4",
      "name": "Fennek v2.6.4",
      "datetime": "2026-07-14T07:44:33Z",
      "url": "https://github.com/danst0/fennek/releases/tag/v2.6.4",
      "prerelease": false,
      "notes": "Schutznetze gegen stille Akku-Tiefentladung im Standby:\n\n- Schlaf-Diagnose im RTC-RAM (Phase-Breadcrumb + Wake-Historie, beim nächsten Vollboot ins battlog)\n- Task-Watchdog um Timer-Wake-Minimalpfad (30 s) und enterStandby (60 s), Loslass-Warteschleife mit 10-s-Timeout\n- Crash-Loop-Bremse: 3 abnormale Resets in Folge → Not-Standby (nur Knopf-Wake), Crash-Boots flushen sofort auf SD\n- Tiefentladeschutz: ≤5 % auf Akku → sofort Standby, im Schlaf keine Stunden-Wakes mehr (Wecker bis 3 %)\n- GPIO42 (Tastatur-Backlight-Gate) über Deep Sleep gehalten, E-Ink-Controller vor Deep Sleep in hibernate()\n- Launcher: Kachel-Icons links + Text-Label, Lage/Gyro-App deaktiviert",
      "notesHtml": "<p>Schutznetze gegen stille Akku-Tiefentladung im Standby:</p>\n<ul>\n<li>Schlaf-Diagnose im RTC-RAM (Phase-Breadcrumb + Wake-Historie, beim nächsten Vollboot ins battlog)</li>\n<li>Task-Watchdog um Timer-Wake-Minimalpfad (30 s) und enterStandby (60 s), Loslass-Warteschleife mit 10-s-Timeout</li>\n<li>Crash-Loop-Bremse: 3 abnormale Resets in Folge → Not-Standby (nur Knopf-Wake), Crash-Boots flushen sofort auf SD</li>\n<li>Tiefentladeschutz: ≤5 % auf Akku → sofort Standby, im Schlaf keine Stunden-Wakes mehr (Wecker bis 3 %)</li>\n<li>GPIO42 (Tastatur-Backlight-Gate) über Deep Sleep gehalten, E-Ink-Controller vor Deep Sleep in hibernate()</li>\n<li>Launcher: Kachel-Icons links + Text-Label, Lage/Gyro-App deaktiviert</li>\n</ul>\n"
    },
    {
      "version": "v2.6.3",
      "name": "v2.6.3",
      "datetime": "2026-06-24T13:45:28Z",
      "url": "https://github.com/danst0/fennek/releases/tag/v2.6.3",
      "prerelease": false,
      "notes": "App-Kacheln im Launcher zeigen jetzt selbst gezeichnete Icons statt Text (Note, Kopfhörer, Buch, Mesh, Zahnrad, Würfel, Ordner, Notizblatt, Wecker, Pin, Gyro, Operatoren, Karteikarten, Kalender, Todo).\n\nOTA: firmware.bin angehängt.",
      "notesHtml": "<p>App-Kacheln im Launcher zeigen jetzt selbst gezeichnete Icons statt Text (Note, Kopfhörer, Buch, Mesh, Zahnrad, Würfel, Ordner, Notizblatt, Wecker, Pin, Gyro, Operatoren, Karteikarten, Kalender, Todo).</p>\n<p>OTA: firmware.bin angehängt.</p>\n"
    },
    {
      "version": "v2.6.2",
      "name": "v2.6.2",
      "datetime": "2026-06-24T12:51:56Z",
      "url": "https://github.com/danst0/fennek/releases/tag/v2.6.2",
      "prerelease": false,
      "notes": "Rechnen-App: Schätz-Wertung + 20-s-Ziel (gedeckelte Zahlenbereiche, Toleranzfenster für große Produkte/Geld-Prozente/SHARE/GROWTH, Sekunden-Anzeige). Kalender: CalDAV-Abo (iCloud u. a.) via `caldav:`-Feed mit Basic-Auth, Zugangsdaten in Settings-App/Konsole.",
      "notesHtml": "<p>Rechnen-App: Schätz-Wertung + 20-s-Ziel (gedeckelte Zahlenbereiche, Toleranzfenster für große Produkte/Geld-Prozente/SHARE/GROWTH, Sekunden-Anzeige). Kalender: CalDAV-Abo (iCloud u. a.) via <code>caldav:</code>-Feed mit Basic-Auth, Zugangsdaten in Settings-App/Konsole.</p>\n"
    },
    {
      "version": "v2.6.0",
      "name": "v2.6.0",
      "datetime": "2026-06-22T16:46:35Z",
      "url": "https://github.com/danst0/fennek/releases/tag/v2.6.0",
      "prerelease": false,
      "notes": "## Änderungen\n\n- **Tic-Tac-Toe**: Fennek macht mit 20 % Wahrscheinlichkeit einen zufälligen Zug statt Minimax — der Spieler hat jetzt eine echte Chance zu gewinnen\n- **Adaptives Polling**: Eingabe-Polling drosselt sich nach 3 s Leerlauf von ~100 Hz auf ~30 Hz (spart Core-1-Wachzeit ohne spürbare Latenz)\n- **Tap-Log-Drossel**: Gehaltener Finger flutete Serial-Konsole mit Dauer-Taps — jetzt max. 1 Log-Zeile alle 400 ms\n- **`power::idleMs()`**: Neue Funktion gibt Millisekunden seit letzter Aktivität zurück",
      "notesHtml": "<h2>Änderungen</h2>\n<ul>\n<li><strong>Tic-Tac-Toe</strong>: Fennek macht mit 20 % Wahrscheinlichkeit einen zufälligen Zug statt Minimax — der Spieler hat jetzt eine echte Chance zu gewinnen</li>\n<li><strong>Adaptives Polling</strong>: Eingabe-Polling drosselt sich nach 3 s Leerlauf von ~100 Hz auf ~30 Hz (spart Core-1-Wachzeit ohne spürbare Latenz)</li>\n<li><strong>Tap-Log-Drossel</strong>: Gehaltener Finger flutete Serial-Konsole mit Dauer-Taps — jetzt max. 1 Log-Zeile alle 400 ms</li>\n<li><strong><code>power::idleMs()</code></strong>: Neue Funktion gibt Millisekunden seit letzter Aktivität zurück</li>\n</ul>\n"
    },
    {
      "version": "v2.5.9",
      "name": "Fennek v2.5.9",
      "datetime": "2026-06-21T19:36:11Z",
      "url": "https://github.com/danst0/fennek/releases/tag/v2.5.9",
      "prerelease": false,
      "notes": "Podcast-App deaktiviert (WLAN-Sync zu langsam).\n\n- Auto-WLAN-Sync vor Standby (podcast::flushBeforeStandby) auskommentiert — brachte bei jedem Standby das WLAN über den 4-MHz-SD-Bus hoch\n- Launcher-Kachel + appmgr-Registrierung + podcast::begin() aus → App vom Gerät verschwunden, Slot 13 (Seite 2) bleibt leer\n- Code/Konsolen-Befehle/NVS-Toggle/i18n bewusst behalten (reaktivierbar)",
      "notesHtml": "<p>Podcast-App deaktiviert (WLAN-Sync zu langsam).</p>\n<ul>\n<li>Auto-WLAN-Sync vor Standby (podcast::flushBeforeStandby) auskommentiert — brachte bei jedem Standby das WLAN über den 4-MHz-SD-Bus hoch</li>\n<li>Launcher-Kachel + appmgr-Registrierung + podcast::begin() aus → App vom Gerät verschwunden, Slot 13 (Seite 2) bleibt leer</li>\n<li>Code/Konsolen-Befehle/NVS-Toggle/i18n bewusst behalten (reaktivierbar)</li>\n</ul>\n"
    },
    {
      "version": "v2.5.7",
      "name": "v2.5.7",
      "datetime": "2026-06-21T19:05:52Z",
      "url": "https://github.com/danst0/fennek/releases/tag/v2.5.7",
      "prerelease": false,
      "notes": "## Sudoku als fünftes Spiel\n\nNeues Spiel **Sudoku** in der Spiele-App (neben 2048, Minensucher, Schach, Tic-Tac-Toe).\n\n- Arduino-freier Generator + Solver (`sudoku_core.h`, host-getestet): randomisiertes Backtracking für die Vollösung, dann eindeutigkeitsprüfendes Ausgraben — erzeugt nur Rätsel mit genau einer Lösung. Rekursionsfrei (iterativer Level-Stack).\n- 9×9-Gitter à 26 px, Touch-Tap/WASD-Cursor, Zifferntasten 1–9 setzen, 0/Backspace/Mikrofon leeren, Konfliktzellen invertiert, „Gelöst\"-Overlay mit Zeit.\n- Schwierigkeit Leicht/Mittel/Schwer (40/32/26 Vorgaben).\n- Beststände im NVS (gelöste Rätsel + Bestzeit), inkl. INI-Export/-Import.\n\n**OTA:** `firmware.bin` angehängt.",
      "notesHtml": "<h2>Sudoku als fünftes Spiel</h2>\n<p>Neues Spiel <strong>Sudoku</strong> in der Spiele-App (neben 2048, Minensucher, Schach, Tic-Tac-Toe).</p>\n<ul>\n<li>Arduino-freier Generator + Solver (<code>sudoku_core.h</code>, host-getestet): randomisiertes Backtracking für die Vollösung, dann eindeutigkeitsprüfendes Ausgraben — erzeugt nur Rätsel mit genau einer Lösung. Rekursionsfrei (iterativer Level-Stack).</li>\n<li>9×9-Gitter à 26 px, Touch-Tap/WASD-Cursor, Zifferntasten 1–9 setzen, 0/Backspace/Mikrofon leeren, Konfliktzellen invertiert, „Gelöst\"-Overlay mit Zeit.</li>\n<li>Schwierigkeit Leicht/Mittel/Schwer (40/32/26 Vorgaben).</li>\n<li>Beststände im NVS (gelöste Rätsel + Bestzeit), inkl. INI-Export/-Import.</li>\n</ul>\n<p><strong>OTA:</strong> <code>firmware.bin</code> angehängt.</p>\n"
    },
    {
      "version": "v2.5.6",
      "name": "v2.5.6",
      "datetime": "2026-06-21T15:32:44Z",
      "url": "https://github.com/danst0/fennek/releases/tag/v2.5.6",
      "prerelease": false,
      "notes": "fix(power): Dateien-Modus am Kabel nicht einschlafen lassen\n\n- battery::external() (DSG-Bit aus BatteryStatus 0x0A) erkennt Netzteil zuverlässig, auch bei vollem Akku (charging() fiel bei Strom ~0 auf false)\n- power::poll() nutzt external() statt charging() für die Dateien-Standby-Bremse",
      "notesHtml": "<p>fix(power): Dateien-Modus am Kabel nicht einschlafen lassen</p>\n<ul>\n<li>battery::external() (DSG-Bit aus BatteryStatus 0x0A) erkennt Netzteil zuverlässig, auch bei vollem Akku (charging() fiel bei Strom ~0 auf false)</li>\n<li>power::poll() nutzt external() statt charging() für die Dateien-Standby-Bremse</li>\n</ul>\n"
    },
    {
      "version": "v2.5.5",
      "name": "v2.5.5",
      "datetime": "2026-06-21T15:07:48Z",
      "url": "https://github.com/danst0/fennek/releases/tag/v2.5.5",
      "prerelease": false,
      "notes": "feat(wecker): Einmalig-Option für Wecker\n\n- Neues Alarm-Feld `once` (NVS byte0 Bit4, abwärtskompatibel)\n- Einmalige Wecker feuern am nächsten hh:mm tageunabhängig und schalten sich danach selbst aus\n- Editor-Preset \"Einmalig\" im Feld Tage; Liste/Editor zeigen es an\n- Konsole: `alarm <i> <hh:mm> einmal` (once/1x)\n\nOTA: firmware.bin angehängt.",
      "notesHtml": "<p>feat(wecker): Einmalig-Option für Wecker</p>\n<ul>\n<li>Neues Alarm-Feld <code>once</code> (NVS byte0 Bit4, abwärtskompatibel)</li>\n<li>Einmalige Wecker feuern am nächsten hh:mm tageunabhängig und schalten sich danach selbst aus</li>\n<li>Editor-Preset \"Einmalig\" im Feld Tage; Liste/Editor zeigen es an</li>\n<li>Konsole: <code>alarm &lt;i&gt; &lt;hh:mm&gt; einmal</code> (once/1x)</li>\n</ul>\n<p>OTA: firmware.bin angehängt.</p>\n"
    },
    {
      "version": "v2.5.4",
      "name": "v2.5.4",
      "datetime": "2026-06-21T15:00:17Z",
      "url": "https://github.com/danst0/fennek/releases/tag/v2.5.4",
      "prerelease": false,
      "notes": "OTA-Update-Fix + Ollama-Timeout.\n\n- **OTA `-104` behoben:** GitHub liefert für Release-Assets eine signierte Redirect-URL (`release-assets.githubusercontent.com`, ~900 Zeichen). Diese sprengte den 300-Byte-Puffer in `apply()` → abgeschnittene URL → `httpUpdate`-Fehler `-104` (wrong http code). Puffer auf 1400 Byte vergrößert.\n- **notes_ai (Ollama) Timeout:** `HTTPClient::setTimeout()` nimmt `uint16_t` (max 65535 ms); der Wert 120000 lief still auf 54464 ms über. Konstante auf 65000 ms korrigiert.\n\nErstes Release, mit dem OTA von einer früheren Version aus zuverlässig durchläuft.",
      "notesHtml": "<p>OTA-Update-Fix + Ollama-Timeout.</p>\n<ul>\n<li><strong>OTA <code>-104</code> behoben:</strong> GitHub liefert für Release-Assets eine signierte Redirect-URL (<code>release-assets.githubusercontent.com</code>, ~900 Zeichen). Diese sprengte den 300-Byte-Puffer in <code>apply()</code> → abgeschnittene URL → <code>httpUpdate</code>-Fehler <code>-104</code> (wrong http code). Puffer auf 1400 Byte vergrößert.</li>\n<li><strong>notes_ai (Ollama) Timeout:</strong> <code>HTTPClient::setTimeout()</code> nimmt <code>uint16_t</code> (max 65535 ms); der Wert 120000 lief still auf 54464 ms über. Konstante auf 65000 ms korrigiert.</li>\n</ul>\n<p>Erstes Release, mit dem OTA von einer früheren Version aus zuverlässig durchläuft.</p>\n"
    },
    {
      "version": "v2.5.3",
      "name": "v2.5.3",
      "datetime": "2026-06-21T14:48:58Z",
      "url": "https://github.com/danst0/fennek/releases/tag/v2.5.3",
      "prerelease": false,
      "notes": "perf(dateien): Request-Zähler-Refresh 10x seltener gegen E-Ink-Flackern\n\n- Drosselung des Request-Zähler-Voll-Redraws im RUNNING-Zustand von 5 s auf 50 s\n- Zähler ist reine Info; seltenere Voll-Redraws sparen sichtbares E-Ink-Flackern",
      "notesHtml": "<p>perf(dateien): Request-Zähler-Refresh 10x seltener gegen E-Ink-Flackern</p>\n<ul>\n<li>Drosselung des Request-Zähler-Voll-Redraws im RUNNING-Zustand von 5 s auf 50 s</li>\n<li>Zähler ist reine Info; seltenere Voll-Redraws sparen sichtbares E-Ink-Flackern</li>\n</ul>\n"
    },
    {
      "version": "v2.5.2",
      "name": "Fennek v2.5.2",
      "datetime": "2026-06-21T14:29:15Z",
      "url": "https://github.com/danst0/fennek/releases/tag/v2.5.2",
      "prerelease": false,
      "notes": "## Highlights\n\n- **On-Device-OTA-Knopf** (Settings → Update → „Aktualisieren\"): prüft GitHub-Releases und flasht direkt am Gerät mit Vollbild-Fortschritt (Phase + Balken + %). Kein Browser/Konsole mehr nötig.\n- **Notizen:** Audionotiz-Player (Play/Pause, ±10 s, Region-Fortschritt) + hoch-scrollbarer Editor.\n- **Karteikarten:** Übersicht mit Leitner-Fächer-Verteilung (fällig/bearbeitet).\n- **Kopfrechnen:** adaptive Schwierigkeit, je-Modus persistierte Stufe.\n- **notes_ai:** behutsamerer Korrektur-Prompt (nur Rechtschreibung/Umlaute, kein Umdichten).\n- **Tools:** `maps_tiles.py` mit wählbaren Kachelquellen (`--preset standard|cyclosm|topo`).\n\n## OTA-Update\n\nGeräte ab v2.5.1 können direkt am Gerät auf diese Version aktualisieren (Settings → Update → „Aktualisieren\") oder via Web-UI (`fennek.local`) / Konsole (`ota update`).\n\n**Flashen (USB):** `firmware.bin` in den inaktiven OTA-Slot bzw. via `pio run -e fennek -t upload`.",
      "notesHtml": "<h2>Highlights</h2>\n<ul>\n<li><strong>On-Device-OTA-Knopf</strong> (Settings → Update → „Aktualisieren\"): prüft GitHub-Releases und flasht direkt am Gerät mit Vollbild-Fortschritt (Phase + Balken + %). Kein Browser/Konsole mehr nötig.</li>\n<li><strong>Notizen:</strong> Audionotiz-Player (Play/Pause, ±10 s, Region-Fortschritt) + hoch-scrollbarer Editor.</li>\n<li><strong>Karteikarten:</strong> Übersicht mit Leitner-Fächer-Verteilung (fällig/bearbeitet).</li>\n<li><strong>Kopfrechnen:</strong> adaptive Schwierigkeit, je-Modus persistierte Stufe.</li>\n<li><strong>notes_ai:</strong> behutsamerer Korrektur-Prompt (nur Rechtschreibung/Umlaute, kein Umdichten).</li>\n<li><strong>Tools:</strong> <code>maps_tiles.py</code> mit wählbaren Kachelquellen (<code>--preset standard|cyclosm|topo</code>).</li>\n</ul>\n<h2>OTA-Update</h2>\n<p>Geräte ab v2.5.1 können direkt am Gerät auf diese Version aktualisieren (Settings → Update → „Aktualisieren\") oder via Web-UI (<code>fennek.local</code>) / Konsole (<code>ota update</code>).</p>\n<p><strong>Flashen (USB):</strong> <code>firmware.bin</code> in den inaktiven OTA-Slot bzw. via <code>pio run -e fennek -t upload</code>.</p>\n"
    },
    {
      "version": "v2.5.0",
      "name": "v2.5.0",
      "datetime": "2026-06-21T10:11:51Z",
      "url": "https://github.com/danst0/fennek/releases/tag/v2.5.0",
      "prerelease": false,
      "notes": "**Full Changelog**: https://github.com/danst0/fennek/compare/v2.4.9...v2.5.0",
      "notesHtml": "<p><strong>Full Changelog</strong>: <a href=\"https://github.com/danst0/fennek/compare/v2.4.9...v2.5.0\" target=\"_blank\" rel=\"noopener noreferrer\">https://github.com/danst0/fennek/compare/v2.4.9...v2.5.0</a></p>\n"
    },
    {
      "version": "v2.4.8",
      "name": "Fennek v2.4.8",
      "datetime": "2026-06-20T19:59:52Z",
      "url": "https://github.com/danst0/fennek/releases/tag/v2.4.8",
      "prerelease": false,
      "notes": "## Änderungen\n\n- **OTA:** Semver-Vergleich für Update-Erkennung (`tag_name != FENNEK_VERSION` → korrekte Versionslogik)\n- **Akku:** Batterieanzeige-Fix in der Statuszeile\n\n## Flashen\n\n```\npio run -e fennek -t upload\n```\n\noder OTA via `fennek.local` → Firmware-Update.",
      "notesHtml": "<h2>Änderungen</h2>\n<ul>\n<li><strong>OTA:</strong> Semver-Vergleich für Update-Erkennung (<code>tag_name != FENNEK_VERSION</code> → korrekte Versionslogik)</li>\n<li><strong>Akku:</strong> Batterieanzeige-Fix in der Statuszeile</li>\n</ul>\n<h2>Flashen</h2>\n<pre><code>pio run -e fennek -t upload\n</code></pre>\n<p>oder OTA via <code>fennek.local</code> → Firmware-Update.</p>\n"
    },
    {
      "version": "v2.3.1",
      "name": "Fennek v2.3.1",
      "datetime": "2026-06-19T14:27:33Z",
      "url": "https://github.com/danst0/fennek/releases/tag/v2.3.1",
      "prerelease": false,
      "notes": "## Notizen / Audio\n- **Sprachnotiz-Liste** zeigt jetzt **Datum + HH:MM** (statt HH:MM:SS bzw. generisch „Sprachnotiz\").\n- **Aufnahme-Gain ×6** mit Sättigung: das PDM-Mikro war ~−20 dBFS leise → Wiedergabe kaum hörbar. Neue Aufnahmen sitzen bei ~−7 dBFS (kein Clipping).\n- **Sauberer I2S0-Handover** nach der Aufnahme: kein doppeltes `i2s_driver_uninstall` mehr (`endMic`/`MicResume` macht uninstall+install in einem Schritt).\n\n## Karten / GPS\n- **No-Fix-Fallback** zentriert jetzt auf **Düsseldorf** (51.2277/6.7735); `DEFAULT_ZOOM` 15 → 13 (NRW-weit bekachelt).\n- **GPS-Zeit-Diagnose**: Einmal-Log `[MAPS] GPS-Zeit empfangen …` pro Karten-Session.\n\nEnthält außerdem v2.3.0 (GPS-/WAV-Diagnose-Logs, Karten-Fallback, Notizen-Zeitlabel).",
      "notesHtml": "<h2>Notizen / Audio</h2>\n<ul>\n<li><strong>Sprachnotiz-Liste</strong> zeigt jetzt <strong>Datum + HH:MM</strong> (statt HH:MM:SS bzw. generisch „Sprachnotiz\").</li>\n<li><strong>Aufnahme-Gain ×6</strong> mit Sättigung: das PDM-Mikro war ~−20 dBFS leise → Wiedergabe kaum hörbar. Neue Aufnahmen sitzen bei ~−7 dBFS (kein Clipping).</li>\n<li><strong>Sauberer I2S0-Handover</strong> nach der Aufnahme: kein doppeltes <code>i2s_driver_uninstall</code> mehr (<code>endMic</code>/<code>MicResume</code> macht uninstall+install in einem Schritt).</li>\n</ul>\n<h2>Karten / GPS</h2>\n<ul>\n<li><strong>No-Fix-Fallback</strong> zentriert jetzt auf <strong>Düsseldorf</strong> (51.2277/6.7735); <code>DEFAULT_ZOOM</code> 15 → 13 (NRW-weit bekachelt).</li>\n<li><strong>GPS-Zeit-Diagnose</strong>: Einmal-Log <code>[MAPS] GPS-Zeit empfangen …</code> pro Karten-Session.</li>\n</ul>\n<p>Enthält außerdem v2.3.0 (GPS-/WAV-Diagnose-Logs, Karten-Fallback, Notizen-Zeitlabel).</p>\n"
    }
  ],
  "changelogSource": "github",
  "changelogUpdatedAt": "2026-07-22T19:24:23.874Z",
  "deviceFamilies": [
    {
      "id": "lilygo-t-deck",
      "label": "LilyGo T-Deck"
    }
  ],
  "primaryFamily": {
    "id": "lilygo-t-deck",
    "label": "LilyGo T-Deck"
  },
  "scopeGroup": "LilyGo T-Deck"
}
