aa2137f3f8
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>
577 lines
25 KiB
Markdown
577 lines
25 KiB
Markdown
> New ESP32-2432S028 installation: start at [README.md](README.md) and
|
||
> [the current tile guide](docs/TILES.md). Legacy behavior is also described below.
|
||
|
||
# Tile Configuration Reference
|
||
|
||
For the ESP32-2432S028 profile, use `home-like-2432s028.yaml` and
|
||
[CYD_STABILITY.md](CYD_STABILITY.md). That profile uses fixed pages instead of
|
||
scrolling, hides pagination when `TILE_COUNT <= 6`, and dims after ten minutes.
|
||
The scrolling section below describes `home-like.yaml`, an early personal
|
||
profile that has since been removed from the repository; it's kept here only
|
||
as a historical record.
|
||
|
||
This document explains every substitution used across the tile profiles and provides copy-paste examples for all supported entity types.
|
||
|
||
---
|
||
|
||
## How substitutions work
|
||
|
||
ESPHome substitutions are compile-time text replacements. There is no runtime logic in the substitution block — every `${TILE1_...}` reference in the YAML is replaced with the value you set before the firmware is compiled and flashed. This means:
|
||
|
||
- You cannot use `if/else` in substitutions
|
||
- Changes require a reflash
|
||
- The firmware is fully self-contained after flashing
|
||
|
||
---
|
||
|
||
## The home screen scrolls
|
||
|
||
The wallpaper, the room name and the clock sit on the page itself and stay put.
|
||
All tiles live inside one transparent container (`tile_scroll`) that scrolls
|
||
vertically, so the grid can be taller than the screen.
|
||
|
||
- The grid is **2 columns x 5 rows = 10 tiles**. Rows 1-3 are visible at rest;
|
||
dragging up reveals rows 4 and 5.
|
||
- `GRID_ROW*_Y` are **relative to the scroll container**, not to the page.
|
||
`SCROLL_Y` / `SCROLL_H` define where the container sits and how tall the
|
||
viewport is. Both are set per orientation preset.
|
||
- LVGL derives the scroll length from the tile positions, so there is no
|
||
content height to maintain by hand.
|
||
- Tapping and scrolling do not conflict: once a drag passes LVGL's scroll
|
||
limit (10 px) the short click *and* the long press are cancelled.
|
||
- `scroll_snap_y: START` makes the container click into place per row. Set it
|
||
to `NONE` on the `tile_scroll` object for free scrolling.
|
||
|
||
## Background
|
||
|
||
The background is a two-stop vertical gradient (`BG_TOP_COLOR` ->
|
||
`BG_BOTTOM_COLOR`), not an image. That saves ~150 KB of flash and removes an
|
||
image blit from every redraw, which is what makes scrolling usable on this
|
||
board. The same gradient is reused as the backdrop of the slider and color
|
||
overlays through the `style_bg_grad` style; the climate card uses the plain
|
||
light background of the other cards.
|
||
|
||
## Accent colors are automatic
|
||
|
||
A tile's accent color is derived from the **Home Assistant domain** — the part
|
||
of the entity id before the dot:
|
||
|
||
| Entity | Domain | Accent |
|
||
|--------|--------|--------|
|
||
| `script.good_morning` | `script` | `ACCENT_ACTION` (violet) |
|
||
| `scene.evening_lights` | `scene` | `ACCENT_ACTION` (violet) |
|
||
| `light.living_room_2` | `light` | `ACCENT_LIGHT` (amber) |
|
||
| `vacuum.s8` | `vacuum` | `ACCENT_DEVICE` (cyan) |
|
||
| `climate.ac` | `climate` | `ACCENT_DEVICE` (cyan) |
|
||
|
||
The distinction that matters: a script or scene is something you *fire*, a
|
||
device is something you switch *on and off*. Those should not look the same.
|
||
|
||
Two of the ten per-tile color keys participate: `TILE*_CIRCLE_ACTIVE_COLOR`
|
||
and `TILE*_ICON_DISABLED_COLOR`. Set them to `${ACCENT_AUTO}` to let the domain
|
||
decide — that is the default for every tile — or to a real hex value to
|
||
override that one tile. Tile 8 does exactly that: the mailbox turns red when
|
||
there is post, regardless of its domain.
|
||
|
||
Because the color follows the entity, dropping a different entity into a tile
|
||
gives it the right color without touching any color key.
|
||
|
||
> The domain lookup lives in a small `accent_for` lambda that appears **twice**
|
||
> in each profile: once in `ui_refresh` (for the tiles) and once in
|
||
> `open_value_overlay` (for the slider fill). Keep the two copies in sync.
|
||
|
||
---
|
||
|
||
## Global settings
|
||
|
||
| Key | Default | Description |
|
||
|-----|---------|-------------|
|
||
| `DIRECT_ACTIONS` | `"true"` | `true` = device calls HA services directly on tap. `false` = only publishes the action event, you handle it in HA automations. |
|
||
| `ROOM_NAME` | `"Office"` | Text shown in the top-left header. |
|
||
| `TIME_24H` | `"true"` | `true` = 24h clock, `false` = 12h with AM/PM. |
|
||
| `AUTO_DIM` | `"true"` | Enable backlight auto-dimming after inactivity. |
|
||
| `AUTO_DIM_TIMEOUT` | `"10"` | Seconds of no touch before dimming. |
|
||
| `MAX_BRIGHTNESS` | `"100"` | Backlight brightness (%) when active. |
|
||
| `DIM_BRIGHTNESS` | `"40"` | Backlight brightness (%) when dimmed. |
|
||
| `NIGHT_MODE` | `"true"` | Use a lower brightness level during night hours. |
|
||
| `NIGHT_START_HOUR` | `"22"` | Hour (0–23) when night mode starts. |
|
||
| `NIGHT_END_HOUR` | `"7"` | Hour (0–23) when night mode ends. |
|
||
| `NIGHT_DIM_BRIGHTNESS` | `"18"` | Backlight brightness (%) during night hours. |
|
||
| `BG_TOP_COLOR` | `"0xAEC4D9"` | Top color of the background gradient. |
|
||
| `BG_BOTTOM_COLOR` | `"0xD6BB9E"` | Bottom color of the background gradient. |
|
||
| `ACCENT_AUTO` | `"0x1000000"` | Sentinel meaning "derive this color from the entity domain". Deliberately outside the 24-bit color range. |
|
||
| `ACCENT_ACTION` | `"0x8B5CF6"` | Accent for `script`, `scene`, `button`, `input_button`, `automation`. |
|
||
| `ACCENT_LIGHT` | `"0xFEC600"` | Accent for `light`. |
|
||
| `ACCENT_DEVICE` | `"0x00C5EC"` | Accent for everything else (switch, fan, cover, climate, vacuum, media_player, …). |
|
||
|
||
---
|
||
|
||
## Per-tile substitutions
|
||
|
||
Each tile has the same set of keys, just with a different number
|
||
(TILE1 … TILE10). All ten slots are in use — see [Adding a tile](#adding-a-tile)
|
||
if you want to extend the grid further.
|
||
|
||
### Basic settings
|
||
|
||
| Key | Description |
|
||
|-----|-------------|
|
||
| `TILE*_ENTITY` | The Home Assistant entity this tile controls (e.g. `light.living_room`). |
|
||
| `TILE*_STATE_ENTITY` | Entity used to determine active/inactive visual state. Usually the same as `TILE*_ENTITY`. Set to a different entity if you want the tile to reflect a group or a related sensor. |
|
||
| `TILE*_TITLE` | Text label shown on the tile. |
|
||
| `TILE*_ICON` | Material Design Icons Unicode glyph. Find icons at [pictogrammers.com/library/mdi](https://pictogrammers.com/library/mdi/) — click an icon and copy the Unicode value (e.g. `U+F0769` → `"\U000F0769"`). |
|
||
| `TILE*_TYPE` | Entity type: `light` \| `fan` \| `switch` \| `scene` \| `script` \| `cover` \| `climate`. Controls tap behavior, value display, and slider type in auto mode. |
|
||
| `TILE*_TAP_ACTION` | What happens on short tap — see [Tap actions](#tap-actions) below. |
|
||
| `TILE*_LONGPRESS` | What happens on long press — see [Long press modes](#long-press-modes) below. |
|
||
| `TILE*_VALUE_MODE` | How the value line below the title is rendered — see [Value modes](#value-modes) below. |
|
||
| `TILE*_LABEL_OFF` | Text shown in the value line when the entity is off / inactive. |
|
||
| `TILE*_LABEL_ON` | Text shown in the value line when `VALUE_MODE` is `text` and entity is on. |
|
||
| `TILE*_ACTIVE_STATE` | Optional. Exact Home Assistant state that counts as "active". Leave empty for the default behavior (`on`, or always-on for scenes/scripts). Used by tile 8, where the state is `Vol` / `Leeg` rather than `on` / `off`. |
|
||
|
||
### Colors
|
||
|
||
All colors are 24-bit hex in the format `"0xRRGGBB"`.
|
||
|
||
| Key | Description |
|
||
|-----|-------------|
|
||
| `TILE*_CIRCLE_ACTIVE_COLOR` | Icon circle background when active. `${ACCENT_AUTO}` = derive from the entity domain. |
|
||
| `TILE*_CIRCLE_DISABLED_COLOR` | Icon circle background when inactive. |
|
||
| `TILE*_ICON_ACTIVE_COLOR` | Icon glyph color when active. |
|
||
| `TILE*_ICON_DISABLED_COLOR` | Icon glyph color when inactive. `${ACCENT_AUTO}` = derive from the entity domain. |
|
||
| `TILE*_BG_ACTIVE_COLOR` | Tile background when active. |
|
||
| `TILE*_BG_DISABLED_COLOR` | Tile background when inactive. |
|
||
| `TILE*_TITLE_ACTIVE_COLOR` | Title text color when active. |
|
||
| `TILE*_TITLE_DISABLED_COLOR` | Title text color when inactive. |
|
||
| `TILE*_VALUE_ACTIVE_COLOR` | Value text color when active. |
|
||
| `TILE*_VALUE_DISABLED_COLOR` | Value text color when inactive. |
|
||
|
||
### Advanced settings (short tap)
|
||
|
||
| Key | Default | Description |
|
||
|-----|---------|-------------|
|
||
| `TILE*_TAP_SERVICE` | `""` | Override the HA service called on tap (e.g. `"light.toggle"`). Leave empty to use the default for the tile type. |
|
||
| `TILE*_TAP_PARAM_KEY` | `""` | Extra parameter key for the service call. Supported keys: `preset_mode`, `brightness_pct`, `percentage`, `option`. Any other value is ignored and the service is called with `entity_id` only. |
|
||
| `TILE*_TAP_PARAM_VAL` | `""` | Extra parameter value (e.g. `"Auto"`). |
|
||
|
||
### Advanced settings (long press — slider mode)
|
||
|
||
Only relevant when `TILE*_LONGPRESS` is set to `"slider"`.
|
||
|
||
| Key | Default | Description |
|
||
|-----|---------|-------------|
|
||
| `TILE*_LONGPRESS_SLIDER` | `"auto"` | Slider type: `auto` \| `brightness` \| `percentage` \| `cover_position` \| `climate_temperature`. `auto` picks the right type based on `TILE*_TYPE`. |
|
||
| `TILE*_LONGPRESS_OFF_VALUE` | `"0"` | Initial slider position (0–100) shown when the entity is currently off. |
|
||
|
||
### Advanced settings (climate tiles)
|
||
|
||
Only relevant when `TILE*_TYPE` is set to `"climate"`.
|
||
|
||
| Key | Default | Description |
|
||
|-----|---------|-------------|
|
||
| `TILE*_CLIMATE_MIN_TEMP` | `"5.0"` | Minimum target temperature on the climate card. |
|
||
| `TILE*_CLIMATE_MAX_TEMP` | `"30.0"` | Maximum target temperature on the climate card. |
|
||
| `TILE*_CLIMATE_STEP` | `"0.5"` | Step size of the − / + keys. Values below `0.5` are rounded up to `0.5`, so the UI always adjusts in whole or half-degree steps. |
|
||
| `TILE*_CLIMATE_CURRENT_TEMP_ATTRIBUTE` | `"current_temperature"` | Home Assistant attribute used for the current room temperature. |
|
||
| `TILE*_CLIMATE_TARGET_TEMP_ATTRIBUTE` | `"temperature"` | Home Assistant attribute used for the target temperature. |
|
||
| `TILE*_CLIMATE_HUMIDITY_ATTRIBUTE` | `"current_humidity"` | Home Assistant attribute used for humidity. Leave the default if the entity does not provide humidity. |
|
||
|
||
### Advanced settings (long press — action mode)
|
||
|
||
Only relevant when `TILE*_LONGPRESS` is set to `"action"`.
|
||
|
||
| Key | Default | Description |
|
||
|-----|---------|-------------|
|
||
| `TILE*_LONGPRESS_ACTION` | `""` | HA entity to call on long press. Can be completely different from `TILE*_ENTITY`. |
|
||
| `TILE*_LONGPRESS_ACTION_TYPE` | `""` | Entity type of the long press target: `light` \| `fan` \| `switch` \| `scene` \| `script` \| `cover`. Leave empty to inherit from `TILE*_TYPE`. |
|
||
| `TILE*_LONGPRESS_ACTION_SERVICE` | `""` | Service to call (default is `activate`/`turn_on`). Set e.g. `"light.toggle"` to toggle instead. |
|
||
|
||
---
|
||
|
||
## Tap actions
|
||
|
||
| Value | Behavior |
|
||
|-------|----------|
|
||
| `auto` | Picks the best action for the tile type: `toggle` for light/fan/switch/cover, `activate` for scene/script. Climate tiles do not have a default tap action; use `TILE*_TAP_SERVICE` if you want short tap behavior. |
|
||
| `toggle` | Toggles the entity (light.toggle / fan.toggle / switch.toggle / cover open↔close). |
|
||
| `activate` | Turns on / activates the entity (scene.turn_on / script.turn_on / light.turn_on / cover.open_cover). |
|
||
| `fan_toggle_preset` | If fan is ON: turns it off. If fan is OFF: turns it on and sets a preset mode (configure with `TAP_PARAM_KEY` / `TAP_PARAM_VAL`). |
|
||
| `custom` | Use `TAP_SERVICE` + `TAP_PARAM_KEY` / `TAP_PARAM_VAL` for a fully custom service call. |
|
||
|
||
---
|
||
|
||
## Long press modes
|
||
|
||
| Value | Behavior |
|
||
|-------|----------|
|
||
| `slider` | Opens a value overlay with a slider. Configure with `TILE*_LONGPRESS_SLIDER` and `TILE*_LONGPRESS_OFF_VALUE`. |
|
||
| `action` | Fires a different HA entity than the short tap. Configure with `TILE*_LONGPRESS_ACTION*`. |
|
||
| `none` | No direct action — only publishes `tileN_long_press` to HA so you can react in automations. |
|
||
|
||
In all modes, the event `tileN_long_press` is always published to `sensor.smartdisplay_action` in Home Assistant.
|
||
|
||
For light tiles in `slider` mode, the brightness overlay automatically shows a color-ring button when `DIRECT_ACTIONS` is `"true"` and Home Assistant reports a supported color mode (`hs`, `rgb`, `rgbw`, `rgbww`, `xy`) or color temperature mode (`color_temp`). The color detail view can send `light.turn_on` with `color_name`, `color_temp_kelvin`, and the current brightness percentage. If the light only supports color or only supports color temperature, the Color/Temp tab switch is hidden and only the supported controls are shown. No extra tile substitutions are required.
|
||
|
||
For climate tiles in `slider` mode, the climate card shows the target temperature between big − / + keys: the number follows every tap at once, holding a key keeps stepping, and one `climate.set_temperature` goes out once the taps stop (0.7 s). The min/max range, step size, and Home Assistant attribute names are configured through the `TILE*_CLIMATE_*` substitutions. Below it, one key per supported `hvac_mode` (in Home Assistant's order, off is the power key) sends `climate.set_hvac_mode` when `DIRECT_ACTIONS` is `"true"`; the ··· key opens the picker with fan and swing modes.
|
||
|
||
---
|
||
|
||
## Value modes
|
||
|
||
| Value | Behavior |
|
||
|-------|----------|
|
||
| `auto` | Picks automatically: `brightness` for lights, `percentage` or `preset` for fans, `climate` for climate entities, `text` for everything else. |
|
||
| `brightness` | Shows brightness as a percentage (e.g. `80 %`). When off, shows `LABEL_OFF`. |
|
||
| `percentage` | Shows fan speed as a percentage. When off, shows `LABEL_OFF`. |
|
||
| `preset` | Shows the fan preset_mode attribute. When off, shows `LABEL_OFF`. |
|
||
| `climate` | Shows the target temperature, falling back to current temperature if no target is available. When off, shows `LABEL_OFF`. |
|
||
| `text` | Shows `LABEL_ON` when on, `LABEL_OFF` when off. For scenes/scripts, always shows `LABEL_ON`. |
|
||
|
||
---
|
||
|
||
## Home Assistant events
|
||
|
||
Every tap publishes a short-lived state to `sensor.smartdisplay_action`:
|
||
|
||
| Event | Trigger |
|
||
|-------|---------|
|
||
| `tile1_press` … `tile10_press` | Short tap on tile 1–10 |
|
||
| `tile1_long_press` … `tile10_long_press` | Long press on tile 1–10 |
|
||
|
||
The state resets to `""` after 500ms. In HA automations, trigger on `state` → `to: "tile1_press"` etc.
|
||
|
||
---
|
||
|
||
## Complete examples
|
||
|
||
### Light — toggle + brightness slider
|
||
|
||
```yaml
|
||
TILE1_ENTITY: "light.living_room_ceiling"
|
||
TILE1_STATE_ENTITY: "light.living_room_ceiling"
|
||
TILE1_TITLE: "Ceiling"
|
||
TILE1_ICON: "\U000F0769" # mdi:ceiling-light
|
||
TILE1_TYPE: "light"
|
||
TILE1_TAP_ACTION: "auto" # toggles the light
|
||
TILE1_LONGPRESS: "slider" # long press opens brightness slider
|
||
TILE1_VALUE_MODE: "auto" # shows brightness % when on, "Off" when off
|
||
TILE1_LABEL_OFF: "Off"
|
||
TILE1_LABEL_ON: "On"
|
||
# colors
|
||
TILE1_CIRCLE_ACTIVE_COLOR: "0xFEC600"
|
||
TILE1_CIRCLE_DISABLED_COLOR: "0x7B7B6F"
|
||
TILE1_ICON_ACTIVE_COLOR: "0xFFFFFF"
|
||
TILE1_ICON_DISABLED_COLOR: "0xFEC600"
|
||
TILE1_BG_ACTIVE_COLOR: "0xFFFFFF"
|
||
TILE1_BG_DISABLED_COLOR: "0x939391"
|
||
TILE1_TITLE_ACTIVE_COLOR: "0x000000"
|
||
TILE1_TITLE_DISABLED_COLOR: "0xFFFFFF"
|
||
TILE1_VALUE_ACTIVE_COLOR: "0x7A7A7C"
|
||
TILE1_VALUE_DISABLED_COLOR: "0xD9D9D9"
|
||
# advanced
|
||
TILE1_TAP_SERVICE: ""
|
||
TILE1_TAP_PARAM_KEY: ""
|
||
TILE1_TAP_PARAM_VAL: ""
|
||
TILE1_LONGPRESS_SLIDER: "auto" # auto = brightness for lights
|
||
TILE1_LONGPRESS_OFF_VALUE: "0"
|
||
TILE1_LONGPRESS_ACTION: ""
|
||
TILE1_LONGPRESS_ACTION_TYPE: ""
|
||
TILE1_LONGPRESS_ACTION_SERVICE: ""
|
||
```
|
||
|
||
---
|
||
|
||
### Switch — simple toggle, no slider
|
||
|
||
```yaml
|
||
TILE2_ENTITY: "switch.office_power_strip"
|
||
TILE2_STATE_ENTITY: "switch.office_power_strip"
|
||
TILE2_TITLE: "Power Strip"
|
||
TILE2_ICON: "\U000F06FF" # mdi:power-socket-eu
|
||
TILE2_TYPE: "switch"
|
||
TILE2_TAP_ACTION: "auto" # toggles the switch
|
||
TILE2_LONGPRESS: "none" # long press only sends event, no slider
|
||
TILE2_VALUE_MODE: "text" # shows "On" / "Off"
|
||
TILE2_LABEL_OFF: "Off"
|
||
TILE2_LABEL_ON: "On"
|
||
# colors
|
||
TILE2_CIRCLE_ACTIVE_COLOR: "0xFEC600"
|
||
TILE2_CIRCLE_DISABLED_COLOR: "0x7B7B6F"
|
||
TILE2_ICON_ACTIVE_COLOR: "0xFFFFFF"
|
||
TILE2_ICON_DISABLED_COLOR: "0xFEC600"
|
||
TILE2_BG_ACTIVE_COLOR: "0xFFFFFF"
|
||
TILE2_BG_DISABLED_COLOR: "0x939391"
|
||
TILE2_TITLE_ACTIVE_COLOR: "0x000000"
|
||
TILE2_TITLE_DISABLED_COLOR: "0xFFFFFF"
|
||
TILE2_VALUE_ACTIVE_COLOR: "0x7A7A7C"
|
||
TILE2_VALUE_DISABLED_COLOR: "0xD9D9D9"
|
||
# advanced
|
||
TILE2_TAP_SERVICE: ""
|
||
TILE2_TAP_PARAM_KEY: ""
|
||
TILE2_TAP_PARAM_VAL: ""
|
||
TILE2_LONGPRESS_SLIDER: "auto"
|
||
TILE2_LONGPRESS_OFF_VALUE: "0"
|
||
TILE2_LONGPRESS_ACTION: ""
|
||
TILE2_LONGPRESS_ACTION_TYPE: ""
|
||
TILE2_LONGPRESS_ACTION_SERVICE: ""
|
||
```
|
||
|
||
---
|
||
|
||
### Cover — open/close toggle + position slider
|
||
|
||
```yaml
|
||
TILE3_ENTITY: "cover.living_room_blinds"
|
||
TILE3_STATE_ENTITY: "cover.living_room_blinds"
|
||
TILE3_TITLE: "Blinds"
|
||
TILE3_ICON: "\U000F111C" # mdi:blinds
|
||
TILE3_TYPE: "cover"
|
||
TILE3_TAP_ACTION: "auto" # opens if closed, closes if open
|
||
TILE3_LONGPRESS: "slider" # long press opens position slider
|
||
TILE3_VALUE_MODE: "auto" # shows "Open" / "Closed" (text mode for covers)
|
||
TILE3_LABEL_OFF: "Closed"
|
||
TILE3_LABEL_ON: "Open"
|
||
# colors — blue theme for covers
|
||
TILE3_CIRCLE_ACTIVE_COLOR: "0x00C5EC"
|
||
TILE3_CIRCLE_DISABLED_COLOR: "0x7B7B6F"
|
||
TILE3_ICON_ACTIVE_COLOR: "0xFFFFFF"
|
||
TILE3_ICON_DISABLED_COLOR: "0x00C5EC"
|
||
TILE3_BG_ACTIVE_COLOR: "0xFFFFFF"
|
||
TILE3_BG_DISABLED_COLOR: "0x939391"
|
||
TILE3_TITLE_ACTIVE_COLOR: "0x000000"
|
||
TILE3_TITLE_DISABLED_COLOR: "0xFFFFFF"
|
||
TILE3_VALUE_ACTIVE_COLOR: "0x7A7A7C"
|
||
TILE3_VALUE_DISABLED_COLOR: "0xD9D9D9"
|
||
# advanced
|
||
TILE3_TAP_SERVICE: ""
|
||
TILE3_TAP_PARAM_KEY: ""
|
||
TILE3_TAP_PARAM_VAL: ""
|
||
TILE3_LONGPRESS_SLIDER: "auto" # auto = cover_position for covers
|
||
TILE3_LONGPRESS_OFF_VALUE: "0"
|
||
TILE3_LONGPRESS_ACTION: ""
|
||
TILE3_LONGPRESS_ACTION_TYPE: ""
|
||
TILE3_LONGPRESS_ACTION_SERVICE: ""
|
||
```
|
||
|
||
---
|
||
|
||
### Fan — toggle preset on tap + speed slider on long press
|
||
|
||
```yaml
|
||
TILE4_ENTITY: "fan.air_purifier"
|
||
TILE4_STATE_ENTITY: "fan.air_purifier"
|
||
TILE4_TITLE: "Purifier"
|
||
TILE4_ICON: "\U000F0D43" # mdi:air-purifier
|
||
TILE4_TYPE: "fan"
|
||
TILE4_TAP_ACTION: "fan_toggle_preset" # off→on with preset, on→off
|
||
TILE4_LONGPRESS: "slider" # long press opens speed slider
|
||
TILE4_VALUE_MODE: "auto" # shows preset name when on, "Off" when off
|
||
TILE4_LABEL_OFF: "Off"
|
||
TILE4_LABEL_ON: "On"
|
||
# colors — blue theme for fan
|
||
TILE4_CIRCLE_ACTIVE_COLOR: "0x00C5EC"
|
||
TILE4_CIRCLE_DISABLED_COLOR: "0x7B7B6F"
|
||
TILE4_ICON_ACTIVE_COLOR: "0xFFFFFF"
|
||
TILE4_ICON_DISABLED_COLOR: "0x00C5EC"
|
||
TILE4_BG_ACTIVE_COLOR: "0xFFFFFF"
|
||
TILE4_BG_DISABLED_COLOR: "0x939391"
|
||
TILE4_TITLE_ACTIVE_COLOR: "0x000000"
|
||
TILE4_TITLE_DISABLED_COLOR: "0xFFFFFF"
|
||
TILE4_VALUE_ACTIVE_COLOR: "0x7A7A7C"
|
||
TILE4_VALUE_DISABLED_COLOR: "0xD9D9D9"
|
||
# advanced — fan_toggle_preset requires SERVICE + PARAM
|
||
TILE4_TAP_SERVICE: "fan.toggle"
|
||
TILE4_TAP_PARAM_KEY: "preset_mode"
|
||
TILE4_TAP_PARAM_VAL: "Auto" # preset to activate when turning on
|
||
TILE4_LONGPRESS_SLIDER: "auto" # auto = percentage for fans
|
||
TILE4_LONGPRESS_OFF_VALUE: "0"
|
||
TILE4_LONGPRESS_ACTION: ""
|
||
TILE4_LONGPRESS_ACTION_TYPE: ""
|
||
TILE4_LONGPRESS_ACTION_SERVICE: ""
|
||
```
|
||
|
||
---
|
||
|
||
### Climate — climate card on long press
|
||
|
||
```yaml
|
||
TILE5_ENTITY: "climate.living_room"
|
||
TILE5_STATE_ENTITY: "climate.living_room"
|
||
TILE5_TITLE: "Living"
|
||
TILE5_ICON: "\U000F0438" # mdi:radiator
|
||
TILE5_TYPE: "climate"
|
||
TILE5_TAP_ACTION: "auto" # no default tap action; use TAP_SERVICE if desired
|
||
TILE5_LONGPRESS: "slider" # long press opens the climate card
|
||
TILE5_VALUE_MODE: "auto" # shows target temperature, or current temperature as fallback
|
||
TILE5_LABEL_OFF: "Off"
|
||
TILE5_LABEL_ON: "Heat"
|
||
# colors
|
||
TILE5_CIRCLE_ACTIVE_COLOR: "0xFF9F0A"
|
||
TILE5_CIRCLE_DISABLED_COLOR: "0x7B7B6F"
|
||
TILE5_ICON_ACTIVE_COLOR: "0xFFFFFF"
|
||
TILE5_ICON_DISABLED_COLOR: "0xFF9F0A"
|
||
TILE5_BG_ACTIVE_COLOR: "0xFFFFFF"
|
||
TILE5_BG_DISABLED_COLOR: "0x939391"
|
||
TILE5_TITLE_ACTIVE_COLOR: "0x000000"
|
||
TILE5_TITLE_DISABLED_COLOR: "0xFFFFFF"
|
||
TILE5_VALUE_ACTIVE_COLOR: "0x7A7A7C"
|
||
TILE5_VALUE_DISABLED_COLOR: "0xD9D9D9"
|
||
# advanced
|
||
TILE5_TAP_SERVICE: ""
|
||
TILE5_TAP_PARAM_KEY: ""
|
||
TILE5_TAP_PARAM_VAL: ""
|
||
TILE5_LONGPRESS_SLIDER: "auto" # auto = climate_temperature for climate tiles
|
||
TILE5_LONGPRESS_OFF_VALUE: "0"
|
||
TILE5_LONGPRESS_ACTION: ""
|
||
TILE5_LONGPRESS_ACTION_TYPE: ""
|
||
TILE5_LONGPRESS_ACTION_SERVICE: ""
|
||
TILE5_CLIMATE_MIN_TEMP: "5.0"
|
||
TILE5_CLIMATE_MAX_TEMP: "30.0"
|
||
TILE5_CLIMATE_STEP: "0.5"
|
||
TILE5_CLIMATE_CURRENT_TEMP_ATTRIBUTE: "current_temperature"
|
||
TILE5_CLIMATE_TARGET_TEMP_ATTRIBUTE: "temperature"
|
||
TILE5_CLIMATE_HUMIDITY_ATTRIBUTE: "current_humidity"
|
||
```
|
||
|
||
---
|
||
|
||
### Scene — activate on tap
|
||
|
||
```yaml
|
||
TILE6_ENTITY: "scene.movie_night"
|
||
TILE6_STATE_ENTITY: "scene.movie_night" # scenes are always "on" so the tile stays active-styled
|
||
TILE6_TITLE: "Movie"
|
||
TILE6_ICON: "\U000F0E8B" # mdi:movie-open
|
||
TILE6_TYPE: "scene"
|
||
TILE6_TAP_ACTION: "auto" # activates the scene
|
||
TILE6_LONGPRESS: "none"
|
||
TILE6_VALUE_MODE: "text" # always shows LABEL_ON for scenes
|
||
TILE6_LABEL_OFF: "Scene"
|
||
TILE6_LABEL_ON: "Scene"
|
||
# colors — green theme
|
||
TILE6_CIRCLE_ACTIVE_COLOR: "0x4CAF50"
|
||
TILE6_CIRCLE_DISABLED_COLOR: "0x7B7B6F"
|
||
TILE6_ICON_ACTIVE_COLOR: "0xFFFFFF"
|
||
TILE6_ICON_DISABLED_COLOR: "0x4CAF50"
|
||
TILE6_BG_ACTIVE_COLOR: "0xFFFFFF"
|
||
TILE6_BG_DISABLED_COLOR: "0x939391"
|
||
TILE6_TITLE_ACTIVE_COLOR: "0x000000"
|
||
TILE6_TITLE_DISABLED_COLOR: "0xFFFFFF"
|
||
TILE6_VALUE_ACTIVE_COLOR: "0x7A7A7C"
|
||
TILE6_VALUE_DISABLED_COLOR: "0xD9D9D9"
|
||
# advanced
|
||
TILE6_TAP_SERVICE: ""
|
||
TILE6_TAP_PARAM_KEY: ""
|
||
TILE6_TAP_PARAM_VAL: ""
|
||
TILE6_LONGPRESS_SLIDER: "auto"
|
||
TILE6_LONGPRESS_OFF_VALUE: "0"
|
||
TILE6_LONGPRESS_ACTION: ""
|
||
TILE6_LONGPRESS_ACTION_TYPE: ""
|
||
TILE6_LONGPRESS_ACTION_SERVICE: ""
|
||
```
|
||
|
||
---
|
||
|
||
### Script — run on tap
|
||
|
||
```yaml
|
||
TILE6_ENTITY: "script.good_morning"
|
||
TILE6_STATE_ENTITY: "script.good_morning"
|
||
TILE6_TITLE: "Morning"
|
||
TILE6_ICON: "\U000F0A72" # mdi:weather-sunny
|
||
TILE6_TYPE: "script"
|
||
TILE6_TAP_ACTION: "auto" # runs the script
|
||
TILE6_LONGPRESS: "none"
|
||
TILE6_VALUE_MODE: "text"
|
||
TILE6_LABEL_OFF: "Run"
|
||
TILE6_LABEL_ON: "Run"
|
||
# colors — orange theme
|
||
TILE6_CIRCLE_ACTIVE_COLOR: "0xFF6F00"
|
||
TILE6_CIRCLE_DISABLED_COLOR: "0x7B7B6F"
|
||
TILE6_ICON_ACTIVE_COLOR: "0xFFFFFF"
|
||
TILE6_ICON_DISABLED_COLOR: "0xFF6F00"
|
||
TILE6_BG_ACTIVE_COLOR: "0xFFFFFF"
|
||
TILE6_BG_DISABLED_COLOR: "0x939391"
|
||
TILE6_TITLE_ACTIVE_COLOR: "0x000000"
|
||
TILE6_TITLE_DISABLED_COLOR: "0xFFFFFF"
|
||
TILE6_VALUE_ACTIVE_COLOR: "0x7A7A7C"
|
||
TILE6_VALUE_DISABLED_COLOR: "0xD9D9D9"
|
||
# advanced
|
||
TILE6_TAP_SERVICE: ""
|
||
TILE6_TAP_PARAM_KEY: ""
|
||
TILE6_TAP_PARAM_VAL: ""
|
||
TILE6_LONGPRESS_SLIDER: "auto"
|
||
TILE6_LONGPRESS_OFF_VALUE: "0"
|
||
TILE6_LONGPRESS_ACTION: ""
|
||
TILE6_LONGPRESS_ACTION_TYPE: ""
|
||
TILE6_LONGPRESS_ACTION_SERVICE: ""
|
||
```
|
||
|
||
---
|
||
|
||
### Long press — call a different entity
|
||
|
||
Short tap toggles a light; long press activates a scene.
|
||
|
||
```yaml
|
||
TILE1_ENTITY: "light.living_room"
|
||
TILE1_TYPE: "light"
|
||
TILE1_TAP_ACTION: "auto" # short tap: toggle the light
|
||
TILE1_LONGPRESS: "action" # long press: fire a different entity
|
||
# ...
|
||
TILE1_LONGPRESS_ACTION: "scene.movie_night"
|
||
TILE1_LONGPRESS_ACTION_TYPE: "scene"
|
||
TILE1_LONGPRESS_ACTION_SERVICE: "" # empty = default activate for scene
|
||
```
|
||
|
||
Short tap toggles a light; long press also toggles a different light.
|
||
|
||
```yaml
|
||
TILE1_LONGPRESS: "action"
|
||
TILE1_LONGPRESS_ACTION: "light.bedroom"
|
||
TILE1_LONGPRESS_ACTION_TYPE: "" # empty = inherits "light" from TILE1_TYPE
|
||
TILE1_LONGPRESS_ACTION_SERVICE: "light.toggle" # must set toggle explicitly, default is turn_on
|
||
```
|
||
|
||
---
|
||
|
||
## Adding a tile
|
||
|
||
All ten slots are filled. To grow the grid, add a `GRID_ROW6_Y` to every
|
||
orientation preset first (this applied to the now-removed `home-like.yaml`;
|
||
the maintained fixed-page profiles cap at ten tiles by design — see
|
||
[docs/TILES.md](docs/TILES.md)). A tile is not a single block — it is six
|
||
places. Copy tile 9 (a light with a slider) or tile 10 (a service
|
||
call) and change the number:
|
||
|
||
1. **Substitutions** — a `TILE9_*` block. Copy an existing one wholesale.
|
||
2. **Icon** — pick `TILE9_ICON` from `screen_manager/app/tile_icons.py`; the
|
||
icon fonts contain exactly that set. A glyph outside it renders as blank
|
||
space; add it there and run `tools/generate_icons.py`.
|
||
3. **Sensors** — under `sensor:` / `text_sensor:`. `ha_state_tile9` is the only
|
||
required one. Add the rest only if the tile actually uses them:
|
||
`tile9_brightness` (light), `tile9_percentage` + `tile9_preset` (fan),
|
||
`tile9_cover_position` + `tile9_cover_state` (cover),
|
||
`tile9_climate_*` (climate), `tile9_supported_color_modes` (color light).
|
||
Every subscription costs heap, so skip what the tile does not read.
|
||
4. **Widget** — an `obj` under `tile_scroll`'s `widgets:`, at
|
||
`x: ${GRID_COL1_X}` / `y: ${GRID_ROW5_Y}`. Pass `NAN` (floats) or `""`
|
||
(strings) to `open_value_overlay` for any sensor you skipped in step 3.
|
||
5. **Ack script** — a `tile9_ack` copy under `script:`.
|
||
6. **Refresh lambda** — three lines in `ui_refresh`: a `t9_on` line next to the
|
||
others, a `set_value_auto(id(t9_value), …)` call, and an `apply_tile(t9_on, …)`
|
||
call. Climate tiles also need a `sync_open_climate` line.
|
||
|
||
Watch `sensor.*_heap_free` in Home Assistant after flashing. This board has no
|
||
PSRAM, so free heap is the real ceiling on how many tiles fit.
|
||
|
||
---
|
||
|
||
## Finding Material Design Icons
|
||
|
||
1. Go to [pictogrammers.com/library/mdi](https://pictogrammers.com/library/mdi/)
|
||
2. Search for an icon name
|
||
3. Click the icon → copy the Unicode codepoint (e.g. `F0769`)
|
||
4. Format it as `"\U000F0769"` (always 8 hex digits, padded with leading zeros)
|
||
|
||
The icon fonts contain the tile icon set from `screen_manager/app/tile_icons.py` (150 icons plus the weather glyphs). An icon outside that set shows as a blank space: add it to that file and run `python3 tools/generate_icons.py` and `python3 tools/generate_packages.py`.
|