Show a live picture on a camera tile, run an action from the alert button, roll long media titles, and keep full-page tiles in their own colour (0.2.91)
Live picture (issue #4): a camera or image tile on a Guition takes Display -> Live picture with a pace of 15 or 30 s. The camera tiles of a page share one download: the screen asks ESP Screens for them together (esphome.screen_camera with tiles, size and bg) and the app serves one BMP, a strip of squares with the corners rounded over each tile's own colour; every tile draws its square out of it with LVGL's image offset (LV_IMAGE_ALIGN_TOP_LEFT: the default centres a taller source). A third online_image on the Guition holds the strip; it loads after the alert's picture, a cover and the camera full screen, never under a card, in standby or under a finger. The strip is served whole every time: ESPHome's http_request logs a 304 as a failed request. Firmware 0.2.77. Alert button: esp_screens_show_alert takes action and data; the app performs the action once when the button's report (esphome.screen_alert, ok) comes from any screen. show_alert keeps its seven fields, so every firmware from 0.2.31 has it. Media card and full-page media tile: a title or artist line that is too wide rolls by (LV_LABEL_LONG_SCROLL_CIRCULAR) instead of ending in dots. Full-page tiles are white or their own pastel like every other tile; the tint in the state colour of firmware 0.2.62 to 0.2.76 is gone. Host harness (27 checks) and bench Guition + local add-on on the Yellow: docs/TEST_RESULTS_0291.md. CYD firmware 1,633,728 B, 89.0 %. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
+35
-5
@@ -35,6 +35,34 @@ what plays, with the title, the artist and the album, a progress bar and the key
|
||||
size *Full page* the alert's picture goes first: the tile's cover waits until the alert's picture
|
||||
is there, and a cover already on its way finishes before the alert's picture starts.
|
||||
|
||||
## A live picture on a camera tile
|
||||
|
||||
App 0.2.91 with firmware 0.2.77 puts the camera on the tile itself: **Display → Live picture** in the
|
||||
tile's settings, with a pace of 15 or 30 seconds (`refresh`). The tile shows a small square of the
|
||||
camera's view in the icon's place, the middle of the snapshot cut square with the tile's rounded
|
||||
corners, and refreshes it while that page is on the screen. A tap still opens the camera full screen.
|
||||
|
||||
- **One download per page.** The screen asks ESP Screen Manager for all the live tiles of the page at
|
||||
once (the event `esphome.screen_camera` with `tiles`, the entities in slot order, `size`, the side of
|
||||
the icon's circle, and `bg`, the colour of each tile behind the corners). The app answers with one
|
||||
BMP: a strip of squares, top to bottom in that order, and every tile draws its own square out of it
|
||||
(LVGL's image offset). Six live tiles cost the screen one download of about 50 KB; a tile over the
|
||||
whole page gets one square of 128 px.
|
||||
- **At the pace of the fastest tile.** The page loads its strip every 15 s when any of its tiles says
|
||||
15 s. The app fetches a camera again only when that camera's own pace has passed, so a 30 s camera
|
||||
on a 15 s page is fetched every other load. The strip comes whole every time, never as a 304:
|
||||
ESPHome's `http_request` logs a 304 as a failed request and raises its error flag, which a page of
|
||||
slow cameras would do every 15 s. Nobody loading means nothing fetched, as with the camera full
|
||||
screen.
|
||||
- **After the other pictures.** The strip waits for the alert's picture, a cover on its way and the
|
||||
camera full screen (one picture loads at a time), and does not load under an open card, in standby
|
||||
or under a finger. A page turn, dark mode (other colours behind the corners) or a changed tile drops
|
||||
the strip and asks for a new one.
|
||||
- **A camera without a picture** keeps its icon: the app names it with an empty entry in its answer
|
||||
and paints a plain square of the tile's colour in the strip.
|
||||
- The strip lives in a third `online_image` of the Guition profile (`tile_image`, PSRAM); the CYD has
|
||||
none and the editor does not offer the live picture there.
|
||||
|
||||
## A doorbell
|
||||
|
||||
```yaml
|
||||
@@ -105,11 +133,13 @@ Guition it comes in about 1.8 s (2.8 s with 4 KB).
|
||||
|
||||
## For developers
|
||||
|
||||
- `screen_manager/app/camera_feed.py`: fetching, sizing, links and the port.
|
||||
- `screen_manager/app/camera_feed.py`: fetching, sizing, links and the port; `encode_live` and `CameraFeed.live`
|
||||
make the strip for a page's live tiles (`Manager.answer_live` in `server.py` checks the tiles against the layout).
|
||||
- `components/smart_display/camera_view.h`: when to ask for a link and when to load again
|
||||
(`tests/test_camera_view.cpp`).
|
||||
- `components/smart_display/runtime_tiles.h`: the full-screen view, the alert picture and the
|
||||
`camera` message.
|
||||
- `packages/boards/guition-4848s040.yaml`: the two `online_image` components, the alert frame, and the diagnostic
|
||||
action `preview_camera` (an entity opens it, an empty entity closes it).
|
||||
- `components/smart_display/runtime_tiles.h`: the full-screen view, the alert picture, the live tiles
|
||||
(`live_tick`, `live_place`) and the `camera` message.
|
||||
- `packages/boards/guition-4848s040.yaml`: the three `online_image` components (the camera full screen and the
|
||||
cover, the alert's picture, the live tiles' strip), the alert frame, and the diagnostic action `preview_camera`
|
||||
(an entity opens it, an empty entity closes it).
|
||||
- `tests/test_camera.py`: the app side and the words both sides share.
|
||||
|
||||
@@ -219,6 +219,48 @@ icons sit off-center in the browser).
|
||||
The `MDI_GLYPH_*` substitutions are retired: `TILEn_ICON` in manual
|
||||
profiles must come from the set. No changed preferences or keys.
|
||||
|
||||
### Compatibility 0.2.91 / firmware 0.2.77
|
||||
|
||||
Four things: a live picture on a camera tile, an action behind an alert's button, media texts that roll by, and a
|
||||
full-page tile without a colour of its own. Storage version and preferences unchanged; new tile settings and one new
|
||||
camera view.
|
||||
|
||||
- **Live picture** (`display: live` with `refresh: 15|30` on a `camera.*` or `image.*` tile; `DISPLAYS`,
|
||||
`LIVE_REFRESH`, `LIVE_MIN_FIRMWARE` in `core.py`, `validate_layout` drops `refresh` from any other display). The
|
||||
state message's `o` carries both keys verbatim; firmware before 0.2.77 ignores them (`min_firmware` asks for 0.2.77).
|
||||
The screen sends `esphome.screen_camera` with `tiles` (comma-separated entities in slot order), `size` (the icon
|
||||
circle's side, 24-160) and `bg` (one `RRGGBB` per tile); `Manager.answer_live` refuses a tile that is not a live
|
||||
camera tile of that layout and answers op `camera`, `t: "live"`, `e` the same list with `""` where the app has no
|
||||
picture, `u` a link to a BMP of `size` by `size` times the tiles (`camera_feed.encode_live`, `CameraFeed.live`,
|
||||
`Link.live`). The screen validates `e` with `valid_entity_list` (runtime_model.h, 400 bytes) and matches it to what
|
||||
it asked (`same_list`). The strip is always served whole (200, never 304, whatever `If-None-Match` says): ESPHome's
|
||||
`http_request` logs a 304 as a failed request and raises its error flag (seen on the bench Guition with a radar
|
||||
camera), which a page of slow cameras would do every 15 s; the ETag still goes out, and every picture now carries a
|
||||
`Last-Modified`, because `online_image` warns at each load about either header missing. `camera_view::Feed` got
|
||||
`every` (the pace per feed; the full screen keeps `REFRESH_MS`) and
|
||||
asks again at that pace after an empty answer. The Guition profile has a third `online_image`, `tile_image`, bound
|
||||
as `runtime_tiles::camera_live` with `live_loaded(cached)` / `live_failed()`; `live_tick()` runs from
|
||||
`camera_tick()` after `cover_tick()`. Each tile's square is an `lv_image` in the icon circle's place with
|
||||
`LV_IMAGE_ALIGN_TOP_LEFT` and `offset_y = -n * size` (the default inner alignment centres a taller source, which
|
||||
showed the neighbour's square); the circle hides under it (`live_place`, called wherever `render_slot` and
|
||||
`render_full` place the circle). The strip is released (pictures hidden, `src` cleared first) when the page's wish
|
||||
changes: entities, grounds (dark mode) or size. Loads wait for `alert_image_due()`, a cover or camera on its way,
|
||||
the camera full screen, an open card, standby and a finger. `tests/test_camera.py` (LiveTiles, LiveApp),
|
||||
`tests/test_camera_view.cpp`, `web/tests/components.spec.ts`.
|
||||
- **Alert action** (`action` and `data` in `esp_screens_show_alert`; `ALERT_ACTION_FIELD`, `alert_action` in
|
||||
`core.py`). `show_alert` keeps its seven fields: the app remembers `(key, action, data)` per node of every screen
|
||||
that got the alert (`Manager.alert_actions`), subscribes to `esphome.screen_alert` and queues it with the broadcasts
|
||||
(`alert_loop` → `alert_ended`); `action: ok` performs it once through `HomeAssistant.call` and forgets it on every
|
||||
screen of that alert, any other ending forgets it on that screen, a new alert or a dismissal forgets it too. Works
|
||||
with every firmware from 0.2.31. `tests/test_alert_broadcast.py`; the cheatsheet, the Claude skill and
|
||||
README_EXTENDED document the field.
|
||||
- **Full-page tiles are no longer tinted**: `render_slot` paints every card `theme::surface(t.background)` with
|
||||
`theme::outline` (the `lit` tint of 0.2.62-0.2.76 and `Tile::lights_up()` are gone; `tests/test_state_colours.py`
|
||||
guards it). The editor's mockup never painted the tint, so nothing changes there.
|
||||
- **Media texts roll by**: the title and the artist line of the media card and of the full-page media tile are
|
||||
`LV_LABEL_LONG_SCROLL_CIRCULAR` (`marquee()`, LVGL's default 40 px/s and 300 ms wait; a text that fits stands
|
||||
still). The single and wide tiles keep `LV_LABEL_LONG_DOT` on their one status line.
|
||||
|
||||
### Compatibility 0.2.89 / firmware 0.2.75
|
||||
|
||||
ESPHome 2026.9.0 in the add-on (`screen_manager/Dockerfile`, `requirements.txt`); the packages' `min_version` stays
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
# Test results app 0.2.91 / firmware 0.2.77 (2026-09-20)
|
||||
|
||||
Four asks in one round: a live picture on a camera tile (issue #4, "show a camera preview on the tile as an
|
||||
option"), an action behind the alert's button, media titles that roll by, and full-page tiles without a colour of
|
||||
their own. The live picture is the one with design in it; the rest is small.
|
||||
|
||||
## Live pictures: the design and why
|
||||
|
||||
- **One picture per page, not per tile.** The screen already has two `online_image`s and a rule that one picture
|
||||
loads at a time (a download shares ESPHome's main loop with touch and drawing). Six tiles each loading their own
|
||||
picture would mean six downloads and six buffers. Instead the screen asks for all the live tiles of the page at
|
||||
once and the app serves one BMP: a strip of squares, top to bottom in slot order. Every tile draws its own square
|
||||
out of that one image with LVGL's image offset. A page with six live tiles costs one download of about 50 KB.
|
||||
- **The corners come from the app.** LVGL's image radius (`clip_radius`) rounds the whole source image, not each
|
||||
square of it, and `clip_corner` would draw into a layer (`tests/test_layer_free.py`). So the app bakes the rounded
|
||||
corners into each square over that tile's own colour, as it does for a media cover; the screen sends the colour of
|
||||
every tile with the request (`bg`), so dark mode and pastel tiles come out right.
|
||||
- **A third `online_image`** (`tile_image`) holds the strip: it lives beside a cover or a camera full screen instead
|
||||
of sharing their buffer, and PSRAM has room. Loading still waits its turn: after the alert's picture, a cover or
|
||||
the camera full screen, never under an open card, in standby or under a finger.
|
||||
- **The pace is the tile's.** 15 or 30 s per tile; the page loads at the pace of its fastest tile, and the app fetches
|
||||
a camera again only when that camera's own pace has passed. Nobody loading means nothing fetched.
|
||||
- **The size is the icon's.** The square takes the icon circle's place and size (54 px on a Guition tile, 128 px on a
|
||||
tile over the whole page), so the tile's text does not move.
|
||||
|
||||
## Host harness (Mac, host build of the Guition package, real add-on code)
|
||||
|
||||
`live_host.py` builds the Guition package as a host program with probe actions and drives it over the ESPHome API
|
||||
against a demo home with five cameras (`live_demo_home.py`, the real `Manager.answer_camera` behind `/dev/camera`);
|
||||
git-ignored tooling under `.esphome/readme-render/live/`. 27 checks, all passing:
|
||||
|
||||
- page 1 asks for its three live tiles (two single tiles and a wide one, one of them on a pastel) with size 54 and
|
||||
the three colours; the strip loads and every tile shows its own square (offsets 0, −54, −108), the circle hidden
|
||||
under it, the plain camera tile keeping its icon;
|
||||
- the page loads again after 15 s; the 15 s camera is fetched again while the 30 s camera is not, and after 30 s
|
||||
both are;
|
||||
- the camera full screen pauses the strip (no load for 17 s) and it loads again once closed, the pictures back;
|
||||
- a full-page live tile alone on page 2 asks at 128 px and shows its picture at 128;
|
||||
- a page without live tiles wants nothing and holds no picture; a media tile over the whole page still asks for its
|
||||
cover; a camera without a picture keeps its icon (the app answers with an empty entry and no link);
|
||||
- back on page 1 the strip is asked for again; a card over the page pauses the loads and closing it resumes them;
|
||||
dark mode asks again with the dark grounds (`1A1A1A,4A2422,1A1A1A`) and shows the dark strip.
|
||||
|
||||
Found on the host, fixed before the bench: LVGL's default inner alignment centres a source that is taller than its
|
||||
object, so every tile showed the square of its neighbour (and the corners of the wrong colour); the picture now sets
|
||||
`LV_IMAGE_ALIGN_TOP_LEFT`. The host's `http_request` fails a 304 outright where the ESP32's `online_image` takes it as
|
||||
"unchanged"; the harness counts both as a load.
|
||||
|
||||
The rolling title was checked the same way: two renders of a full-page media tile 1.5 s apart differ only in the rows
|
||||
of the title and the artist line.
|
||||
|
||||
## Bench Guition (192.168.146.136, firmware 0.2.77 from this tree over OTA, local add-on 0.2.91 on the Yellow)
|
||||
|
||||
- `camera.buienradar` live on page 1: the screen asked for the strip at once, the radar showed as a rounded square
|
||||
in the icon's place on the dark tile (`capture_ui.py`), and every 15 s the screen loaded again. The radar changes
|
||||
every five minutes, so the app answered 304 in between, and ESPHome's `http_request` logged every one of those as
|
||||
`HTTP Request failed; Code: 304` and raised its error flag (`online_image` then said "Download skipped"). The app
|
||||
now serves a live strip whole every time, never a 304 (about 9 KB for one tile, 50 KB for six, on the LAN), and
|
||||
without the ETag `online_image` warned "No header with name etag found" and "... last-modified ..." at every load,
|
||||
so every picture now carries both headers. No "took a long time" warning during the loads.
|
||||
- The alert with `action: persistent_notification.create` reached both bench screens; the button's report
|
||||
(`esphome.screen_alert`, `action: ok`, sent the way the screen sends it) made the notification once, and the add-on
|
||||
logged `Alert button on guition-wallbox: persistent_notification.create performed`.
|
||||
|
||||
## Builds
|
||||
|
||||
`tools/check.sh`: Python 516 tests, C++ tests, packages, icons, translations (9 languages, 1431 texts), editor tests
|
||||
(106), types and build. `tools/check.sh --firmware` with ESPHome 2026.9.0: CYD 1,633,728 B, 89.0 % of the update slot
|
||||
(832 B more than 0.2.90); Guition 2,058,368 B.
|
||||
Reference in New Issue
Block a user