Take what a tile can do, its tap actions, words and icons from Home Assistant (0.2.67)
GitHub issue #7 asked for cover.toggle on tap. ESP Screens now asks Home Assistant which actions each entity has instead of keeping lists: the editor offers On / off (covers included), sliders, controls and displays only where Home Assistant has the action, and refuses only new unsupported settings. Perform action runs any action Home Assistant offers for the tile's entity, under its own names and fields; the screen sends it with a call id and says Refused when Home Assistant refuses. Sensors round by display precision, and tiles, the top bar, timelines, vacuum chips and the inspector use Home Assistant's words where they showed raw states. Tiles show Home Assistant's icons, picked as its frontend does (the fonts grow to 309 glyphs). Existing screens keep every setting and tap as before: stored layouts load leniently, legacy taps route the same (1020 combinations), and messages are byte-identical without Home Assistant's words and icons. Firmware 0.2.58. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+6
-1
@@ -140,7 +140,12 @@ Click **Save & send to screen** to send your changes.
|
||||
- Light, switch, input_boolean, and fan: tap to turn on/off.
|
||||
- Long press a light: brightness, rainbow color, and white temperature, as far as
|
||||
the light supports those features.
|
||||
- Climate, vacuum, and cover: tap to open the control card.
|
||||
- Climate, vacuum, and cover: tap to open the control card. Under **On tap**, choose **On / off**
|
||||
to open, close, or stop a cover with a tap instead (firmware 0.2.58+); holding it still opens the card.
|
||||
ESP Screens offers **On / off**, a small slider, and direct controls only when Home Assistant has
|
||||
the action for that entity. **Perform action** runs any action Home Assistant offers for the
|
||||
entity, such as **Set cover position** with a position, under Home Assistant's own names
|
||||
(firmware 0.2.58+).
|
||||
- Long press a fan: speed, if the device supports percentages.
|
||||
- Scene/script: tap to run; button/input_button: tap to press.
|
||||
- Sensor, number, binary sensor, and person: tap for the history card, for 1 hour,
|
||||
|
||||
@@ -176,6 +176,125 @@ icons sit off-center in the browser); run `generate_packages.py` afterward.
|
||||
The `MDI_GLYPH_*` substitutions are retired: `TILEn_ICON` in manual
|
||||
profiles must come from the set. No changed preferences or keys.
|
||||
|
||||
### Compatibility 0.2.67 / firmware 0.2.58
|
||||
|
||||
App (new `ha_catalogue.py`, `core.py`, `server.py`, `header_bar.py`, `history_card.py`, `tile_icons.py`, the editor and
|
||||
the Claude skill), `runtime_model.h`, `tile_controls.h`, `runtime_tiles.h` and `text.py`; the app raises
|
||||
`FIRMWARE_VERSION` and both profiles' icon fonts grow. The storage version and the tile protocol stay 1. A tile gains
|
||||
the tap choice `action` with the option `action`; its state message gains the options `act` and `x.w`, and `o.icon` now
|
||||
carries most tiles' icon. Without Home Assistant's answers everything behaves as before.
|
||||
|
||||
Capabilities (what the editor offers):
|
||||
|
||||
- What the editor offers per entity comes from Home Assistant. `HomeAssistant.fetch_services` keeps the whole
|
||||
`get_services` answer (it kept only `esphome`), and every `service_registered`/`service_removed` refreshes it after
|
||||
the usual second; only an `esphome` one still wakes the sync loop. `HomeAssistant.entity_actions` asks
|
||||
`get_services_for_target` per entity (Home Assistant 2025.12+, core PR 157334) and keeps the answer until the action
|
||||
list, the registry or the entity's `supported_features`/`device_class` change. A Home Assistant that answers "Unknown
|
||||
command" is remembered, and `ha_catalogue.local_actions` evaluates the `target.entity` filters of the descriptions
|
||||
instead: every condition of a filter must hold, a `supported_features` entry is a mask the entity must support
|
||||
completely, any entry will do. On Max's Home Assistant 2026.9.2 both answers were identical for 30 of 30 entities.
|
||||
- `ha_catalogue.capabilities` turns the action list into what the editor may offer: `toggle` (`<domain>.toggle`),
|
||||
`inline` and `controls` (the Home Assistant action each of our widgets sends, `INLINE`/`CONTROLS`, with a field that
|
||||
must pass its `filter`: a light's small slider needs `light.turn_on` with `brightness_pct`), and `displays` (graph for
|
||||
a sensor `history_card.kind` draws as a line, forecast for weather with the daily bit or no features yet). `GET
|
||||
/api/capabilities?entity=...` returns it for up to 40 entities, null when unknown (no action list, no state).
|
||||
- `Manager.check_supported` runs before `Manager.save` for the editor's PUT and for tile events. It refuses a tap,
|
||||
slider, control or display Home Assistant doesn't support only when that setting is new or changed for the tile; what
|
||||
a tile already has keeps saving, and nothing is refused while the capabilities are unknown.
|
||||
- `validate_layout` no longer limits `tap: toggle` to six domains (only `screen.*` has none); `check_supported` takes
|
||||
that place. `validate_layout(data, stored=True)` loads the app's own data leniently: a tile whose options fail
|
||||
validation (a newer app's setting after a downgrade) keeps them as stored instead of stopping the app. The editor and
|
||||
tile events still validate strictly.
|
||||
- Firmware: `tile_controls::tap_route` decides what a tap or hold does and `runtime_tiles::event` carries it out. `tap
|
||||
== "toggle"` on a short tap sends `<domain>.toggle` for every domain before the domain's own card; before, the 13
|
||||
runtime-card domains opened their card first, so a cover could not toggle. `tests/test_tile_controls.cpp` transcribes
|
||||
`event()` of firmware 0.2.56 and checks 800 combinations (22 domains x 4 tap choices x 5 states x hold): every one
|
||||
routes as before, including `busy`; only a short tap with `toggle` on the 16 domains that could not have it changes.
|
||||
- Firmware before 0.2.58 opens the card for `toggle` on those domains; the editor says so under On tap and keeps the
|
||||
choice. The editor keeps showing a stored choice that Home Assistant no longer supports, with a warning, and hides it
|
||||
otherwise; a tile that becomes wide gets the first supported direct control when the domain's default isn't there.
|
||||
Hints under a field sit beside the label (`withHint`): a click inside a `<label>` pressed its first button.
|
||||
- `renderResults` skips `tile: false` entities (the top bar's extra domains), and `input_button` joins the `domains`
|
||||
table and the Actions filter.
|
||||
- `Tile::available()` counts `unknown` as available for `scene`, `button` and `input_button`: their state is the moment
|
||||
they last ran, and Home Assistant's button row disables only an `unavailable` one. Since the first runtime tiles such
|
||||
a tile said Unavailable and ignored taps until it had run once from Home Assistant; it now says Never run.
|
||||
|
||||
Perform action:
|
||||
|
||||
- Stored: `options.tap = "action"` with `options.action = {"action": "domain.action", "data": {...}}`.
|
||||
`core.validate_tap_action` takes an action name of any integration, at most 8 fields, no target keys (`entity_id`,
|
||||
`device_id`, `area_id`, `floor_id`, `label_id`: the target is the tile's entity), JSON values without NaN, each at
|
||||
most 400 bytes on the wire and 800 bytes together. `validate_layout` drops `action` when the tap is anything else and
|
||||
refuses it on `screen.*`. App 0.2.67 loads such a layout leniently; 0.2.66 and older stop on it (a downgrade only).
|
||||
- On the wire `screen_options` sends `o.act = {"s": action, "d": [[key, text]], "t": [[key, template]]}` and never the
|
||||
stored `action`. Text goes as ESPHome action data; every other value as `{{ "<json>" | from_json }}`, which Home
|
||||
Assistant's ESPHome integration renders with `render_complex` back into a number, a boolean, a list or an object
|
||||
(ESPHome's action data is text only).
|
||||
- The list: `HomeAssistant.fetch_services` also reads `frontend/get_translations` (English, `services`) into
|
||||
`service_names`; `get_services` has carried only services.yaml's legacy text since 2025-10-24. `GET
|
||||
/api/entity-actions?entity=` answers `ha_catalogue.action_choices`: the actions of `entity_actions`, the entity's
|
||||
domain first, then its integration, then the rest, each with Home Assistant's name and description and the fields
|
||||
whose `filter` fits the entity (sections flattened). An action that must return data (`response.optional` false) is
|
||||
left out. A `state` selector gets the entity's values for that attribute (`<attribute>_list`, `<attribute>s`,
|
||||
`available_<attribute>s`, `supported_<attribute>s`), so a Sonos source is a choice.
|
||||
- `Manager.check_supported` refuses a new or changed action that Home Assistant doesn't offer for the entity, that only
|
||||
returns data, that sets a field Home Assistant doesn't have for it, or that leaves a required field empty. A saved,
|
||||
unchanged action keeps saving. Tile events take `action` and `data` (`tap` follows unless given); the layout sensor
|
||||
carries `tap` and `action`.
|
||||
- Firmware: `receive` parses `o.act` into `Extra::action`, `action_data` and `action_templates` (a valid action name, at
|
||||
most 8 pairs, keys up to 32 and values up to 400 bytes), so only a tile with an action holds them.
|
||||
`tile_controls::tap_route` returns `CUSTOM` for a short tap with `tap == "action"` and an action; without one it taps
|
||||
automatically, as older firmware does with the unknown value (the legacy test now routes 1020 combinations). Holding
|
||||
still opens the card. `runtime_tiles::perform` sends `entity_id` plus the data, and the templates as `data_template`.
|
||||
- Answers: `text.py` defines `USE_API_HOMEASSISTANT_ACTION_RESPONSES`, which ESPHome otherwise sets only for a YAML
|
||||
`homeassistant.action` with `on_success`/`on_error`. A tap's action (the tile's own, On / off, the automatic taps from
|
||||
`event()`, not the sliders and keys) gets a call id through `watch_call`, at most four at a time. A refusal sets
|
||||
`Tile::refused_at`: the tile says Refused for four seconds and stops waiting. A success changes nothing: the tile
|
||||
waits for the new state as before. ESPHome keeps a callback until its answer arrives and has no timeout, and Home
|
||||
Assistant never answers when the device may not perform actions or is older than 2025.10, so `expire_calls` ends a
|
||||
call after eight seconds through `handle_action_response(id, false, "no answer")`, which shows nothing.
|
||||
|
||||
Numbers, words and icons:
|
||||
|
||||
- `core.rounded_state` rounds a sensor's state in `state_message` by the entity registry's display precision
|
||||
(`header_bar.precision_of`: `display_precision`, else `suggested_display_precision`), half up like the frontend,
|
||||
without thousands separators because the firmware parses the number, and "-0.0" as "0.0". No precision keeps the state
|
||||
as it is, as Home Assistant does. Numbers, climate and other domains are unchanged.
|
||||
- `HomeAssistant.fetch_services` also reads `frontend/get_translations` (English) for `entity_component` (about 63 KB on
|
||||
Max's installation) and `entity` (about 215 KB) into `state_words`, on connect and when actions register.
|
||||
`core.state_word` picks a word as the frontend's `computeStateDisplay` does: the integration's word for the entity's
|
||||
translation key (`component.<platform>.entity.<domain>.<key>.state.<state>`), then the domain's word for the state's
|
||||
device class, then the domain's word; `core.attribute_word` does the same for
|
||||
`state_attributes.<attribute>.state.<value>` (`computeAttributeValueToParts`). `ha_catalogue.screen_word` sends a word
|
||||
as `x.w` only for cover, media player, vacuum, select, input select and non-numeric sensors, folded to the tile fonts'
|
||||
glyphs (`header_bar.clean_text`), at most 32 bytes, and only when it differs from the state.
|
||||
- The same words, add-on only (any firmware): `header_bar.value` for a select, input select or input text and for a
|
||||
state without a word in `STATES` (which stays: Returning, Auto, Up); `history_card.state_label` for timeline legends
|
||||
and heading words, after `STATES`; `ha_catalogue.chip_words` for a vacuum card's `l` labels of a mode or water select
|
||||
option and of a fan speed (`attribute_word` `fan_speed`) that `VACUUM_LABELS` lacks; the inspector's `word`. Without
|
||||
translations every message is as before.
|
||||
- Firmware keeps `x.w` in `Extra::state_word` (heap only for such tiles). The tile value uses it after the screen's own
|
||||
words (Unavailable, a light's brightness, a climate's setpoint, person, sun, timer, scene, script, button, binary
|
||||
sensor, On, Off, Cleaning, Docked) and before the unit; `detail_state` after the vacuum words and Unavailable. Wide
|
||||
cover and media tiles keep `tile_controls::status_text`, and the cover card its own status line.
|
||||
- Binary sensors keep firmware 0.2.53's words (Motion / No motion where Home Assistant says Detected / Clear) until Max
|
||||
decides. Older firmware ignores `x.w`.
|
||||
- Icons: `tile_icons.HA_DEFAULTS` adds the 125 icons the fonts lacked that Home Assistant 2026.9 shows for the tile and
|
||||
top bar domains: every default, state and range icon of `frontend/get_icons` (`entity_component`) and those its
|
||||
frontend picks in code (`stateIcon`: a tracker on a router or Bluetooth). `circle` and `radiobox-blank` are not in
|
||||
this repo's MDI font. `tools/generate_icons.py` puts them in both profiles' three icon fonts and the editor font (309
|
||||
glyphs); they are not pickable. `HomeAssistant.fetch_services` reads `frontend/get_icons` (`entity_component`,
|
||||
`entity`) into `tile_icons.use_ha_icons`. `tile_icons.ha_default_icon` follows the frontend's `getEntityIcon`
|
||||
(src/data/icons.ts): the integration's icon for the translation key, then `stateIcon`, then the domain's icon for the
|
||||
state's device class or else `_`; within one, the state's icon, then a range step for a number (`Number()`, the
|
||||
highest step not above it), then the default. `default_glyph` returns a codepoint only for a glyph the fonts carry,
|
||||
never for weather, sun or `screen.*`. `core.tile_icon` uses it after a chosen icon and the entity's own `icon`
|
||||
attribute, so `o.icon` now carries most tiles' icon; `header_bar.auto_icon` and the editor's entity list (`discover`)
|
||||
use the same before their tables. Firmware before 0.2.58 drops a codepoint its fonts lack (`has_icon_glyph`) and shows
|
||||
its own default. Without icon resources (a Home Assistant before 2024.2, a refused request) everything is as before.
|
||||
|
||||
### Compatibility 0.2.66 / firmware 0.2.57
|
||||
|
||||
Camera images on the Guition (docs/CAMERA.md). Storage, keys, preferences and the settings block are unchanged; the
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
# Test results app 0.2.67 / firmware 0.2.58 (2026-09-17)
|
||||
|
||||
GitHub issue #7 asked for a specific action on tap, such as `cover.toggle` instead of the cover card. Max wanted the
|
||||
answer taken from Home Assistant rather than from lists in ESP Screens, the same for names, words and icons, and
|
||||
existing screens untouched. This release offers what Home Assistant says each entity can do (On / off for covers among
|
||||
it), lets a tap perform any action Home Assistant offers under its own names, and shows Home Assistant's numbers, words
|
||||
and icons. See CHANGELOG 0.2.67 and the compatibility note in docs/RELEASING.md. Built on 0.2.66 (`d60a0f1`).
|
||||
|
||||
## Home Assistant, read first
|
||||
|
||||
- Home Assistant core: `cover.toggle` needs OPEN+CLOSE and stops a moving cover; `media_player.toggle` needs
|
||||
TURN_ON+TURN_OFF; `climate.toggle` either. `get_services_for_target` exists since 2025.12 (PR 157334). `get_services`
|
||||
has carried only untranslated names since 2025-10-24; the names come from `frontend/get_translations`.
|
||||
- Home Assistant frontend: the tile card's tap defaults to more-info and hides Toggle where `canToggleState` says no;
|
||||
the button row disables a button only when it is `unavailable`, not `unknown`.
|
||||
- Frontend `src/common/entity/compute_state_display.ts` and `compute_attribute_display.ts`: a state's word is the
|
||||
integration's for the translation key, then the domain's for the state's device class, then the domain's, else the raw
|
||||
state; an attribute value's (a robot's fan speed) the same under `state_attributes.<attribute>`.
|
||||
- Frontend `src/data/icons.ts` (`getEntityIcon`) and `src/common/entity/state_icon.ts`: the entity's own icon first (the
|
||||
registry's, which Home Assistant also writes into the state's `icon`), then the integration's icon for the translation
|
||||
key, then the icons the frontend picks in code (a tracker on a router or Bluetooth, an input_datetime with only a date
|
||||
or a time, an update, the sun), then the domain's icon for the state's device class, else `_`. Within one entry: the
|
||||
state's icon, then for a number the highest `range` step not above it (below the lowest step the default), then the
|
||||
default. Home Assistant 2026.9.2 has range icons for two sensor classes: battery (a step every 10 %) and wind
|
||||
direction.
|
||||
- Max's dashboard (read only, nothing saved): Tap behaviour, Icon tap behaviour and Add interaction (hold, double tap).
|
||||
- Max's Home Assistant 2026.9.2 (read only): `media_player.sonos_badkamer` has `supported_features` 8321599, without
|
||||
TURN_ON or TURN_OFF, while ESP Screens offered On / off for every media player.
|
||||
|
||||
## Automated
|
||||
|
||||
- Python (`.venv-portal`): 377 tests OK (337 on 0.2.66).
|
||||
- New `tests/test_ha_capabilities.py` (12): target filters and field filters on real action descriptions, what the
|
||||
editor offers per entity, refusing only new settings, lenient loading of a newer app's setting, the per-entity cache
|
||||
and its invalidation, the fallback for a Home Assistant that answers "Unknown command", tile events, and `GET
|
||||
/api/capabilities`. `test_extended` and `test_cover_card` follow the new rules.
|
||||
- New `tests/test_tap_actions.py` (12): what a stored action may hold (names of any integration, field limits, no
|
||||
target keys, no NaN), dropping a stale action, the wire form (text as data, numbers, booleans and lists as
|
||||
`from_json` templates that decode back to the value), tile events and the layout sensor, Home Assistant's names and
|
||||
per-entity fields in the list (a cover without SPEED gets no speed field), the values a `state` selector offers (a
|
||||
Sonos source list), leaving out actions that only return data, what a save refuses (not offered, a missing required
|
||||
field, an unknown field, data-only actions) and what it keeps (a saved action Home Assistant dropped later), the
|
||||
translations fetch and its fallback, Claude's tile event, and `GET /api/entity-actions`.
|
||||
- New `tests/test_state_words.py` (9): rounding by display precision (half up, no thousands separator, "-0.0",
|
||||
non-numbers and missing precisions unchanged, sensors only), Home Assistant's word picked as its frontend does with
|
||||
real entries of Home Assistant 2026.9.2, words only where the screen showed the raw state and never for numbers or
|
||||
binary sensors, the tile message carrying the rounded value and `x.w`, the top bar and its editor preview ("Vacuum
|
||||
and mop", while Returning, Auto and Motion stay), a history timeline's legend and heading words, a vacuum card's
|
||||
chips ("Off (raised brush)", while Normal stays, values unchanged), and everything as before without translations.
|
||||
- New `tests/test_ha_icons.py` (7): the frontend's order with real entries (a closed blind, a playing speaker, an open
|
||||
door, an integration's icon first, the device class from the state), batteries and wind directions by their range
|
||||
steps (45 % `battery-40`, 5 % `battery-alert`, -1 and `unavailable` `battery-unknown`, 2.1e2 degrees
|
||||
`arrow-top-right`), the icons the frontend picks in code, only glyphs the fonts carry reaching the screen (none for
|
||||
weather, sun and screen tiles), every default, state and range icon of those entries in the fonts, the tile, the top
|
||||
bar and the editor list showing the same icon, and everything as before without Home Assistant's icons.
|
||||
- C++ (`clang++ -std=c++17 -Wall -Wextra -Werror -I.`): 17/17 PASS. `test_tile_controls` transcribes `event()` of
|
||||
firmware 0.2.56 and routes 1020 combinations (22 domains x auto/detail/toggle/none/action x 5 states x tap/hold, and
|
||||
`action` without an action) through the new `tap_route`: every one the same, `busy` included; only a short tap with
|
||||
`toggle` on the 16 domains that could not have it now sends `<domain>.toggle`, and a tile with an action gets
|
||||
`CUSTOM`. `valid_action` takes names of any integration. `test_runtime_model`: a scene, button or input button that
|
||||
never ran is available; an unknown light is not.
|
||||
- `generate_icons.py --check` (150 pickable icons, 309 glyphs) and `generate_packages.py --check` green.
|
||||
|
||||
## Existing screens stay as they are
|
||||
|
||||
- `local_actions` against Home Assistant's own `get_services_for_target` on Max's installation: identical action lists
|
||||
for 30 of 30 entities (covers, media players, lights, climate, scripts, scenes, buttons, numbers, selects, a timer).
|
||||
- Four stored layouts (two production screens saved from the bench, the demo's two screens) load the same with the old
|
||||
`validate_layout`, the new one and the new one with `stored=True`, and all 49 tile messages encode byte for byte the
|
||||
same as with `core.py` of 0.2.65 and of 0.2.66 when Home Assistant gives no words or icons.
|
||||
|
||||
## Firmware on the Mac (host builds, driven over the ESPHome API)
|
||||
|
||||
`tap_host.py` sends a layout to host builds of both packages (own device names, API ports 6167 and 6168), with every tap
|
||||
choice in the state messages themselves, taps and holds tiles like a finger does, and captures the Home Assistant
|
||||
actions the screen sends. The test client answers the screen's calls like Home Assistant does
|
||||
(`send_homeassistant_action_response`). **Guition 26/26, CYD 26/26**, on builds with the final fonts.
|
||||
|
||||
| Check | Guition | CYD |
|
||||
|---|---|---|
|
||||
| Tap on a garage door with On / off: `cover.toggle` with its `entity_id`, no card | pass | pass |
|
||||
| Hold that garage door: its card opens, nothing is sent | pass | pass |
|
||||
| Tap on a cover without On / off: its card opens, nothing is sent | pass | pass |
|
||||
| Tap on a lamp, a switch: `light.toggle`, `switch.toggle` | pass | pass |
|
||||
| Tap on a running timer, a scene: `timer.pause`, `scene.turn_on` | pass | pass |
|
||||
| Tap on an input button that never ran (`unknown`): `input_button.press` (before: ignored, "Unavailable") | pass | pass |
|
||||
| A saved On / off on a speaker: still `media_player.toggle` | pass | pass |
|
||||
| Tap on a sensor: its card opens, nothing is sent | pass | pass |
|
||||
| Tap on the skylight set to Set cover position 50: `cover.set_cover_position`, `entity_id` in data, `position: {{ "50" \| from_json }}` in data_template, a call id, no card | pass | pass |
|
||||
| Home Assistant refuses: the tile says Refused, and its state again after four seconds | pass | pass |
|
||||
| Holding the skylight opens its card and sends nothing | pass | pass |
|
||||
| Home Assistant succeeds: the tile keeps waiting for the state, no Refused | pass | pass |
|
||||
| No answer: the call is watched, and let go after eight seconds without Refused | pass | pass |
|
||||
| A status sensor with `x.w` shows "Rinsing"; without a word its state as before ("spinning"); a cover that opens "Opening" | pass | pass |
|
||||
| No errors in the log | pass | pass |
|
||||
|
||||
## ESP Screens
|
||||
|
||||
The real add-on from this tree on a demo home whose fake Home Assistant answers from Max's real action descriptions,
|
||||
English action names, translations and icon resources, in the browser pane:
|
||||
|
||||
- Opening the kitchen screen asks `GET /api/capabilities` once for its 15 tiles (200).
|
||||
- Sonos with a saved On / off: the choice stays, with the warning "Home Assistant can't turn this on and off, so a tap
|
||||
does nothing. Choose another option." Choosing Automatic removes On / off and the warning; saving: PUT 200.
|
||||
- TV (on and off): On / off offered. Garage door: On / off offered, no small slider; choosing On / off on this screen's
|
||||
firmware 0.2.33 shows "The screen switches this from firmware 0.2.58: press Update on the screen. Until then a tap
|
||||
opens its card."
|
||||
- Skylight (position only): no On / off, a small slider; made double-width it takes Position slider, and the direct
|
||||
control offers only Position slider and None.
|
||||
- Cooker hood light with a saved small slider, washing machine status with a saved graph: both kept, with a warning.
|
||||
Clicking the warning text changes nothing (clicking the old hint inside a label pressed the first choice: reproduced
|
||||
with the old markup).
|
||||
- The skylight, On tap → Perform action: the list shows Set cover position and Home Assistant's general actions, each
|
||||
with its id and description; open, close and toggle are not there because the skylight lacks them. The screen's old
|
||||
firmware adds "The screen performs an action from firmware 0.2.58: press Update on the screen. Until then a tap works
|
||||
as Automatic."
|
||||
- Choosing Set cover position shows Position (%) with "Target position." and "Home Assistant needs Position." until 50
|
||||
is typed. Saving: PUT 200, and the skylight's state message carries
|
||||
`{"tap":"action","act":{"s":"cover.set_cover_position","t":[["position","{{ \"50\" | from_json }}"]]}}`.
|
||||
- The living room's Sonos: searching "source" leaves Select media player source; its Source field offers the speaker's
|
||||
own sources (Not set, TV, NPO Radio 2, Qmusic) and "Home Assistant needs Source." until one is chosen. The state
|
||||
message then carries `"act":{"s":"media_player.select_source","d":[["source","Qmusic"]]}`.
|
||||
- The ceiling light, Turn on light: Color is a colour picker, Color temperature and Brightness are numbers, Color name a
|
||||
list, the object fields text with Home Assistant's examples; Transition, Effect and Flash are not offered because the
|
||||
light lacks those features. Orange at 80 % sends `"t":[["rgb_color","{{ \"[255,136,0]\" | from_json
|
||||
}}"],["brightness_pct","{{ \"80\" | from_json }}"]]`. Every field has Home Assistant's field name as its accessible
|
||||
name.
|
||||
- `GET /api/inventory` (with a phone battery and tracker added) gives the battery at 64 % `battery-60`, the phone
|
||||
tracked by the router `lan-connect`, the playing Sonos `speaker-play`, the TV that is off `television-off`, the closed
|
||||
garage door `garage`, the skylight `window-open`, the cooker hood light that is off `lightbulb-off`, the living room
|
||||
climate `thermostat`, the washing machine status Home Assistant's `eye`, and no icon for the weather, which the screen
|
||||
draws. The kitchen screen's mockup draws the same icons on its tiles.
|
||||
- Inspector → Read current data: every tile's status in Home Assistant's words (Partly cloudy, Active, On, Playing,
|
||||
Home, Off, Closed, Open); numbers, a scene's time and states without a word (the demo washing machine's rinsing, an
|
||||
input button's unknown) as they come.
|
||||
- The entity list: "front door" finds the door sensor but no longer the lock; the input button has the Action badge and
|
||||
shows under Actions. Saving the changed kitchen screen: PUT 200, "Saved. Your screen is being updated."
|
||||
- No console errors apart from the live update stream that dropped while the demo server restarted.
|
||||
|
||||
## Real Home Assistant, read only
|
||||
|
||||
The app's own `HomeAssistant` class and lookups against Max's Home Assistant 2026.9.2:
|
||||
|
||||
- 79 action domains and 1571 action names; `get_services_for_target` answered, eight entities in 30 ms from the Mac and
|
||||
0.2 ms from the cache. Sonos: no On / off, volume and playback controls. Curtains: On / off, buttons and position.
|
||||
Cooker hood light (on/off only): On / off, no small slider.
|
||||
- Perform action: Curtains list Close cover, Open cover, Set cover position (Position, required), Stop cover, Toggle
|
||||
cover, then the general actions. Sonos Badkamer: 29 actions, its media player actions first, Select media player
|
||||
source among them with Source as a choice of its own stations. Bathroom light: Toggle light, Turn off light and Turn
|
||||
on light with Transition, Color, Color temperature, Brightness, Effect and more for its colour modes.
|
||||
- Words: of 743 entities a tile or the top bar can show, 11 read differently in the top bar, all as Home Assistant shows
|
||||
them: a washing machine's "Stop" is "Stopped", an Oral-B brushing mode "Daily_clean" is "Daily clean", a Voice
|
||||
satellite's "no_wake_word" is "No wake word", a select's "0" is "Off". The Roborock S8's chips stay as they were:
|
||||
every option it offers has a short label of the screen's own.
|
||||
- Icons: of the same 743 entities, 458 now get Home Assistant's icon on the screen, where they had the screen's own
|
||||
before. 52 keep their own icon and 3 are drawn by the screen (weather, sun). The other 230 keep the screen's icon as
|
||||
before: 154 whose own icon the fonts lack, and 76 whose integration's icon they lack (Sonos, Roborock, WLED, Oral-B,
|
||||
EZVIZ and others). All 29 battery sensors follow their level: 35 % `battery-30`, 55 % `battery-50`, 100 % `battery`,
|
||||
unavailable `battery-unknown`.
|
||||
|
||||
## Builds
|
||||
|
||||
Check profiles with the generated packages and local components, ESPHome 2026.6.2 (the app's own); no errors or compiler
|
||||
warnings.
|
||||
|
||||
| Profile | RAM | Flash | vs 0.2.66 |
|
||||
|---|---|---|---|
|
||||
| CYD | 23.9% (78,284 B) | 79.1% (1,452,291 B) | +344 B RAM, +28,476 B flash |
|
||||
| Guition | 25.6% (83,860 B) | 21.0% (1,707,603 B) | +344 B RAM, +42,688 B flash |
|
||||
|
||||
The RAM is the action answers (a watch list of four calls) and the words; the icons cost about 25 KB (CYD) and 39 KB
|
||||
(Guition) of flash, and the CYD keeps 383 KB free in its app partition.
|
||||
|
||||
ESPHome 2026.8.1 (what Device Builder installs now) builds both profiles too: CYD flash 79.6% (1,461,375 B), Guition
|
||||
21.2% (1,720,695 B). Its newer compiler warns about `JsonVariant` loops and `%d` with `int32_t`, all in code 0.2.66
|
||||
already had.
|
||||
|
||||
## Not tested
|
||||
|
||||
- Physical screens: not flashed (another session was working on the bench screens). A real tap on a cover with On / off,
|
||||
a real Perform action and refusal, and the new icons on the panels themselves are Max's check after the update.
|
||||
- The page in Home Assistant's Ingress frame, and the app on the Yellow (the capability lookups there are slower than
|
||||
from the Mac).
|
||||
Reference in New Issue
Block a user