A tap on a cover now opens a card like Home Assistant's own, in the style
of the climate and vacuum cards: a tall position slider on which the blind
hangs from the top, a tilt slider over slats for venetian blinds, and open,
stop and close keys. The key of the direction the cover moves is filled; a
key that cannot move it further is disabled and stays out of the keys the
card's tick enables. Sliders show their value while dragged and send it on
release. The card offers only what supported_features allows. A
battery-powered blind shows its battery at the top right: the app sends
the device's battery sensor as the extra the vacuum card uses, and adds
current_tilt_position to the attributes.
Checking Studio 1 after its update to firmware 0.2.49 found that a setting
number equal to its initial state 0 (night brightness 0 %) was never
published, so Home Assistant kept it unknown and ESP Screens could not
change it; apply_screen_settings now publishes a number without a state.
The app also took "unavailable" for the device name during the restart
and wrote sensor.esp_screens_unavailable; diagnostics ignore unknown and
unavailable. The editor redraws its tiles, top bar and entity list when
the live stream opened a screen before the first full inventory (a busy
add-on), and loads app.js and style.css by content stamp after Safari kept
an old script.
Checked with 254 Python and 14 C++ tests, generate_packages --check, ESP32
builds of both profiles, and 20 API checks of the card on host builds of
both boards. Firmware 0.2.50.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A code check found that a setting changed on a screen could jump back.
ESP Screen Manager kept its own copy and sent it with every full update:
after a restart of the app or Home Assistant, every hour and after every
save. A change it missed while it or Home Assistant restarted came back
to the old value, a reported setting was lost when save() refused a
layout with a removed entity, and every step of a held - or + on the
screen resent the whole screen.
Firmware 0.2.49 offers every setting as an entity over the existing
preference records (no migration): Night mode, Night starts/ends,
24-hour clock, Back to page 1 and after how long, Back to page 1 on
standby, Swipe between pages and, on the Guition, Rotation, next to the
four numbers and Auto standby. The settings page and every entity write
through settings_screen::set(), which clamps like the page and stores,
applies and reports only a real change. screen_message answers a caller
that asks with its status and layout revision (api.respond). The
settings tile opens without Home Assistant.
The app reads and changes the settings of such a screen through its
entities and leaves them out of the layout message. Older firmware keeps
them with the layout; a setting it reports is stored without the tile
check and not sent back. Pings to screens that can answer learn at once
whether a tile is missing and resend after 30 s instead of 120 s. Layout
sensors come back after a Home Assistant restart, and weather tiles only
ask for the forecasts the entity supports. The editor's settings form is
now three cards with the rows of the screen's own page; a change applies
at once, and an offline screen shows its values as unknown.
Checked with 245 Python and 14 C++ tests, generate_packages --check,
ESP32 builds of both profiles, host-build API tests on both boards, and
a live run against Home Assistant 2026.9.1 with a temporary host device.
Firmware 0.2.49.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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>
App 0.2.47 / firmware 0.2.40:
- guition-4848s040.yaml gets the CYD's climate card: the setpoint between large -/+ keys
(debounced, hold to repeat) and one row of mode keys in HA's order and colours; the arc,
scrim, mode pill and climate_number font are gone.
- Fan and swing modes sit right on the card as segmented rows behind their icons, drawn by the
new climate_card.h (async rebuild, taps through the touch guard and a profile hook). The card
is laid out per case from one table: no, one or two settings rows, with or without mode keys.
- Both boards hide a mode key row that would hold a single mode and centre the setpoint instead.
- Glyph arrow-oscillating (Home Assistant's swing icon) joins the icon set.
Verified on the Guition over OTA with the owner's air conditioner and with host renders of both
boards; see docs/TEST_RESULTS_0247.md.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
App 0.2.46 / firmware 0.2.39:
- The vacuum's state message carries extras from its own device: the cleaning mode and water
selects (found by translation key, then entity id ending, so localized ids work), the suction
speeds to offer, the battery sensor (HA 2026.8 dropped battery_level), charging and the current
room. Speeds and water levels a mode covers move into the mode row; Custom only while in use.
The manager watches these entities and resends only the vacuum's message when one changes.
- Vacuum card redesign on both boards: robot with state, battery, charging bolt and room; Start
(Pause, Resume) and Dock; then segmented rows for mode, suction and water, showing only the rows
the chosen mode uses. Taps show at once and wait for Home Assistant; Locate is a round button in
the Guition hero.
- CYD climate card without the arc: big setpoint between large -/+ keys (debounced, hold to
repeat) and one row of mode keys in HA's order and colours, with a more key for fan and swing.
- Both profiles clear climate_edit_pending when the climate card is closed, instead of running
ui_refresh every second while the flag stayed set.
Tested with the owner's Roborock S8 on HA 2026.9.1 (live data, OTA-flashed bench boards) and with
host renders of both boards; see docs/TEST_RESULTS_0246.md.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- The app listens for the Home Assistant events esp_screens_show_alert and
esp_screens_dismiss_alert and calls each screen's show_alert/dismiss_alert action,
screens added later included. Fields are typed like Home Assistant's ESPHome action
schema; an unusable value is left empty instead of losing the alert.
- Settings → Claude installs an ESP Screens skill for Claude Code in Home Assistant
(/homeassistant/.claude/skills/esp-screens) or downloads it as a zip for claude.ai.
It is generated from the alert reference, so fields, colors and icons match the firmware.
- New screen, Firmware & USB, firmware updates, Alerts and Claude move to a Settings view;
the header keeps one button. Unselected screens in My screens get a light grey card.
App only; firmware stays 0.2.38.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Firmware 0.2.37 for both boards:
- The analog clock card gets a thin red second hand that moves every second while the
screen is awake (runtime_tiles::screen_awake, set by the profiles from display_dimmed);
in standby it hides and the clock keeps its once-a-minute redraw.
- Card sliders follow HA's control slider: 12/42 and 8/42 corners, a 4 px handle an
eighth of the height from the fill end, a stub of a third of the height at 0 or 1 %,
the track in the fill colour at 20 %. An off light or fan shows only the empty grey
track, also in the colour card's brightness row. A light's slider floors at 1 %.
- Every overlay card shares one top bar: a round back arrow at the left (60/40 px), the
name centred, and only the climate power as a right-hand action. The "done"/"ok"
buttons of the colour and vacuum cards are gone; the brightness card gets its arrow.
- The top bar reads "Connecting to Home Assistant..." / "Waiting for ESP Screens..."
until the first layout, instead of "Choose tiles in HA".
Checked with the host renderer for both boards and on the Guition over USB.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Everything a user sees or reads is now English: both boards' labels,
status replies and logs, the ESP Screens editor and Alerts cheatsheet,
and the README and guides (docs/TILES.md, CALIBRATING.md, ACCEPTANCE.md
and TROUBLESHOOTING.md replace the Dutch file names). Labels follow
Home Assistant's own English names (Heat/Cool modes, Heating/Cooling
actions, Away, Returning to dock, weather conditions), dates use English
abbreviations and the top bar writes numbers the English way. Docs use
HA 2026.9's menu names (Settings -> Apps, App store, Settings -> Tools).
Unused legacy files (home-like.yaml, buttons.yaml, a.out) are removed.
Firmware 0.2.34 names its entities in English. Home Assistant registers
a renamed ESPHome entity under a new entity ID, so the inbox
text.<screen>_tegelinstellingen becomes text.<screen>_tile_settings and
the layout stored under the old ID would be lost. The manager now
recognises the screen by its device, during a run or after a restart,
and moves its layout and update history along; the Update button and
the nightly round follow the screen through the rename. Screens that
still run 0.2.33 or older keep working: both languages are matched.
Main is the only release branch from now on.
Tested on a Home Assistant Yellow (HA 2026.9.1) with both bench boards:
see docs/TEST_RESULTS_0240.md.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The name stays on the left; up to six items go on the right: the time, an
analog clock, the date, or a Home Assistant entity with its icon, showing its
state or how long ago it changed, always or only while active. The add-on
formats entity text in Dutch and sends it as op: header right after the layout
to firmware 0.2.32+; older firmware keeps the clock of show_clock, which now
follows the clock item.
The firmware draws every value in one font on the name's baseline, centres
icons and the dial on the digit height and measures gaps between glyph ink, so
the bar looks even; the editor's mockup uses Roboto and the same integer rules.
tools/render_topbar.py renders the real LVGL code on a computer (ESPHome host +
SDL2). The editor's section buttons are gone.
Firmware 0.2.32 for both boards.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Home Assistant shows an ESPHome device action with bare field names and
types only: no description, no dropdowns. The new Alerts button opens a
reference page instead: per screen the exact action names
(esphome.<node>_show_alert and _dismiss_alert) with copy buttons and
whether the firmware is new enough, a paste-ready YAML example per
screen, every field with explanation, example and the byte limits per
board, all icons with glyph and name (searchable, tap copies), the
colour swatches, the behaviour (timeout, button, flash, standby,
replace), and the esphome.screen_alert event with an automation that
waits for the button.
core.alert_reference() carries the data and tests/test_alerts_reference.py
keeps it equal to what both board profiles, tile_palette.h,
alert_overlay.h and tile_icons.py compile. Screens carry alert_action
and dismiss_action in the inventory. App only; firmware stays 0.2.31.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Tiles get an absolute grid slot instead of a packed order: a tile lands exactly
where it is dropped, dropping on another tile swaps the two, everything else
stays put, and empty cells and empty pages persist. The mockup previews the
result while dragging, a new page waits below the last one, "Pagina toevoegen"
keeps an empty page, empty cells accept the next tile from the picker, and the
mouse no longer selects text while dragging.
Storage and protocol stay version 1: `tiles[].slot` (0-47) and `pages` (1-8)
are additive, the layout message carries `slots` and `pages`. Firmware 0.2.26
places tiles on those slots (`place()` next to `pack()`); older firmware packs
in order as before and the editor says so.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The status line under each screen name used the muted text colour for the
online dot, so online and offline screens looked alike. The dot is now its
own span and turns green when the screen is online; offline keeps the grey
open circle. Firmware 0.2.25 for both boards carries only the new version.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Page swipes were an LVGL gesture anywhere on the screen: 50 px, fast only,
and almost always starting on a tile that lit up as pressed. On the Guition
a touch that starts within 32 px of the left or right edge and travels
40 px inward, clearly sideways, now flips one page (from the right edge
leftwards is next, from the left edge rightwards previous), at any speed
and in every rotation; a swipe that starts in the middle does nothing, so
taps and drags on tiles can no longer change the page by accident. The
whole-screen gesture is removed from the Guition profile; the CYD keeps
it. Firmware 0.2.24 for both boards, the app only reworded the setting.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
"Nieuw scherm" used to span two dialogs plus a copy/download of the
installation YAML. It is now one dialog: board, name (node name derived,
editable), wifi only when secrets.yaml lacks it, the detected USB port,
and Installeren. The add-on writes the profile with unique API/OTA keys,
merges just the missing wifi lines into secrets.yaml (comments and other
secrets untouched, result re-parsed before writing), then builds and
flashes with the live ESPHome log and stage in the same dialog; a failed
build offers a retry without a second profile. The YAML download
endpoint is gone: the profile already lives in the ESPHome folder.
Pairing happens in Home Assistant itself, so the done view and a sidebar
card per not-yet-paired profile say so, with a button to Apparaten &
diensten, the API key to copy and the reminder to allow HA actions.
One profile per screen; the dialog says that too.
Tests: wifi merge cases, install pre-checks, pending list, profile
metadata; the date-anchored hourly forecast test now follows the clock.
Firmware 0.2.22 stays current.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
App 0.2.23 / firmware 0.2.19.
- Wide cards of climate, switch, light, fan, vacuum, cover, media_player,
number, select, timer, scene, script and button show Home Assistant style
controls on the right (keys, -/+ pill with debounced send, slider with
handle, toggle, run key); per-tile choice `options.controls` in the editor
with mockup preview; the add-on sends only the set a card really shows.
- Weather card: now + next hours and coming days with rain, from daily and
hourly forecasts; scenes/scripts/buttons show when they last ran.
- Climate card: power key, tap-to-toggle option, fan and swing rows in a
redesigned mode picker (grey backdrop, white chips, accent selection).
- Busy state as a spinner on a translucent sheet; render guards so only
changed styles reach LVGL; dark theme removed from the runtime code.
- supported_features above 1e6 reaches the screen; middle dot in text fonts;
18 control glyphs in the icon fonts; diagnostics services
preview_climate_picker and preview_busy; demo layout --controls.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
/api/events streams the light inventory whenever the sync loop or a save
changes it (3 s check during firmware updates). The page stops polling
while the stream is open and falls back to the 10 s poll otherwise. The
websocket close is logged with duration, close code and exception.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The sync loop now wakes only for state changes of entities on a layout or
belonging to a screen. Registries refresh on HA registry events with a
10 minute fallback instead of every 30 s. The page polls a light inventory
(screens + update status) every 10 s and the full catalogues every 5 min or
when the tab becomes visible. The full keepalive interval is 120 s.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
/api/inventory re-read every ESPHome profile with pure-Python PyYAML up to
four times per request, which blocked the event loop for seconds on a Pi.
Profiles are now cached per file on (inode, mtime_ns, size), parsed with
libyaml when available, and read once per request. The sync loop computes
the inventory once per iteration. The page pauses polling while hidden.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
- screen_manager/app/tile_icons.py is the single icon list (12 groups, 20 media
and music icons); tools/generate_icons.py writes it into the three icon fonts
of both boards and builds the editor's subset font.
- Firmware 0.2.18 shows o.icon when its fonts carry the glyph, else the domain
icon. The app sends the chosen icon, or Home Assistant's own mdi icon on auto.
- Tile sheet gets an icon picker with search; the mockup shows the icon the
screen actually draws.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The checkbox inherited the global 100%-wide input style, pushing its label
out of the sidebar. App 0.2.17, firmware unchanged.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Screens now report their ESPHome name and IP address, so the add-on can
match each screen to its YAML profile and OTA address itself. The screen
list shows an update badge with a Bijwerken button, an update-all action
and a nightly checkbox; updates run one screen at a time, wait for the
new version to report back and stop the round on the first failure.
App 0.2.16, firmware 0.2.17.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Firmware 0.2.16: the analog clock uses index strokes with 12/3/6/9
numerals on large cards and shows a calendar block (weekday, big day,
short month) beside the dial on single tiles; wide cards keep the digital
time and date. New palette key 'none' hides only the card fill and
border: geometry, padding and the pressed flash stay identical. Skeleton
frames and the render self-test honour the transparency.
App 0.2.15: 'Geen' in the background palette with a dashed mockup tile,
min_firmware 0.2.16 for such layouts, demo layout with the bare calendar
clock (--wide for the double-width clock). README and AGENTS note that
every push is a release and bumps the add-on version.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
App 0.2.14: clicking a card opens a settings sheet (bottom sheet on
mobile) with segmented choices that apply live to the mockup behind it,
so the page no longer scrolls to a list below. Each card gets a remove
button with an undo toast; the old per-tile list is gone.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Firmware 0.2.15: trend graphs use a Catmull-Rom curve with a soft fill
drawn by the card's draw event; sun.sun gets a wide sun-path card with
horizon, arc and the sun at its current position; page switches show
the new page's card frames immediately and fill them from a one-shot
timer; the navigation is one full-width bar without a divider; the CYD
adopts the Guition light palette in styles and overlays.
App 0.2.13: pointer-based drag & drop (mouse and touch) to reorder tiles
in the mockup and to drop entities from the list, sticky save bar, a new
header with explained actions and a three-step guide, clearer firmware
dialog. New sun, weather and clock tiles start wide in their best view.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Any tile can now be double width: pack() in runtime_model.h places wide
tiles in the left column and the manager preview follows the same rules.
New cards: built-in clock (digital or analog, screen.clock), five-day
weather forecast on a wide weather card fed by weather.get_forecasts,
history sparkline for sensors, sunrise/sunset (sun.sun), live kitchen
timer (timer.*, tap starts or pauses) and presence (person.*). The
manager pre-computes time-zone and forecast extras in a new 'x' object
and refuses layouts with new domains until the screen runs 0.2.14.
The self-test follows the packing, checks custom card parts and wide
widths, and diagnostics/send_layout.py pushes a demo layout of every
card type for render checks without Home Assistant. App 0.2.12,
firmware 0.2.14.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>