Change a screen's settings on the screen itself (0.2.52)

Holding the top bar for about a second and a half opens a settings page on the
screen, with a blue line filling along the top edge while you hold. A built-in
screen.settings tile and the esphome.<screen>_open_settings action open it too.

The page is one constexpr table of rows in settings_screen.h: Brightness,
Night, Screen (clock, back to page 1, swiping, rotation) and This screen (name,
address, firmware, Home Assistant, Restart). Toggles flip on a tap, numbers and
times step with -/+ (a held time walks whole hours), a choice cycles in a chip,
and a row that depends on a switch above it is greyed out. The LVGL objects exist
only while the page is open: +608 bytes of RAM and +10.7 KB of flash on the CYD.
A change is saved, applied and reported through the existing screen_setting
event, so ESP Screens shows the same value within a second.

New setting auto_home (default on, 2 minutes): an open card, the settings page
or a later page goes back to page 1 after that long without a touch, not only on
standby. It travels beside the frozen eleven-key settings block with its own
preference, so older firmware and older apps keep working.

docs/SETTINGS.md is the recipe for adding a setting; the Claude skill explains
the page. Firmware 0.2.44.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Max Gramser
2026-09-16 10:05:53 +02:00
parent 93c789dc48
commit b83164d61a
28 changed files with 1645 additions and 27 deletions
+4 -1
View File
@@ -22,7 +22,7 @@ inline bool valid_entity(const std::string &entity) {
!(entity[i] >= '0' && entity[i] <= '9') && entity[i] != '_') return false;
std::string domain = entity.substr(0, dot);
// screen.* are built-in cards without a Home Assistant entity behind them.
if (domain == "screen") return entity == "screen.clock";
if (domain == "screen") return entity == "screen.clock" || entity == "screen.settings";
for (const auto *allowed : {"light", "switch", "input_boolean", "scene", "script", "climate", "vacuum", "fan", "cover", "sensor", "binary_sensor", "input_select", "select", "number", "input_number", "weather", "media_player", "button", "input_button", "sun", "timer", "person"})
if (domain == allowed) return true;
return false;
@@ -146,6 +146,9 @@ struct Tile {
void observe(uint32_t next) { revision=next; if (pending && revision!=pending_revision) confirmed=true; }
std::string domain() const { return entity.substr(0, entity.find('.')); }
bool builtin() const { return domain() == "screen"; }
// Two built-in cards, and only one of them is a clock that has to be redrawn every minute.
bool is_clock() const { return entity == "screen.clock"; }
bool is_settings() const { return entity == "screen.settings"; }
bool available() const { return builtin() || (received && state != "unknown" && state != "unavailable" && !state.empty()); }
bool active() const {
return state == "on" || state == "cleaning" || state == "active" || (domain() == "person" && state == "home") ||