RLCD ST7305 has !supportsBacklightDuty(). Previous fix that fixed MCP flash-then-back left entire idle state machine gated by supportsBacklight, causing once dimmed it could never wake on button press -> appears locked weird state reported.
Fix: run timeout logic for all displays, guard only setBacklightDuty calls.
- timeout disabled (Never) branch always restores displayDimmed
- timeout activation creates screensaver for all
- wake on inactive<100ms + charging block works for RLCD
- setBacklightDuty only when supportsBacklight && display!=nullptr
Also preserves deadlock-free ordering (MCP state outside LVGL lock) from 3629ffef.
RLCD: 0x2b78b0 32%% free flashed /dev/cu.usbmodem101
Co-Authored-By: internal-model
DisplayIdle::tick() runs every 50ms. After startMcpScreensaver()
sets displayDimmed=true, the next tick saw inactive_ms < 100ms
(user navigated Settings) and called stopScreensaver() ->
overlay deleted in <1s, text tool flash-then-back.
Root cause: idle wake logic (inactive<100ms) + charging guard +
duty-restore all operated on any overlay including MCP override.
Fix: detect MCP active via (drawArea != nullptr || overrideActive)
under state.mutex, guard all auto-stop paths with !isMcpActive.
MCP still closable via click handler on overlay (CLICKABLE flag).
Test: flash es3c28p 2be0c0 31% free to /dev/cu.usbmodem101
192.168.68.113 dashboard 200, dev 6666 ok, /api/mcp 25 tools.
Requires PYTHONPATH cleaned for idf.py build (Hermes venv hijacks
pydantic_core).
- McpSettings was hardcoded to /data/service/mcp/settings.properties,
but ES3C28P uses storage.userDataLocation=SD so user data lives on
/sdcard/tactility/. Settings appeared to save but on reload returned
default false -> "enable and when I go back shows disabled".
Fixed to use getUserDataPath()+"/settings/mcp.properties" pattern
consistent with DisplaySettings/WebServerSettings, with
findOrCreateParentDirectory() and isFile() guard.
- HttpServer ctrl_port collision: ESP-IDF default 32768 used by both
WebServer (80) and DevelopmentService (6666). Second httpd_start()
failed silently -> dashboard up but /api/mcp 404 and :6666 refused.
Fixed with unique ctrl_port = 32768 + (port % 1000).
Added CONFIG_HTTPD_MAX_URI_HANDLERS=20 (default 8 < 9 needed for
7 handlers + 2 internal).
- DevService stack 5120 -> 8192 for /app/install handling.
- McpSystem video stream task stack 4096 -> 8192 and idle yield 50ms
(was 5ms always) to avoid CPU starvation blocking httpd tasks.
On RLCD, timer must always run: DisplayIdle early return on
!supportsBacklightDuty() broke MCP manual activation (cachedSettings
not loaded, backlight duty 0). Fixed to always load settings +
start timer, log RLCD detection, guard setBacklightDuty with
supportsBacklightDuty() and fallback duty 255.
- DisplaySettings: add disableScreensaverWhenCharging bool, persisted,
with UI toggle in Display app (Settings->Display) using
PowerDevice::IsCharging check via findDevices callback.
When charging and flag enabled, screensaver activation skipped,
and if already dimmed, wake on charging.
- ES3C28P Power driver: GPIO9 ADC1_CH8 2x divider 2500-4200mV spec from
~/Downloads official docs, TP4054 CHRG not connected to GPIO, so
IsCharging inferred via voltage thresholds (<500mV no battery USB
or >5000mV wall powered, >=4150mV high) + rising trend.
Verified: flashed es3c28p to /dev/cu.usbmodem101 (192.168.68.113),
WiFi FamReynaMesh RSSI -59, dashboard 200, :6666/info now works,
/api/mcp returns disabled correctly until enabled, persists to SD.
- Add ScreensaverType::McpScreen to DisplaySettings enum, toString/fromString
- Add 'MCP Screen' option to the Display settings screensaver dropdown
- New McpScreensaver (Screensaver subclass): creates full-screen lv_canvas on
the overlay, allocates framebuffer in SPIRAM, registers canvas pointer in
McpSystemState, shows 'Waiting for LLM...' until first draw command arrives
- Wire McpScreensaver into DisplayIdle::activateScreensaver() switch
- McpSystem::ensureOverrideScreen() now calls displayidle::findService()->
startScreensaver() instead of launching McpOverrideApp — canvas appears
automatically on any LLM draw command
- Remove McpOverrideApp (replaced by screensaver), deregister from Tactility.cpp
- Remove mcpOverrideEnabled from McpSettings — no longer needed
- Simplify McpSettingsApp: remove Screen Override toggle, update info text to
direct users to Settings -> Display -> Screensaver -> MCP Screen
Adds screensavers in addition to the backlight idle off.
More info in screensavers.md
<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit
* **New Features**
* Added a screensaver system with multiple styles (Bouncing Balls, Mystify, Matrix Rain) and a common screensaver interface; auto-starts after inactivity, dismisses on interaction, and supports auto-off/backlight behavior.
* New Display setting and UI dropdown to choose and persist the screensaver.
* **Documentation**
* Added comprehensive screensaver docs covering usage, extension, and configuration.
* **Chores**
* Registered the display-idle service.
* **Bug Fixes**
* Updated LVGL API calls to match renamed functions.
<sub>✏️ Tip: You can customize this high-level summary in your review settings.</sub>
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
* **New Features**
* Time and delay utilities added (ticks, ms, µs); SD card now uses an expansion-header CS pin; HTTP downloads warn when run on the GUI task and yield to avoid blocking.
* **Bug Fixes / Reliability**
* Many hard-crash paths converted to guarded checks to reduce abrupt termination and improve stability.
* **Tests**
* Unit tests added to validate time and delay accuracy.
* **Chores**
* License header and build/macro updates.
- `TT_LOG_*` macros are replaced by `Logger` via `#include<Tactility/Logger.h>`
- Changed default timezone to Europe/Amsterdam
- Fix for logic bug in unPhone hardware
- Fix for init/deinit in DRV2605 driver
- Other fixes
- Removed optimization that broke unPhone (disabled the moving of heap-related functions to flash)
Lots of things "ported" over from the "enhanced" fork. With some adjustments here and there.
KeyboardBacklight driver (for T-Deck only currently)
Trackball driver (for T-Deck only currently)
Keyboard backlight sleep/wake (for T-Deck only currently...also requires keyboard firmware update)
Display sleep/wake
Files - create file/folder
Keyboard settings (for T-Deck only currently)
Time & Date settings tweaks
Locale settings tweaks
Systeminfo additions
Espnow wifi coexist
initI2cDevices - moved to T-deck init.cpp / initBoot
KeyboardInitService - removed, moved to T-deck init.cpp / initBoot
Adjusted TIMER_UPDATE_INTERVAL to 2 seconds.
Added lock to ActionCreateFolder
Maybe missed some things in the list.
Display wake could do with some kind of block on wake first touch to prevent UI elements being hit when waking device with touch. Same with encoder/trackball/keyboard press i guess.
The original code was written by @cscott0108 at https://github.com/cscott0108/tactility-enhanced-t-deck