Files
homeassistant_espscreen/docs/PROFILES.md
T
Max Gramser 3b15e7f7a3 Build the screens with ESPHome 2026.9 and keep its build memory in the app's own storage, give the CYD 94 KB more room, and stop a timer from counting one second too many (0.2.89)
The add-on ships ESPHome 2026.9.0: it builds an ESP32 with ESP-IDF itself
and keeps a compiler cache. firmware.py gives the CLI its own storage in
/data (ESPHOME_DATA_DIR /data/esphome, which the ESPHome Device Builder no
longer wipes on start; ESP-IDF and ccache in /data/idf, at most 1 GB;
compilers limited to the core count as PlatformIO ran them), removes the
unused PlatformIO once before the first ESP-IDF build, and leaves the new
folders out of backups.

Firmware 0.2.75: assertion_level SILENT in every board's esp32 block, the
core logs from INFO, and clock_parts() in runtime_model.h replaces sscanf.
timer_left() caps a running timer at its duration (the screen's clock runs
up to a second behind Home Assistant's). The packages keep min_version
2026.6.2, the top-level online_image and OTA passwords for new screens, so
an add-on or Device Builder that isn't updated yet keeps building every
screen; CI now builds both boards with the add-on's ESPHome and with
min_version. ESP-IDF's error names stay on, and build_flags stay under
platformio_options, because ESPHome 2026.9's LVGL reads only those.

tools/check.sh: 478 Python tests, 19/19 C++, editor; --firmware PASS with
ESPHome 2026.6.2 (CYD 87.7 %), 2026.8.1 (88.3 %) and 2026.9.0 (86.4 %,
was 91.5 %). Both bench screens OTA'd and watched for half an hour;
ESP Screens as a local add-on on the Yellow built both profiles
(CYD 1,037 s first build, 41 s unchanged). Details:
docs/TEST_RESULTS_0289.md.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 12:35:49 +02:00

71 lines
6.6 KiB
Markdown

# One screen, three files: the shared core and the board files
Since app 0.2.84 a screen's ESPHome configuration is one shared file plus one file per board, put together by
ESPHome's own [packages](https://esphome.io/components/packages/) mechanism. Before, each board was a 5,000-line
profile of which 87 % was the same text as the other board's; every change had to be made twice and the two had
already drifted apart in small ways.
| File | What it holds |
|---|---|
| `packages/core.yaml` | Everything every board shares: the LVGL tree (tiles, cards, overlays, the touch test page), the scripts, the API actions, the entities, the fonts, the globals, and Wi-Fi that never dozes (`power_save_mode: none`, firmware 0.2.74+; the network itself stays in the screen's own YAML). It contains no number that depends on the board: every such value is a `${NAME}` the board file defines. |
| `packages/boards/cyd-2432s028.yaml` | The CYD: its hardware (ILI9341 over SPI, XPT2046 resistive touch, backlight, LED), its sizes and font sizes, the code the shared lambdas take from it (the *hooks*, below), and what only a CYD has: the calibration wizard, a page swipe by LVGL's gesture, `ui_self_test`, the two scripts that drive the backlight as a light action, its climate card layout. |
| `packages/boards/guition-4848s040.yaml` | The Guition: its hardware (ST7701S RGB, GT911, PSRAM), its sizes, its hooks, and what only a Guition has: camera images (`online_image`, the alert's picture frame), the Rotation entity, the page swipe from the glass edge, the snapshot diagnostics, the climate card with its fan and swing card, the wider tile labels (`!extend` on each tile). |
| `packages/cyd.yaml`, `packages/guition.yaml` | What a screen installed from ESP Screens builds from over GitHub, unchanged in name and place: ESP Screen Manager writes every screen's YAML with `files: [packages/<board>.yaml]`. Each is a few lines: where the fonts are, the components from GitHub, and `packages: {core: !include core.yaml, board: !include boards/<board>.yaml}`. |
| `home-like-2432s028.yaml`, `guition-4848s040.yaml` | The same two files for a build from a checkout (the bench, the manual route of README_EXTENDED.md): the components of the checkout, the fonts from `fonts/`, and the secrets from `secrets.yaml`. |
ESPHome merges them in this order: the core, then the board file on top of it, then the entry file on top of both.
A mapping merges key by key, a list of components with ids merges by id (`!extend` adds to an existing widget or
script, `!remove` takes one away), any other list is the core's items followed by the board's, and a plain value of
the board file replaces the core's. `esphome config home-like-2432s028.yaml` shows the result.
## The three ways a board differs from the core
1. **A size, a font size, a name.** `${TILE_ICON_SIZE}`, `${FONT_HEADLINE_SIZE}`, `${TOUCH_TEST_TITLE}`: the core
writes the placeholder, the board file's `substitutions:` table gives the value. `tools/check_packages.py` fails
when a board leaves one out, so a new board cannot forget a size.
2. **A stretch of C++ inside a shared lambda.** The Guition sets `runtime_tiles::rotation_supported`, closes its
camera when the cards close, prepares the alert's picture frame; the CYD sets its calibration up and lays the
climate card out for a portrait panel. Each such stretch is a *hook*: a substitution whose value is that board's
exact lines, written where the old profile had them (`${BOOT_ENABLED_HOOK}`, `${CLOSE_CARDS_HOOK}`,
`${APPLY_ROTATION}`, ...). A board that adds nothing there names the hook with an empty value. The hooks sit at
the end of the board file's `substitutions:` table, each with a line that says where it lands.
3. **A whole section or script.** Hardware, `online_image`, the Rotation select, `capture_ui_snapshot`: these are
the board file's own sections, merged next to the core's. `alert_dismiss`, `alert_flash` and `wake_display` are
in both board files because their *steps* differ (a `light.turn_on` action on the CYD, the `set_backlight` script
on the Guition); so are `ui_self_test` and `climate_card_refresh`, whose layouts differ by design.
## Adding a board
1. Copy the board file of the panel that resembles the new one most (a small SPI panel: the CYD; a big RGB panel
with capacitive touch: the Guition) to `packages/boards/<board>.yaml` and change its hardware sections. Keep
`assertion_level: SILENT` in its `esp32:` block (firmware 0.2.75+): every board builds its firmware the same way,
and `tests/test_easy_package.py` checks it.
2. Fill the sizes table for the new resolution, and go through the hooks: keep, change or empty each one.
3. Add `packages/<board>.yaml` and `<board>.yaml` after the existing entries, `<board>` to `ENTRIES` in
`tools/profiles.py` and to `REFS` in `screen_manager/app/core.py` (the boards `installation_yaml()` writes a
profile for), and a `BANDS` entry to `tools/render_topbar.py`. The add-on and the editor still know two boards,
a Guition or not: the board a screen is (`core.py`), `ALERT_LIMITS`, the camera sizes in `camera_feed.py`, and
the editor's New screen choices and `BAR_METRICS` (`web/src`) need the new board too.
4. `python3 tools/check_packages.py`, `esphome config <board>.yaml`, `tools/check.sh --firmware`.
The tiles per page (two columns of three) are still fixed in the firmware, the add-on and the editor
(`SLOTS_PER_PAGE`); a panel that wants more rows is a later round.
## How the split was verified
The split was made by a script that replaced every size in the old CYD profile and asserted the value it replaced
in both old profiles (195 places, 84 names), and took every hook's text from the old profiles by line. Then the
result of `esphome config` and the generated `main.cpp` of both boards, through the checkout entry and through the
GitHub package route, were compared with the same of the old profiles:
- every scalar, every lambda body and every component is the same, apart from whitespace and `#line` directives;
- on the CYD, the calibration setup runs in the same lambda as the effects page's hooks instead of a lambda of
its own (the same statements, in the same order: `${BOOT_CARDS_TAIL}`);
- on the Guition, the alert's picture frame is created after the OK button instead of before it (they never
overlap), and the hidden `camera_image_seed` after the labels;
- the order in which ESPHome declares and registers fonts, entities, scripts, API actions, styles, includes and
build flags follows the merge (the core's first, the board's after), which changes the numbers in ESPHome's
component tables and nothing that runs in sequence.
Every other generated source file of both builds was identical, byte for byte.