Free memory on the CYD and drop the old manual profile (0.2.50)

The CYD restarted under load: a slider fill rounded less than its track made
LVGL draw the fill into a buffer of its own size on every redraw (15-20 KB), and
when that allocation failed the refresh retried until the task watchdog fired.
Track and fill now share one radius, and tests/test_layer_free.py keeps every
layer-making style out of the profiles, the packages and the firmware headers.

A tile keeps only the fields every card uses; climate modes, select options,
weather, sun and timer times, the media title and the vacuum rows moved to an
Extra block that exists only while a state needs one, and the state copy became
a fingerprint. runtime_tiles::model went from 24,296 to 8,216 bytes.

The manual profile that bound tiles to fixed entities in the YAML is gone:
331 TILE* substitutions, DYNAMIC_TILES/TILE_COUNT/DIRECT_ACTIONS, the 80 Home
Assistant subscriptions, its tap handlers and scripts, its own vacuum card, its
guides and helper scripts, and the five stale header copies in the repository
root that two C++ tests were compiling instead of the components. esphome config
of both Easy profiles is unchanged by that cleanup.

tile_scroll and the wake overlay no longer light up on a tap, and the debug
sensor min_free reports the lowest free heap since boot. On the bench CYD static
RAM went from 32.0% to 22.8% and free heap from 64-77 KB to about 101 KB, with
78 KB as the lowest point over thirteen hours without a restart.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Max Gramser
2026-09-16 08:06:41 +02:00
parent 79a84a4c77
commit 08197c4ae1
45 changed files with 854 additions and 12896 deletions
-98
View File
@@ -1,98 +0,0 @@
# Acceptance test and handover
Note the date, board variant/MAC, Git commit, ESPHome version, device name, and the
names of the two measurement files. Don't include passwords in the report.
## Without real HA actions
1. Calibrate using [CALIBRATING.md](CALIBRATING.md); flash the result and run a
new, independent measurement with `verify`. A successful fit alone
doesn't prove the firmware coordinates are correct.
2. Flash normal mode. Check that the measurement screen disappears.
3. Check every visible tile and its edges: no other tile should respond.
Tap calmly and rapidly in succession, but expect no repeat within the
deliberate debounce period. A swipe should not trigger a tile action afterward.
4. With 1–6 tiles: no page button. With 7–10: repeat at least twenty times:
Next → tile → Previous. The bottom tile should not respond to the
page button. Open/close overlays; a tap inside one should not leak through.
5. Run the built-in render test via the encrypted API:
```sh
python diagnostics/run_ui_test.py --host display-kitchen.local --name display-kitchen
```
Requires ten successful page checks, fifty overlay cycles, and progress
from real draw callbacks. This doesn't test physical touch or HA actions.
6. Leave the board on for at least 15 minutes. Check that it doesn't restart,
that standby only starts after ten minutes without touch, and that the first
tap wakes the screen without toggling a device.
## With Home Assistant
Only now enable direct actions, reflash, and choose safe test devices.
Check every configured tile with its real HA entity:
- A tap performs exactly one intended action; the feedback is correct.
- Changes from HA also appear on the screen.
- Light slider/color, climate setpoint, and supported modes work where used.
- Vacuum actions and speeds work where supported. Note any missing functionality.
- After a power interruption, Wi-Fi and HA come back; name, calibration, and tiles persist.
- After a brief Wi-Fi/HA interruption, the connection recovers without a USB flash.
Keep logs local only. Check for resets, watchdog messages, repeated
connection errors, and noticeably slow components. A short render test doesn't
prove stability over days; note the duration actually observed.
## Automated development checks
From the repo, with the Python environment active:
```sh
python -m unittest discover -s tests -p 'test_*.py'
c++ -std=c++17 -Wall -Wextra -pedantic tests/test_cyd_ui.cpp -o /tmp/test_cyd_ui
/tmp/test_cyd_ui
c++ -std=c++17 -Wall -Wextra -pedantic tests/test_touch_filter.cpp -o /tmp/test_touch_filter
c++ -std=c++17 -Wall -Wextra -pedantic tests/test_light_controls.cpp -o /tmp/test_light_controls
/tmp/test_light_controls
/tmp/test_touch_filter
c++ -std=c++17 -Wall -Wextra -pedantic tests/test_light_controls.cpp -o /tmp/test_light_controls
/tmp/test_light_controls
python -m esphome config device.yaml
python -m esphome compile device.yaml
```
The C++ commands above are for macOS/Linux with a compiler. On Windows,
the developer can use whatever C++17 toolchain is available. Only flash the
checked profile to the identified board.
## Handover report
```text
Board / MAC:
Git commit / ESPHome version:
Device name / HA entities:
Calibration measurement + independent verification:
Render test:
Physical pagination/touch/standby:
Real HA actions:
Observed stable duration:
Limitations / not yet tested:
Local profile files safely stored:
```
Give the owner the three local YAML files and the measurement files through a
suitable private channel. For a different owner, use the clean repository
or starter ZIP, so they get their own keys and their own panel calibration.
## Light card
- RGB+white light: three sliders; RGB-only: color and brightness; white-only:
white temperature and brightness. A plain dimmer keeps the brightness card.
- Drag slowly across the rainbow, release, and check the physical light.
Repeat for white temperature and brightness. Brightness keeps the color mode.
- Reopen the card and check the received values. Test two lights with
different temperature ranges; no value should leak from the other light.
- The firmware render diagnostic includes `Light sliders: PASS`: twenty preview events
per slider, exactly one commit on release, no duplicate commit, no commit
after an aborted touch, and four capability combinations. This runs with
swapped-in callbacks and doesn't control any real lights.
+20 -11
View File
@@ -11,14 +11,20 @@ panel, a loose connection, unstable power, or random outliers.
## Preparing
1. Use the `device.yaml` from `tools/new_device.py`, with your own
`calibration.yaml` that starts as identity. Don't carry over the personal
correction from the historical base profile.
1. Use the screen's own ESPHome YAML, the one ESP Screens wrote when it was
installed, and add your own `calibration.yaml` to its `packages:` (it starts as
identity). Don't carry over another panel's correction.
```yaml
packages:
display: ... # what ESP Screens put there
calibration: !include calibration.yaml
```
2. Check the data cable and the USB port with `python -m serial.tools.list_ports`.
3. Flash from the repo root:
```sh
python -m esphome -s CALIBRATION_ON_BOOT true run device.yaml --device <USB_PORT>
python -m esphome -s CALIBRATION_ON_BOOT true run <your-screen>.yaml --device <USB_PORT>
```
4. Physically check for the **dark screen with five white + marks**.
@@ -75,8 +81,8 @@ The script:
placing a new, complete version.
The output contains only the four base bounds and six affine coefficients in
an ESPHome substitutions map. `device.yaml` imports this as the calibration
package. Don't change the coefficients by feel, and don't add a second correction
an ESPHome substitutions map, which the screen's YAML imports as the
calibration package. Don't change the coefficients by feel, and don't add a second correction
in the driver. The `raw=` logs contain the filtered **physical ADC values**,
even once a correction is already set; recalibrating therefore doesn't stack twice.
@@ -87,7 +93,7 @@ A successful fit on existing data is not yet a successful physical test.
Flash the correction, still with the measurement screen:
```sh
python -m esphome -s CALIBRATION_ON_BOOT true run device.yaml --device <USB_PORT>
python -m esphome -s CALIBRATION_ON_BOOT true run <your-screen>.yaml --device <USB_PORT>
```
Close the log reader with Ctrl+C and collect **new taps**:
@@ -109,12 +115,15 @@ test to pass. Report any remaining hardware deviation honestly.
## Back to normal operation
```sh
python -m esphome run device.yaml --device <USB_PORT>
python -m esphome run <your-screen>.yaml --device <USB_PORT>
```
No `-s CALIBRATION_ON_BOOT true` is given here. In `device.yaml`, the
setting stays `false`. Check the actual tiles and navigation per
[ACCEPTANCE.md](ACCEPTANCE.md).
No `-s CALIBRATION_ON_BOOT true` is given here; the profile keeps it `false`.
Then check the real thing: the tiles, the navigation and a few taps in the corners.
Most screens never need this. A CYD shows its calibration on the screen itself when
it first starts, and ESP Screens has **Calibrate touch** for a repeat. This USB route
is for a panel that stays off after that, or for a measurement report.
If calibration mode was opened only via the API, you can close it:
+2 -2
View File
@@ -74,8 +74,8 @@ three times, hold each tap briefly, and follow each next crosshair in turn.
There are five positions. The center checks accuracy. On a failed
measurement, the screen asks you to start over. The correction is stored locally
and survives OTA updates. Use the HA device button **Calibrate touch** to
measure again later. For diagnostics and the older manual installation, see:
[CALIBRATING.md](CALIBRATING.md).
measure again later. For a panel that stays off, or for a measurement report over
USB, see [CALIBRATING.md](CALIBRATING.md).
**Guition:** the GT911 touch mapping is baked into the board profile; there's no ADC calibration.
+13 -24
View File
@@ -13,9 +13,9 @@ or periodic recovery script is needed. The GT911 uses unmirrored coordinates.
## Files
- `guition-4848s040.yaml`: neutral hardware + 480×480 interface.
- `guition-device.example.yaml`: personal device/tile settings.
- `guition-device.yaml`: your local profile, outside Git.
- `guition-4848s040.yaml`: the board profile (hardware + 480×480 interface).
- `packages/guition.yaml`: what a screen builds from; generated from that profile.
- `<your-screen>.yaml`: the screen's own profile, written by ESP Screens, outside Git.
- `secrets.yaml`: local Wi-Fi/API/OTA settings, outside Git.
- `tools/verify_gt911.py`: physical pixel check; no resistive ADC calibration.
@@ -50,30 +50,20 @@ interrupts the transition. ESPHome's light state is synced after the fade,
so the entity in HA and later transitions stay correct.
The existing tile actions, climate control, and vacuum card are preserved.
All card types are available at all twenty runtime positions. Only in
the old manual profile does the vacuum card stay on tile 6 and do positions
8/10 have limitations; see [TILES.md](TILES.md).
Every card type works in all twenty positions.
## New installation
Follow the Python/USB setup in [README.md](../README.md), in a fresh
copy. Create this profile:
```sh
python tools/new_device.py --board guition --name wallbox-kitchen --friendly-name "Wallbox kitchen"
```
This creates `guition-device.yaml` and new secrets; existing files are
not overwritten. Fill in Wi-Fi and change the tile entities. With
multiple boards, use a separate folder per device. The owner's current local
Guition profile may use their existing secrets.
Install the screen from ESP Screens ([EASY_SETUP.md](EASY_SETUP.md)): it writes the
screen's own profile with its name, Wi-Fi reference and unique keys, and flashes it
over USB. Choose the tiles afterwards in the app, not in the YAML.
Check the serial port and chip before uploading. On the tested board,
higher serial speeds proved unreliable when reading. Use 115200 baud:
```sh
python -m esphome config guition-device.yaml
python -m esphome compile guition-device.yaml
python -m esphome config <your-screen>.yaml
python -m esphome compile <your-screen>.yaml
```
Flash via `esphome run` if the USB connection is reliable. For explicit
@@ -119,17 +109,16 @@ desired LVGL rotation and give the wizard the same value, for example
## HA and acceptance
Add the new device via the ESPHome integration (name/IP, port 6053,
API key from secrets). Grant permission for HA actions and use
`DIRECT_ACTIONS: "true"` once the correct entities have been checked.
API key from secrets), then choose its tiles in ESP Screens.
```sh
python diagnostics/run_ui_test.py --host wallbox-kitchen.local --name wallbox-kitchen
python -m unittest discover -s tests -p 'test_*.py'
```
Also go through the physical checks in [ACCEPTANCE.md](ACCEPTANCE.md), using the
GT911 wizard instead of the XPT2046 calibration. Check the display, correct
touches, pagination, long press, climate/vacuum, real HA feedback,
Also go through the physical checks, using the GT911 wizard instead of the XPT2046
calibration. Check the display, correct touches, pagination, long press,
climate and vacuum cards, real HA feedback,
standby, and recovery after a restart. A compile/render test doesn't replace
that physical check. The original CYD board's test outcome
says nothing about this new board.
+50 -4
View File
@@ -21,10 +21,10 @@
1. Update the source profiles and shared components. Run
`python3 tools/generate_packages.py`; never edit `packages/*.yaml` directly.
2. Run all Python tests with aiohttp installed, all `tests/*.cpp`, the
generator with `--check`, and compile both Easy Setup profiles plus the
existing manual profiles. Do that sequentially: profiles with the same
`DEVICE_NAME` share one build folder, and a parallel build can make an upload
pick the wrong `firmware.bin`. Check that no secrets are in Git.
generator with `--check`, and compile both Easy Setup profiles. Do that
sequentially: profiles with the same `DEVICE_NAME` share one build folder, and a
parallel build can make an upload pick the wrong `firmware.bin`. Check that no
secrets are in Git.
3. Test app start, saving, restarting/updating with existing layouts,
reconnecting to HA, and an ESP restart. Test a new card on real
hardware. A good build doesn't replace physical touch acceptance.
@@ -176,6 +176,52 @@ 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.50 / firmware 0.2.43
Firmware, board profiles and the package generator; the app only raises `FIRMWARE_VERSION`. Storage,
protocol, preferences and keys are unchanged.
- Slider fills: `runtime_tiles::slider_handle` and the light card rows in `light_controls.h` give
`LV_PART_INDICATOR` the track's radius (`height * 12 / 42`, round at 20 px or less). A smaller fill
radius makes LVGL 9.5's `lv_bar` draw the fill into an ARGB8888 layer of its own size on every redraw
and clip it to the track (a 128×30 fill: 15 KB). When that allocation failed, the refresh retried until
the task watchdog reset the CYD (log: `lv_draw_buf_create_ex: No memory: 115x30, cf: 16`).
`tests/test_layer_free.py` rejects layer styles (`opa_layered`, transform rotation/scale/skew, blend
mode, bitmap masks, `clip_corner`, drop shadow, blur) and a fill radius that differs from its track in
both profiles, both packages and the firmware headers. `opa` itself makes no layer in LVGL 9.5.
- `runtime_model.h`: `Tile` keeps the shared fields inline. `Extra` holds climate modes and action, select
options, forecast/hours/wind/feels, sunrise/sunset/timer, media title, vacuum speeds, choices, room and
charging. It lives on the heap only while a state message fills something in (`Tile::set_extra`,
`extra()`, `edit_extra()`, `extra_ptr()`). `options` and `fan_speeds` are vectors (no
`option_count`/`fan_speed_count`), and `history` holds 24 samples or none. `revision`/`pending_revision`
are FNV-1a fingerprints (`Fingerprint`, also an ArduinoJson writer) instead of copies of state,
attributes and extras. On the ESP32 `runtime_tiles::model` shrinks from 24,296 to 8,216 bytes.
- The old manual profile is gone from both board profiles: the 80 `homeassistant` sensor and text
sensors of the fixed tiles, `smartdisplay_action`, the tile tap and long-press handlers,
`publish_action`, `do_tile_action`, the manual refresh in `ui_refresh`, the YAML vacuum card with
`open_vacuum_overlay`/`vacuum_action`/`vacuum_fan_speed`, `light_controls::subscribe`, the 331
`TILE*` substitutions, and `DYNAMIC_TILES`/`TILE_COUNT`/`DIRECT_ACTIONS`/`TIME_24H`/`ORIENTATION`.
`runtime_tiles::enabled` is set true at boot and the `DIRECT_ACTIONS` guards became
`runtime_tiles::fresh()`. The runtime detail hook lost its unreachable vacuum branch. Deleted:
`device.example.yaml`, `guition-device.example.yaml`, `tools/new_device.py`, `tools/export_bundle.py`,
`TILE_CONFIGURATION.md`, `docs/TILES.md`, `docs/ACCEPTANCE.md`, `CYD_STABILITY.md`, `TEST_RESULTS.md`,
and the five stale header copies in the repository root (`cyd_ui.h`, `light_controls.h`,
`alert_overlay.h`, `backlight_fade.h`, `guition_diagnostics.h`) that had drifted from
`components/smart_display/`; `tests/test_cyd_ui.cpp` and `tests/test_light_controls.cpp` were
compiling those copies and now include the component headers, as both profiles do.
`tools/generate_packages.py` no longer strips or substitutes anything for the manual profile: the
board profile's own defaults are the package's, and a `homeassistant` sensor in a profile is refused.
The entity "SmartDisplay Action" disappears from every screen. The USB touch calibration
(`tools/calibrate.py`, `docs/CALIBRATING.md`, `calibration.example.yaml`, `CALIBRATION_ON_BOOT`,
the measurement page) and the on-screen calibration are unchanged.
- `esphome config` of both Easy profiles is byte-identical before and after this cleanup, apart from
two reordered lines: the firmware does the same thing, with the same calibration.
- `tile_scroll` and `dim_wake_overlay` (and the manual vacuum rows) get `pressed: bg_opa: TRANSP`. The
theme's obj pressed style (`bg_opa` 45%) lit up the transparent area on a tap between tiles and on the
wake tap.
- Both profiles add the debug sensor `min_free` ("Heap Minimum Free":
`heap_caps_get_minimum_free_size(MALLOC_CAP_INTERNAL)`, every 300 s).
### Compatibility 0.2.49 / firmware 0.2.42
Firmware and the CYD board profile; the app only raises `FIRMWARE_VERSION`. Storage, protocol,
+50
View File
@@ -0,0 +1,50 @@
# Test results app 0.2.50 / firmware 0.2.43 (2026-09-15/16)
Memory for the CYD: layer-free sliders, a leaner tile model, and the old manual profile out of both
board profiles. See CHANGELOG 0.2.50 and RELEASING "Compatibility 0.2.50".
## Automated
- Python (`.venv-portal`): 175 tests OK. New: `tests/test_layer_free.py` (no style that makes LVGL draw
into a buffer of its own, and every slider fill keeps its track's radius, in both profiles, both
packages and the firmware headers) and `tests/test_easy_package.py` (packages current, no secrets or
local paths, the manual profile gone from profiles and packages, runtime parts present, and the
generator refuses a fixed Home Assistant subscription).
- C++ (`clang++ -std=c++17 -Wall -Wextra -Werror -I . -I components/smart_display`): 13/13 PASS, with
`test_runtime_model.cpp` and `test_tile_controls.cpp` also clean under
`-fsanitize=address,undefined`. `test_cyd_ui.cpp` and `test_light_controls.cpp` were compiling the
stale header copies in the repository root; they include the component headers now and still pass.
- `generate_packages.py --check` green.
- `esphome config` of both Easy profiles is identical before and after the manual-profile cleanup,
apart from two reordered lines: the firmware that was tested on the bench is the firmware released.
## Build sizes (ESPHome 2026.6.2)
| Profile | RAM 0.2.49 | RAM 0.2.50 | Flash 0.2.49 | Flash 0.2.50 |
|---|---|---|---|---|
| easy-cyd-device.yaml | 32.0% | 22.8% (74,668 B) | 78.6% | 75.5% |
| easy-guition-device.yaml | 33.0% | 23.8% (77,892 B) | 19.0% | 18.3% |
`runtime_tiles::model` (twenty tile slots) shrank from 24,296 to 8,216 bytes.
## Bench boards
Both boards were flashed over the air with firmware 0.2.43 and ran from 19:08 to 08:00 the next
morning without a restart: `last_boot` unchanged, `Synced`, no memory warning in the log.
| | CYD before (0.2.42) | CYD after | Guition before | Guition after |
|---|---|---|---|---|
| Free heap after the sync | 64–77 KB | 101–103 KB | 51–65 KB | 84–97 KB |
| Lowest free heap since boot | not measured | 78.1 KB over 13 hours | not measured | 62.8 KB |
| Largest free block | 48 KB | 48 KB | 31.7 KB | 36.9–57.3 KB |
The owner used both screens for about ten minutes right after the update: the brightness slider of a
light tile and of the light card, the vacuum card with its cleaning settings, cards and page swipes.
Home Assistant confirmed every action within about 0.3 s. No `lv_draw_buf_create_ex: No memory`, no
watchdog reset, no rollback. On the Guition, LVGL reported 216–276 ms for single operations while a
card was being rebuilt, as it did before this release.
## Not tested / for the owner
- A screen that still ran the old manual profile. There are none left; the route is gone.
- The USB touch calibration was not measured again; its code and documentation are unchanged.
-184
View File
@@ -1,184 +0,0 @@
# Configuring tiles for your Home Assistant
Edit `device.yaml`, within the existing `substitutions:`. You don't need to
touch the base code for the examples below. Every change requires a rebuild
and reflash. Go through the [installation](../README.md) first.
## Collecting entity IDs
In HA, open **Settings → Tools → States** (**Developer tools → States** on older
HA versions). Find the entity you want and
copy the full ID, for example `light.kitchen`. Check its state and
attributes. The tile's title is free to choose; the entity ID must be exact.
Under **Settings → Tools → Actions**, test the intended action with that entity.
An action can control the real device: choose a suitable test.
See [HA actions](https://www.home-assistant.io/docs/scripts/perform-actions/).
First make a list of position, title, entity ID, tap action, and long-press action.
Use existing HA scripts/scenes for multiple devices or complex logic.
## Positions and limits
| Positions | Intended use in this firmware |
|---|---|
| 1–6 | Main tiles; light, switch, scene, script, fan, cover, and climate |
| 6 | Also the vacuum card; the card is specifically tied to tile 6 |
| 7 and 9 | Extra light tiles with brightness/color control |
| 8 and 10 | Extra status/action tiles; no full number/climate card |
`TILE_COUNT: "1"` through `"10"` determines how many **consecutive** positions are
visible. Up to and including six, Previous/Next stay hidden; from seven on, 1–6 sit
on page one and the rest on page two. Free scrolling has been replaced by fixed
pages. Leave unused positions on the neutral example entities.
Don't change grid dimensions to add tiles.
## Key settings
| Setting (`N` = tile number) | Meaning |
|---|---|
| `TILEN_ENTITY` | Entity the action is performed on |
| `TILEN_STATE_ENTITY` | Entity for status/attributes; usually the same one |
| `TILEN_TITLE` | Short title, ideally about 12 characters max |
| `TILEN_TYPE` | Domain, for example `light`, `scene`, `climate` |
| `TILEN_TAP_ACTION` | `auto`, `toggle`, or `custom` for the examples below |
| `TILEN_TAP_SERVICE` | Explicit HA action when using custom, for example `script.turn_on` |
| `TILEN_LONGPRESS` | `none`, `slider`, or (tile 6 only) `vacuum` |
| `TILEN_LONGPRESS_SLIDER` | `auto`; picks a suitable control based on type |
| `TILEN_LABEL_ON/OFF` | Text for a simple on/off status |
The example config also fills in the remaining fields. Leave those as they are unless
you deliberately use them. For a scene/script, `STATE_ENTITY` can follow a real light or
switch; a scene itself has no reliable on/off status.
## Color, white temperature, and brightness
An RGB/color light with `LONGPRESS: "slider"` opens the light card directly.
It contains up to three horizontal sliders:
- **Color:** a continuous rainbow (0–360° hue, 100% saturation).
- **White temperature:** warm to cool, within the minimum/maximum Kelvin values
the light reports in Home Assistant.
- **Brightness:** 1–100%; on/off stays available via the tile.
The color and white sliders only appear if `supported_color_modes` supports
them. A dimmable-only light keeps the regular brightness card.
No extra tile settings are needed. For a light, use the same
`ENTITY` and `STATE_ENTITY`. The color card follows `hs_color`, `color_temp_kelvin`,
`min_color_temp_kelvin`, and `max_color_temp_kelvin` of the controlled entity.
If the temperature range is missing, the white slider waits for HA data.
When opened, the card takes over the last received light values. Dragging shows
the chosen value locally; only releasing sends a single command. Color selects the
color mode, white temperature selects the white mode. Brightness doesn't change the
color mode. The rainbow controls hue; pastel/saturation isn't a separate control.
The hue list is sent to HA via ESPHome `data_template`; see the
[official API documentation](https://esphome.io/components/api/#homeassistantaction-action).
The shared implementation lives in `light_controls.h`. Both screen profiles
use it; the Guition has larger controls, the CYD a compact card.
`diagnostics/run_ui_test.py` also checks the slider events with swapped-in
callbacks: no real HA actions. For a safe 40-second preview card:
```sh
python diagnostics/control_ui.py light_controls_preview --host guition-wallbox.local --name guition-wallbox
```
For the CYD, use its own host and name. During this preview card,
light commands are suppressed and the card disappears on its own. Then test the
actual light: long press, choose a color, choose white, adjust brightness,
close, and reopen. Check the physical light and the values in HA.
## Examples
Change these keys in the existing map; don't paste `substitutions:` a second time.
Dimmable light at position 1 (tap toggles, long press opens the control):
```yaml
TILE1_ENTITY: "light.kitchen"
TILE1_STATE_ENTITY: "light.kitchen"
TILE1_TITLE: "Kitchen"
TILE1_TYPE: "light"
TILE1_TAP_ACTION: "auto"
TILE1_LONGPRESS: "slider"
```
A non-dimmable light/switch gets `LONGPRESS: "none"`. Color control
requires that the light supports the relevant color mode.
Scene at position 3:
```yaml
TILE3_ENTITY: "scene.evening"
TILE3_STATE_ENTITY: "light.kitchen"
TILE3_TITLE: "Evening"
TILE3_TYPE: "scene"
TILE3_TAP_ACTION: "auto"
TILE3_LONGPRESS: "none"
```
Script at position 4:
```yaml
TILE4_ENTITY: "script.all_off"
TILE4_STATE_ENTITY: "script.all_off"
TILE4_TITLE: "All off"
TILE4_TYPE: "script"
TILE4_TAP_ACTION: "auto"
TILE4_LONGPRESS: "none"
```
AC at position 5 (long press opens climate):
```yaml
TILE5_ENTITY: "climate.living_room"
TILE5_STATE_ENTITY: "climate.living_room"
TILE5_TITLE: "AC"
TILE5_TYPE: "climate"
TILE5_TAP_ACTION: "toggle"
TILE5_TAP_SERVICE: "climate.toggle"
TILE5_LONGPRESS: "slider"
```
Check `min_temp`, `max_temp`, `target_temp_step`, `hvac_modes`, and the
supported fan/swing modes in HA. This card is primarily for a **single
setpoint**, not a thermostat that only uses a temperature range.
Test your integration's modes individually; a different AC unit
may have different capabilities.
Robot vacuum at position 6 (tap starts; long press opens the card):
```yaml
TILE6_ENTITY: "vacuum.robot"
TILE6_STATE_ENTITY: "vacuum.robot"
TILE6_TITLE: "Vacuum"
TILE6_TYPE: "vacuum"
TILE6_TAP_ACTION: "custom"
TILE6_TAP_SERVICE: "vacuum.start"
TILE6_LONGPRESS: "vacuum"
```
The vacuum card uses start/pause/stop/return/locate and the
speed names `quiet`, `balanced`, `turbo`, `max`. Compare these with the
supported actions and `fan_speed_list` in HA. The speed buttons need to be
adjusted in the base code if your integration expects different names.
This is not a universal card for every robot model.
## Enabling and checking actions
After calibration and HA pairing, set `DIRECT_ACTIONS: "true"`. In the
ESPHome integration, grant permission for Home Assistant actions. Don't use an
HA automation that also runs the same screen action again separately; that can
cause a double toggle. With `DIRECT_ACTIONS: "false"`, the action sensor can
still publish events for your own automations.
Flash `device.yaml` and test one tile at a time: correct status, correct physical
action, feedback from HA, and long press. Also check that external
changes in HA appear on the screen. Then run the
[acceptance test](ACCEPTANCE.md).
The icon fonts contain the tile icon set from `screen_manager/app/tile_icons.py`;
pick `TILEn_ICON` from there. To add a different icon, add it there and run
`tools/generate_icons.py`. The bundle includes the fonts locally. The older, more extensive
[TILE_CONFIGURATION.md](../TILE_CONFIGURATION.md) also describes the removed
scroll profile as a historical record; don't use it as hardware/layout instructions for this board.
+2 -2
View File
@@ -15,8 +15,8 @@
| Duplicate HA action | Check both the touch logs and HA automations. Don't use direct actions together with an automation on the action sensor for the same operation. |
| Wi-Fi doesn't connect | 2.4GHz, correct local secrets, network range. USB calibration doesn't need HA. |
| HA doesn't see the board | Manually use the IP from the logs; port 6053 reachable, correct encryption key, no guest network isolation. |
| Status works but action doesn't | Check the HA option for allowed device actions, `DIRECT_ACTIONS: "true"`, the real entity ID, and a supported action. |
| Vacuum/climate partly usable | Supported modes/attributes differ per integration; see TILES.md and test the same action in HA first. |
| Status works but action doesn't | Check the HA option for allowed device actions, the real entity ID, and a supported action. |
| Vacuum/climate partly usable | Supported modes/attributes differ per integration; test the same action in Home Assistant first. |
| Wrong pagination | `TILE_COUNT` is 1–10; hidden buttons up to six, two pages from seven on. Reflash after changing it. |
| Freeze/reset | Keep the USB log, check the reset reason/power, and run the render test. Note the action and time. |