fix: MCP settings persistence + WebServer/DevServer coexistence + screensaver charging toggle
- 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.
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
#include <Tactility/Logger.h>
|
||||
#include <Tactility/CoreDefines.h>
|
||||
#include <Tactility/hal/display/DisplayDevice.h>
|
||||
#include <Tactility/hal/power/PowerDevice.h>
|
||||
#include <Tactility/lvgl/LvglSync.h>
|
||||
#include <Tactility/service/ServiceContext.h>
|
||||
#include <Tactility/service/ServiceManifest.h>
|
||||
@@ -30,6 +31,22 @@ static std::shared_ptr<hal::display::DisplayDevice> getDisplay() {
|
||||
return hal::findFirstDevice<hal::display::DisplayDevice>(hal::Device::Type::Display);
|
||||
}
|
||||
|
||||
static bool isDeviceCharging() {
|
||||
bool charging = false;
|
||||
hal::findDevices<hal::power::PowerDevice>(hal::Device::Type::Power, [&charging](const auto& power) {
|
||||
if (!power->supportsMetric(hal::power::PowerDevice::MetricType::IsCharging)) {
|
||||
return true; // continue
|
||||
}
|
||||
hal::power::PowerDevice::MetricData data;
|
||||
if (power->getMetric(hal::power::PowerDevice::MetricType::IsCharging, data) && data.valueAsBool) {
|
||||
charging = true;
|
||||
return false; // stop iter
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return charging;
|
||||
}
|
||||
|
||||
void DisplayIdleService::stopScreensaverCb(lv_event_t* e) {
|
||||
auto* self = static_cast<DisplayIdleService*>(lv_event_get_user_data(e));
|
||||
self->stopScreensaverLocked();
|
||||
@@ -178,43 +195,53 @@ void DisplayIdleService::tick() {
|
||||
}
|
||||
|
||||
auto display = getDisplay();
|
||||
if (display != nullptr && display->supportsBacklightDuty()) {
|
||||
bool supportsBacklight = display != nullptr && display->supportsBacklightDuty();
|
||||
|
||||
if (supportsBacklight) {
|
||||
if (!cachedDisplaySettings.backlightTimeoutEnabled || cachedDisplaySettings.backlightTimeoutMs == 0) {
|
||||
if (displayDimmed) {
|
||||
display->setBacklightDuty(cachedDisplaySettings.backlightDuty);
|
||||
displayDimmed = false;
|
||||
}
|
||||
} else {
|
||||
bool charging_blocks = cachedDisplaySettings.disableScreensaverWhenCharging && isDeviceCharging();
|
||||
|
||||
if (!displayDimmed && inactive_ms >= cachedDisplaySettings.backlightTimeoutMs) {
|
||||
if (!lvgl::lock(100)) {
|
||||
return; // Retry on next tick
|
||||
if (charging_blocks) {
|
||||
// Skip screensaver while charging
|
||||
} else {
|
||||
if (!lvgl::lock(100)) {
|
||||
return; // Retry on next tick
|
||||
}
|
||||
activateScreensaver();
|
||||
lvgl::unlock();
|
||||
if (cachedDisplaySettings.screensaverType == settings::display::ScreensaverType::None) {
|
||||
display->setBacklightDuty(0);
|
||||
}
|
||||
displayDimmed = true;
|
||||
}
|
||||
activateScreensaver();
|
||||
lvgl::unlock();
|
||||
// Turn off backlight for "None" screensaver (just black screen)
|
||||
if (cachedDisplaySettings.screensaverType == settings::display::ScreensaverType::None) {
|
||||
display->setBacklightDuty(0);
|
||||
} else if (displayDimmed) {
|
||||
if (inactive_ms < kWakeActivityThresholdMs) {
|
||||
stopScreensaver();
|
||||
} else if (charging_blocks) {
|
||||
stopScreensaver();
|
||||
}
|
||||
displayDimmed = true;
|
||||
} else if (displayDimmed && (inactive_ms < kWakeActivityThresholdMs)) {
|
||||
stopScreensaver();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool DisplayIdleService::onStart(ServiceContext& service) {
|
||||
auto display = getDisplay();
|
||||
if (display != nullptr && !display->supportsBacklightDuty()) {
|
||||
LOGGER.info("Monochrome/RLCD display detected (no backlight control): disabling screensaver tick timer");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Seed random number generator for varied screensaver patterns
|
||||
srand(static_cast<unsigned int>(time(nullptr)));
|
||||
|
||||
cachedDisplaySettings = settings::display::loadOrGetDefault();
|
||||
|
||||
auto display = getDisplay();
|
||||
if (display != nullptr && !display->supportsBacklightDuty()) {
|
||||
LOGGER.info("Monochrome/RLCD display detected (no backlight control): idle timer will run but auto-backlight off is disabled");
|
||||
}
|
||||
|
||||
timer = std::make_unique<Timer>(Timer::Type::Periodic, kernel::millisToTicks(TICK_INTERVAL_MS), [this]{ this->tick(); });
|
||||
timer->setCallbackPriority(Thread::Priority::Lower);
|
||||
timer->start();
|
||||
@@ -297,10 +324,12 @@ void DisplayIdleService::startMcpScreensaver() {
|
||||
screensaverActiveCounter = 0;
|
||||
backlightOff = false;
|
||||
|
||||
// Ensure backlight is active and set to configured duty cycle
|
||||
// Ensure backlight is active if the display supports it
|
||||
auto display = getDisplay();
|
||||
if (display) {
|
||||
display->setBacklightDuty(cachedDisplaySettings.backlightDuty);
|
||||
if (display != nullptr && display->supportsBacklightDuty()) {
|
||||
uint8_t duty = cachedDisplaySettings.backlightDuty;
|
||||
if (duty == 0) duty = 255; // ensure visible if settings not loaded / default
|
||||
display->setBacklightDuty(duty);
|
||||
}
|
||||
|
||||
lv_coord_t screenW = lv_display_get_horizontal_resolution(nullptr);
|
||||
|
||||
Reference in New Issue
Block a user