Rebuild the editor as a Vue app: sidebar, pages side by side, tile settings in a drawer (0.2.74)

The page is now web/ (Vue 3 + Vite + TypeScript), built into screen_manager/app/static
with hashed file names; server.py serves index.html as built and /assets/. The Python
API, the data and the firmware are unchanged. Your screens sit in a sidebar, the pages
of a screen stand next to each other at the screen's own shape, the library sits on the
right, and a tile's settings slide in as a drawer while the mockup stays in view. New
screen, Firmware & USB, Alerts, Override YAML and Settings are pages of their own.
Fonts moved to web/src/assets; the tests read the source through tests/editor_sources.py.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Max Gramser
2026-09-18 07:48:45 +02:00
parent 9f5694b9eb
commit 510ebdf885
72 changed files with 5486 additions and 5409 deletions
+12
View File
@@ -1,3 +1,15 @@
## 0.2.73 (firmware 0.2.61)
A new editor, built as a Vue app, with the same firmware.
- **One workspace instead of one long page.** Your screens sit in a sidebar on the left, the screen you chose fills the middle, and the entity library sits on the right. The big title, the separate Settings view and the sticky save bar are gone: **Save & send** appears in the head the moment something changed, and says *Saved · sent to screen* when it is done.
- **Tile settings in a drawer.** Tap a tile and its settings slide in from the right; the mockup stays visible, so a wider tile, another background or a direct control shows up on the page while you choose. Tap another tile and the drawer follows. Esc or a tap beside the pages closes it.
- **Pages side by side.** The pages of a screen stand next to each other, at the screen's own shape (square for a Guition, 4:3 for a CYD), the way you swipe through them. Dragging from the library onto a page and between cells works as before, with mouse and touch; drop past the last page for a new one.
- **The top bar is part of the mockup.** Tap the bar on any page to name the screen and choose its items; the drawer shows every item as the screen draws it. Adding the time, the date, the dial or an entity happens in the same drawer.
- **Screen settings as a tab** next to Layout, with the same rows as the settings page on the screen. **Read current data** and **Override YAML** live in the ··· menu of the screen; New screen, Firmware & USB, Alerts and the app Settings are pages of their own, reached from the sidebar.
- **Dark mode follows your browser**, as Home Assistant's own Auto theme does.
- Same add-on API, same data, same firmware: nothing to update on the screens. The page is now built with Vue and Vite (`web/`); its files carry a hash of their content, so an update never runs an old script against a new page.
## 0.2.72 (firmware 0.2.61)
Next, Next, Next: the page buttons keep up with your finger.
+7 -7
View File
@@ -2,7 +2,7 @@
See [the full installation guide](https://github.com/MaxGramser/homeassistant_espscreen/blob/main/docs/EASY_SETUP.md).
Open **Settings → New screen** to install a screen: connect it via USB to the
Open **New screen** in the sidebar to install a screen: connect it via USB to the
Home Assistant machine, choose the board, name and USB port, then click **Install**.
The profile with unique keys goes into the ESPHome folder of the HA configuration,
any missing Wi-Fi goes into `secrets.yaml` (existing secrets are left untouched), and the
@@ -10,26 +10,26 @@ build and flash run in the same window; it then shows the API key
for pairing. Is the Home Assistant machine out of reach of the screen, such as a server or a
virtual machine? Choose **Download** under **Install via**: ESP Screens builds the firmware and
you put it on the screen from your own computer with [ESPHome Web](https://web.esphome.io) in
Chrome or Edge. Pairing itself happens in Home Assistant under **Settings → Devices & services** (a button in the window and on the *not yet in Home Assistant* card under My screens). Each screen has its own profile. **Settings → Firmware & USB** is
Chrome or Edge. Pairing itself happens in Home Assistant under **Settings → Devices & services** (a button in the window and on the *not yet in Home Assistant* card under My screens). Each screen has its own profile. **Firmware & USB** in the sidebar is
for existing profiles: check, build or reinstall via USB, the IP address (OTA) or
Download. Existing ESPHome profiles in the HA config folder are
found automatically.
**Settings** (top right) also has the nightly firmware updates, the **Alerts** cheatsheet
**Settings** in the sidebar has the nightly firmware updates, the **Alerts** cheatsheet
(an alert on one screen, or on every screen with the `esp_screens_show_alert` event)
and **Claude**: install the ESP Screens skill for Claude Code in Home Assistant, or
download it for claude.ai, and ask Claude for the alert automation.
At the top of the editor you set the **Top bar** for each screen: the name on the left, up
Tap the bar at the top of any page in the mockup to set the **Top bar** of a screen: the name on the left, up
to six items on the right (time, analog clock, date, or an entity with an icon, such as
temperature, a door, the alarm, or "last changed"). Drag to reorder, tap
to configure; firmware 0.2.32 or newer renders them.
After pairing via the HA ESPHome integration, choose the tiles in ESP Screens.
**Tile settings** has click behavior, larger values and mini-sliders.
**Screen settings** has brightness and standby. **Inspector** helps with
Tap a tile and its settings open in a drawer on the right, with the mockup still in view: click behavior, larger values, mini-sliders, a wider tile, backgrounds.
**Screen settings**, the tab next to Layout, has brightness and standby. **Read current data** in the ··· menu of a screen helps with
missing attributes or an offline screen. New cards require firmware 0.2.0.
Each screen also has **Override YAML** for a persistent, hardware-specific
The ··· menu of a screen also has **Override YAML** for a persistent, hardware-specific
`<screen>.local.yaml` file. It is loaded after the shared package and does not
replace the managed name, credentials, Wi-Fi, OTA or package connection.
+7 -7
View File
@@ -1,7 +1,6 @@
"""HA Ingress app. HA writes: text.set_value on discovered inboxes (or the screen_message action on firmware 0.2.33+), each screen's alert actions when an alert event for every screen fires, and one persistent notification when a nightly update stops."""
import asyncio
import contextlib
import hashlib
import json
import logging
import os
@@ -1495,12 +1494,13 @@ def create_app(manager, development=False):
app = web.Application(middlewares=[guard], client_max_size=16*1024)
static = Path(__file__).parent / 'static'
# The page asks for its script and styles with a stamp of their content, so a browser that keeps old copies
# anyway (Safari did after an update) never runs an old script against a new page.
stamp = hashlib.sha1(b''.join((static / name).read_bytes() for name in ('app.js', 'style.css'))).hexdigest()[:12]
page = (static / 'index.html').read_text().replace('"static/app.js"', f'"static/app.js?v={stamp}"').replace('"static/style.css"', f'"static/style.css?v={stamp}"')
# The page is the Vite build of web/ (npm run build writes it here): index.html names its script and styles
# by a hash of their content, so a browser that keeps old copies anyway (Safari did after an update) never
# runs an old script against a new page.
page = (static / 'index.html').read_text()
async def index(request):
return web.Response(text=page, content_type='text/html')
# SCREEN_DEV reads the file every time, so a fresh `npm run build` shows up without a restart.
return web.Response(text=(static / 'index.html').read_text() if development else page, content_type='text/html')
def light_payload(screens=None):
"""Screens and update status: everything that changes while the page is open."""
if screens is None:
@@ -1674,7 +1674,7 @@ def create_app(manager, development=False):
app.router.add_get('/api/events', events)
app.router.add_put('/api/screens/{inbox}', save)
app.router.add_put('/api/screens/{inbox}/settings', change_settings)
app.router.add_static('/static/', static)
app.router.add_static('/assets/', static / 'assets')
return app
async def main():
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+4 -601
View File
@@ -3,609 +3,12 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<meta name="color-scheme" content="light dark" />
<title>ESP Screens</title>
<link rel="stylesheet" href="static/style.css" />
<script src="static/app.js" defer></script>
<script type="module" crossorigin src="./assets/index-DOjlT4hj.js"></script>
<link rel="stylesheet" crossorigin href="./assets/index-D7h6hKdu.css">
</head>
<body>
<header>
<div class="brand">
<span class="mark">▦</span>
<div>
<strong>ESP Screens</strong
><small>Tiles for your CYD and Guition, without reflashing</small>
</div>
</div>
<nav class="toolbar" aria-label="Actions">
<button id="open-settings" class="tool" type="button" aria-controls="settings-view">
<span class="tool-icon" id="open-settings-icon" aria-hidden="true">⚙</span>
<span class="tool-text"
><b id="open-settings-label">Settings</b
><small id="open-settings-hint">New screen, updates, alerts, Claude</small></span
>
</button>
</nav>
</header>
<main>
<div id="home-view">
<div class="intro">
<div>
<p class="eyebrow">HOME ASSISTANT</p>
<h1>Manage your remote screens here.</h1>
</div>
<span id="connection" role="status" class="badge">Connecting…</span>
</div>
<div class="workspace">
<aside>
<h2>My screens</h2>
<div id="screens"></div>
<div id="pending"></div>
<button class="quiet" id="refresh">↻ Refresh</button>
</aside>
<!-- Hidden until the first inventory, so neither card flashes while the page loads. -->
<section id="choose" class="empty" hidden>
<span class="empty-icon">▦</span>
<h2>Choose a screen</h2>
<p>Pick one of your screens to change its tiles, top bar and settings.</p>
</section>
<section id="empty" class="empty" hidden>
<span class="empty-icon">▦</span>
<h2>Start with a screen</h2>
<p>
Connect a CYD or Guition via USB to your Home Assistant machine.
Profile, firmware, and the first flash happen in one window.
</p>
<button id="start">Install new screen</button>
</section>
<section id="editor" hidden>
<div class="editor-head">
<div>
<p class="eyebrow" id="screen-name"></p>
<h2>Make it your screen</h2>
</div>
<div class="editor-head-actions">
<button id="open-override" class="quiet mini" type="button">Override YAML</button>
<span id="delivery" class="badge"></span>
</div>
</div>
<section class="topbar-editor" id="topbar" aria-labelledby="topbar-title">
<div class="section-title">
<h3 id="topbar-title">Top bar</h3>
<span id="topbar-count"></span>
</div>
<div class="topbar-fields">
<label class="topbar-name"
>Left: name<input
id="title"
maxlength="60"
placeholder="For example: Living room"
/></label>
<div class="topbar-right">
<span class="topbar-caption" id="topbar-caption">Right: time, sensors, or a clock</span>
<div
id="topbar-chips"
class="topbar-chips"
role="list"
aria-labelledby="topbar-caption"
></div>
</div>
</div>
<p class="hint" id="topbar-hint"></p>
</section>
<div class="columns" id="tile-section">
<div class="tile-editor">
<div class="section-title">
<h3>Your tiles</h3>
<span id="count">0 / 10</span>
</div>
<div id="layout-preview" aria-label="Screen layout"></div>
<button id="add-page" class="quiet add-page" type="button">
+ Add page
</button>
<p id="no-tiles" class="hint">
Add your first light, scene, or device via the picker.
</p>
<p id="positions-hint" class="hint" hidden></p>
</div>
<div class="picker">
<label for="search">Add an entity</label
><input
id="search"
type="search"
placeholder="Search by name, device, or room…"
autocomplete="off"
/>
<div class="filters" id="filters"></div>
<div id="results" aria-live="polite"></div>
</div>
</div>
<section class="screen-settings" id="general-settings" aria-labelledby="settings-heading">
<div class="section-title settings-title">
<h3 id="settings-heading">Screen settings</h3>
<span class="hint" id="settings-status" role="status"></span>
</div>
<div class="settings-cards" id="settings-groups"></div>
</section>
<details class="screen-settings" id="inspector-section">
<summary>
Inspector
<span class="hint"
>Connection, status, and supported properties</span
>
</summary>
<button id="inspect" class="quiet">Read current data</button>
<div id="inspection-summary"></div>
<pre id="inspection">Select a screen and read the data.</pre>
</details>
<footer class="savebar">
<div>
<strong id="dirty">All saved</strong
><small id="save-detail"
>Changes apply without reflashing.</small
>
</div>
<button id="save">Save & send to screen</button>
</footer>
</section>
</div>
</div>
<section id="settings-view" class="settings-view" hidden aria-labelledby="settings-title">
<div class="intro">
<div>
<p class="eyebrow">SETTINGS</p>
<h1 id="settings-title">Everything around your screens.</h1>
</div>
<button type="button" class="quiet" id="close-settings">← My screens</button>
</div>
<div class="settings-groups">
<section class="settings-group" aria-labelledby="settings-screens-title">
<h2 id="settings-screens-title">Screens</h2>
<p class="hint">Add a screen, or build and reinstall the firmware of one you already have.</p>
<div class="settings-tools">
<button id="new-screen" class="tool tool-primary" type="button">
<span class="tool-icon" aria-hidden="true">+</span>
<span class="tool-text"
><b>New screen</b><small>Connect and install</small></span
>
</button>
<button id="open-firmware" class="tool" type="button">
<span class="tool-icon" aria-hidden="true">⇪</span>
<span class="tool-text"
><b>Firmware & USB</b
><small>Build and install via USB or Wi-Fi</small></span
>
</button>
</div>
</section>
<section class="settings-group updates" id="updates" aria-labelledby="updates-title">
<h2 id="updates-title">Firmware updates</h2>
<p class="hint" id="updates-hint"></p>
<button id="update-all" hidden>Update all screens</button>
<label class="check">
<input type="checkbox" id="auto-update" />
<span
>Update automatically every night<small
>Between 03:00 and 06:00, one screen at a time. Stops on an
error and reports it in Home Assistant.</small
></span
>
</label>
</section>
<section class="settings-group" aria-labelledby="settings-alerts-title">
<h2 id="settings-alerts-title">Alerts</h2>
<p class="hint">
A card over the whole screen from an automation, on one screen or on all of them.
The cheatsheet has the action names, fields, icons, and colors.
</p>
<div class="settings-tools">
<button id="open-alerts" class="tool" type="button">
<span class="tool-icon" aria-hidden="true">!</span>
<span class="tool-text"
><b>Alerts</b
><small>Full-screen notifications, from an automation</small></span
>
</button>
</div>
</section>
<section class="settings-group" id="claude" aria-labelledby="claude-title">
<h2 id="claude-title">Claude</h2>
<p class="hint">
Teach Claude about ESP Screens, then ask: "Show an alert on all my screens when the
mailbox is full." Claude knows the alert events, every field, color, and icon.
</p>
<div class="claude-skill">
<button type="button" id="claude-install">Install for Claude Code</button>
<span id="claude-status" class="hint" role="status"></span>
</div>
<small>
For Claude Code in Home Assistant. Writes one file to
<code id="claude-path">/homeassistant/.claude/skills/esp-screens</code>; installing
again replaces it.
</small>
<div class="claude-skill">
<a class="button again" id="claude-download" href="api/claude-skill.zip" download="esp-screens.zip">Download for claude.ai</a>
<small>Upload the zip in Claude under Customize → Skills.</small>
</div>
</section>
</div>
</section>
</main>
<dialog id="installer">
<form id="install-form">
<div class="dialog-head">
<div>
<p class="eyebrow">NEW SCREEN</p>
<h2 id="install-title">Connect and install.</h2>
</div>
<button
type="button"
class="quiet"
id="close-install"
aria-label="Close"
>
✕
</button>
</div>
<div id="install-setup">
<p>
ESP Screens creates the screen's own profile with unique keys and
builds the firmware. Connect the screen with a USB data cable to the
machine running Home Assistant, or download the firmware and put it
on the screen from your own computer.
</p>
<fieldset>
<legend>Which screen do you have?</legend>
<label class="board"
><input type="radio" name="board" value="cyd" checked /><span
><b>CYD · 2.8 inch</b
><small>ESP32-2432S028 · 320 × 240</small></span
></label
><label class="board"
><input type="radio" name="board" value="guition" /><span
><b>Guition · 4 inch</b
><small>ESP32-S3-4848S040 · 480 × 480 · GT911</small></span
></label
>
</fieldset>
<label
>Name<input
name="friendly_name"
required
maxlength="60"
placeholder="Living room screen"
autocomplete="off" /><small class="node-line"
>Device name <code id="node-preview">screen</code
><button type="button" class="link" id="edit-node">
customize
</button></small
><small
>Every screen gets its own profile with its own keys. Four
screens? Go through this four times with a different name.</small
></label
>
<label id="node-label" hidden
>Device name<input
name="name"
pattern="[a-z][a-z0-9\-]{0,29}"
maxlength="30"
autocomplete="off" /><small
>Lowercase letters, digits, and dashes. A different name for
each screen.</small
></label
>
<fieldset id="wifi-fields" class="wifi" hidden disabled>
<legend>Wi-Fi</legend>
<p class="hint" id="wifi-status"></p>
<label id="wifi-ssid-label"
>Wi-Fi name (2.4 GHz)<input name="wifi_ssid" autocomplete="off"
/></label>
<label id="wifi-password-label"
>Wi-Fi password<input
name="wifi_password"
type="password"
autocomplete="new-password"
/></label>
</fieldset>
<label
>Install via<select name="target" id="install-target"></select
><small id="target-hint"></small
></label>
<p class="hint" id="install-note"></p>
<div class="install-actions">
<button type="submit" id="install-go">Install</button>
<span id="install-status" role="status"></span>
</div>
</div>
<div id="install-progress" hidden>
<div class="progress-head">
<span class="spin" id="progress-spin"></span>
<span class="outcome" id="progress-mark" hidden></span>
<strong id="progress-title"></strong>
</div>
<p id="progress-detail"></p>
<div id="install-download" class="download-box" hidden>
<a class="button" id="download-firmware" href="">Download firmware</a>
<ol class="steps" id="download-steps"></ol>
<small>The file holds your Wi-Fi password and the screen's keys: keep it to yourself.</small>
</div>
<div id="install-result" hidden>
<div class="key-box">
<span>API key</span><code id="api-key"></code>
<button type="button" class="mini" id="copy-key">Copy</button>
</div>
<ol class="steps" id="install-steps"></ol>
</div>
<details id="install-log-wrap">
<summary>ESPHome log</summary>
<pre id="install-log"></pre>
</details>
<div class="install-actions">
<button type="button" id="install-retry" hidden>
Retry
</button>
<button type="button" class="quiet" id="install-close">
Close
</button>
</div>
</div>
</form>
</dialog>
<dialog id="firmware-dialog">
<div class="dialog-head">
<div>
<p class="eyebrow">FIRMWARE & USB</p>
<h2>Build and install screen firmware</h2>
</div>
<button id="close-firmware" class="quiet" aria-label="Close">✕</button>
</div>
<p>
The built-in ESPHome CLI uses your own profile (YAML with keys)
and secrets. Choose the screen's profile, then a USB port (screen
connected to the Home Assistant machine), <b>Wi-Fi / OTA</b> with the hostname,
or <b>Download</b> to put the firmware on the screen from your own computer.
<b>Check</b> only validates, <b>Build only</b> compiles,
<b>Build & install</b> puts the firmware on the screen. Your tiles
stay as they are in ESP Screens. The first build takes a few minutes.
</p>
<label>ESPHome profile<select id="firmware-file"></select></label>
<label
>Install to<select id="firmware-port">
<option value="ota">Wi-Fi / OTA</option>
</select></label
>
<label id="firmware-host-label"
>IP address or hostname<input
id="firmware-host"
placeholder="screen-livingroom.local"
/></label>
<div class="yaml-actions">
<button id="firmware-validate" class="quiet">Check</button
><button id="firmware-build" class="quiet">Build only</button
><button id="firmware-install">Build & install</button>
</div>
<p id="firmware-status" role="status"></p>
<div id="firmware-download" class="download-box" hidden>
<a class="button" id="firmware-download-link" href="">Download firmware</a>
<small>
Put it on the screen with
<a href="https://web.esphome.io/?dashboard_install" target="_blank" rel="noopener">ESPHome Web</a>
in Chrome or Edge: Connect, choose the screen's USB port, Install, and select this file.
It holds your Wi-Fi password and the screen's keys: keep it to yourself.
</small>
</div>
<pre id="firmware-log"></pre>
</dialog>
<dialog id="override-dialog" class="override-dialog" aria-labelledby="override-title">
<div class="dialog-head">
<div>
<p class="eyebrow">ADVANCED · LOCAL OVERRIDE</p>
<h2 id="override-title">Override YAML</h2>
</div>
<button id="close-override" class="quiet" type="button" aria-label="Close">✕</button>
</div>
<p class="override-intro">
This small file is yours. It is loaded after the shared screen package and stays in place when
ESP Screen Manager updates. Change hardware-specific details here, such as a display model.
</p>
<div class="override-notice">
<span class="override-icon" aria-hidden="true">⌘</span>
<div>
<strong>What is safe to change?</strong>
<span>Display, touchscreen, substitutions, pins and other device details. Name, Wi-Fi, API, OTA and package links remain managed.</span>
</div>
</div>
<div class="override-file-row">
<span id="override-file" class="override-file"></span>
<span id="override-state" class="badge"></span>
</div>
<div class="yaml-editor" id="yaml-editor-wrap">
<div id="override-gutter" class="yaml-gutter" aria-hidden="true">1</div>
<textarea id="override-editor" spellcheck="false" autocapitalize="off" autocomplete="off" autocorrect="off"
aria-label="Local override YAML" placeholder="# Example\ndisplay:\n - id: !extend my_display\n model: ST7789V"></textarea>
</div>
<div class="override-tools">
<button id="override-example" class="quiet mini" type="button">Use example</button>
<button id="override-empty" class="quiet mini" type="button">Clear</button>
<span id="override-count" class="hint"></span>
</div>
<p id="override-status" class="override-status" role="status"></p>
<div class="yaml-actions override-actions">
<button id="override-check" class="quiet" type="button">Save & check</button>
<button id="override-save" type="button">Save override</button>
</div>
</dialog>
<dialog id="tile-sheet" class="tile-sheet" aria-label="Configure tile"></dialog>
<dialog id="topbar-sheet" class="tile-sheet" aria-label="Top bar"></dialog>
<dialog id="alerts-dialog" class="alerts" aria-label="Alerts">
<div class="dialog-head">
<div>
<p class="eyebrow">ALERTS · CHEATSHEET</p>
<h2>A full-screen notification, from an automation.</h2>
</div>
<button id="close-alerts" class="quiet" aria-label="Close">✕</button>
</div>
<p>
Every screen has the <code>show_alert</code> action. It places a card over everything,
wakes the screen, and keeps the backlight at normal brightness until someone taps
the button or the timeout runs out. Home Assistant itself shows no explanation or
dropdowns for ESPHome actions; everything you can fill in is listed here.
</p>
<div class="alert-hero">
<div class="alert-mock" id="alert-mock" aria-hidden="true">
<div class="alert-mock-card">
<span class="mdi alert-mock-icon" id="alert-mock-icon"></span>
<strong id="alert-mock-title">Someone is at the door</strong>
<span id="alert-mock-subtitle">Door 3, back</span>
<button type="button" id="alert-mock-button" tabindex="-1">Coming</button>
</div>
</div>
<nav class="alerts-nav" aria-label="Sections">
<button type="button" data-jump="alerts-screens">Your screens</button>
<button type="button" data-jump="alerts-howto">In an automation</button>
<button type="button" data-jump="alerts-all">All screens</button>
<button type="button" data-jump="alerts-fields">The fields</button>
<button type="button" data-jump="alerts-icons">Icons</button>
<button type="button" data-jump="alerts-colors">Colors</button>
<button type="button" data-jump="alerts-behaviour">Behavior</button>
<button type="button" data-jump="alerts-events">Events</button>
<button type="button" data-jump="alerts-tips">Tips</button>
</nav>
</div>
<section id="alerts-screens">
<h3>Your screens</h3>
<p>
Every screen has its own action, with the device name in it. From firmware
<code id="alerts-min-firmware">0.2.31</code>; update an older screen with its
Update button under My screens.
</p>
<div id="alerts-screen-list"></div>
</section>
<section id="alerts-howto">
<h3>In an automation</h3>
<ol class="steps">
<li><b>Add action</b> and search for <b>ESPHome</b>. Choose your screen's action:
Home Assistant calls it "Performs the action show_alert of the node
<i>device name</i>".</li>
<li><b>Fill in the fields.</b> Home Assistant asks for all seven; leave what you don't
use empty (<code>""</code>, <code>0</code>, off).</li>
<li>Prefer YAML? Choose <b>Edit in YAML</b> on the action and paste the example
below.</li>
</ol>
<div class="alert-example">
<label
>Example for<select id="alerts-example-screen"></select
></label>
<div class="copy-line">
<pre id="alerts-example"></pre>
<button type="button" class="mini" id="alerts-example-copy">Copy YAML</button>
</div>
</div>
</section>
<section id="alerts-all">
<h3>All screens at once</h3>
<p>
Fire the event <code id="alerts-all-event">esp_screens_show_alert</code> with the same
fields, and ESP Screens passes the alert on to every screen that is online, including
screens you add later. <code id="alerts-all-dismiss">esp_screens_dismiss_alert</code>
clears it everywhere. In an automation, add the <b>Event</b> action or paste the example
under <b>Edit in YAML</b>. Leave out the fields you don't use. ESP Screens has to be
running for this.
</p>
<div class="copy-line">
<pre id="alerts-all-example"></pre>
<button type="button" class="mini" id="alerts-all-copy">Copy YAML</button>
</div>
</section>
<section id="alerts-fields">
<h3>The fields</h3>
<p>
Text is free-form; the limit is in bytes, and an accented letter counts as two.
What doesn't fit gets an ellipsis (title) or is dropped (subtitle).
</p>
<div class="table-scroll"><table id="alerts-field-table"></table></div>
</section>
<section id="alerts-icons">
<h3>Icons</h3>
<p>
Fill in the name in <code>icon</code>, for example <code>doorbell</code>.
<code>mdi:doorbell</code> and the hex codepoint (<code>F12E6</code>) also work.
Only these icons are included in the firmware; any other name shows the
warning triangle. Tap an icon to copy its name.
</p>
<p class="alerts-subhead">Handy for notifications</p>
<div class="chips" id="alerts-suggested"></div>
<label class="alerts-search"
>Search for an icon<input
id="alerts-icon-search"
type="search"
placeholder="Search by name or description…"
autocomplete="off"
/></label>
<div id="alerts-icon-groups"></div>
</section>
<section id="alerts-colors">
<h3>Colors</h3>
<p>
Fill in the name in <code>color</code>. These are the pastel shades of the tiles,
with dark text. Empty or unknown gives the white card. Tap to copy.
</p>
<div class="swatches" id="alerts-swatches"></div>
</section>
<section id="alerts-behaviour">
<h3>Behavior</h3>
<ul class="alerts-list">
<li><b>Wakes the screen.</b> An alert immediately wakes a dimmed or dark screen and
appears above every page, every open light card, and the standby layer.</li>
<li><b>On until the button.</b> As long as the card is showing, the backlight stays at
normal brightness. Standby and night hours wait. After the button, the regular
standby time starts again.</li>
<li><b>Timeout.</b> <code>timeout: 0</code> waits for the button, however long that
takes. With <code>timeout: 60</code> the card disappears after a minute, but the
button closes it sooner.</li>
<li><b>Blinking.</b> <code>flash: true</code> blinks the backlight four times
when the alert arrives (about a second) and leaves the screen on afterward.</li>
<li><b>Replacing.</b> A new alert replaces the current one; there's no stack.
The replaced alert reports itself as <code>replaced</code>.</li>
<li><b>Closing remotely.</b> <code>dismiss_alert</code> clears the card,
for example if the door is already open. Without an alert, that action does nothing.</li>
<li><b>Tapping beside the card</b> does nothing; only the button closes it. That way a
wake-up tap never accidentally dismisses the alert.</li>
</ul>
</section>
<section id="alerts-events">
<h3>Events</h3>
<p>
Every end fires the event <code id="alerts-event-name">esphome.screen_alert</code>
with <code>action</code>, <code>title</code>, <code>screen</code> (the device name)
and the <code>device_id</code> that Home Assistant adds. Visible under
Settings → Tools → Events.
</p>
<div class="table-scroll"><table id="alerts-ending-table"></table></div>
<p class="alerts-subhead">Waiting until someone presses the button</p>
<div class="copy-line">
<pre id="alerts-wait-example"></pre>
<button type="button" class="mini" id="alerts-wait-copy">Copy YAML</button>
</div>
</section>
<section id="alerts-tips">
<h3>Tips</h3>
<ul class="alerts-list">
<li>Use a <b>color per kind of notification</b>: orange for the door, red for
smoke or water, green for "done". The text always stays dark and readable.</li>
<li>Keep the title <b>short</b>; a screen shows about twenty characters on one line and
ends a longer title with an ellipsis. Put details in the subtitle.</li>
<li>A <b>custom button text</b> turns the notification into a question: "Coming", "Seen",
"Turn off". The event then tells you who responded.</li>
<li>For an alert that resolves itself (the door opens, the laundry gets taken out)
close it in the same automation with <code>dismiss_alert</code>.</li>
<li>Every screen? Fire <code>esp_screens_show_alert</code> once (see All screens at
once). The screens still work independently and each reports with its own
<code>screen</code>.</li>
<li>Rather <b>ask Claude</b> for the automation? Install the ESP Screens skill under
Settings → Claude.</li>
</ul>
</section>
</dialog>
<div id="toast" role="status" hidden></div>
<div id="app"></div>
</body>
</html>
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,5 +1,5 @@
name: ESP Screen Manager
version: "0.2.72"
version: "0.2.73"
slug: esp_screen_manager
description: Choose tiles for your CYD and Guition touchscreen, without reflashing.
url: https://github.com/MaxGramser/homeassistant_espscreen