Add readable pastel tile backgrounds and refresh setup documentation

This commit is contained in:
Max Gramser
2026-09-12 18:48:49 +02:00
parent ed6192e4dc
commit b327010025
20 changed files with 370 additions and 92 deletions
+127 -10
View File
@@ -1,17 +1,132 @@
# Home Assistant ESP Screens
**Nieuw scherm installeren? Begin met [Easy Setup](docs/EASY_SETUP.md).**
Installeer ESP Screen Manager in Home Assistant, download de YAML voor CYD of
Guition, bouw en flash vanuit dezelfde app via USB op je Raspberry en kies je tegels in de beheerpagina.
Zoeken op entiteit/apparaat/ruimte, slepen, opslaan — zonder opnieuw flashen.
Een Home Assistant-bedieningsscherm dat je zelf indeelt. **ESP Screen Manager**
beheert je tegels én bouwt en installeert de ESPHome-firmware vanuit Home Assistant.
Geen blueprint, MQTT of long-lived token nodig voor normaal gebruik.
Updates van de app behouden je indelingen. Nieuwe firmware installeer je via
ESPHome OTA met behoud van je eigen naam, wifi en sleutels.
Zie [de nieuwe kaarten, inspector en firmwarepagina](docs/WHATS_NEW_020.md) en
[updates publiceren](docs/RELEASING.md).
**Nieuw scherm? Volg de [complete installatiehandleiding](docs/EASY_SETUP.md).**
Voor elke nieuwe gebruiker en elk nieuw apparaat maak je een eigen profiel.
De handleiding hieronder blijft beschikbaar voor handmatige installatie via een
computer. Voor de handmatige Guition-route: [Guition](docs/GUITION.md).
## Ondersteunde schermen
| Scherm | Resolutie | Display / touch |
| --- | --- | --- |
| CYD ESP32-2432S028 | 320 × 240 | ILI9341 / resistieve XPT2046 |
| Guition ESP32-S3-4848S040, 4 inch | 480 × 480 | ST7701S RGB / capacitieve GT911 |
Gebruik deze exacte bordvarianten: gelijkende productnamen kunnen andere
controllers of aansluitingen hebben. Wallbox-relais worden niet aangestuurd.
De firmware en ingebouwde CLI zijn getest met **ESPHome 2026.6.2**.
## Wat je kunt instellen
- **Tot twintig tegels**, verdeeld over maximaal vier vaste pagina's met zes
tegels. Zoek op entiteit, apparaat of ruimte en sleep om te ordenen.
- **Instellingen per tegel:** eigen naam, klikgedrag, een kleine slider waar
ondersteund, of een grote waarde voor bijvoorbeeld temperatuur en verbruik.
- **Pastel achtergronden per tegel:** kies rood voor een alles-uit-script,
groen voor alles-aan, of een andere kleur. Titel en status blijven donker en
leesbaar. De kleur verschijnt ook in het schermvoorbeeld; **Standaard** herstelt
de normale kleuren. Vereist firmware 0.2.10 of nieuwer.
- **Lampbediening:** helderheid, regenboogkleur en wittemperatuur volgens de
mogelijkheden van de lamp. Open de detailbediening met een lange aanraking.
- **Meer kaarten:** climate, vacuum, fan, cover, media player, sensoren,
select/input_select, number/input_number, schakelaars, scènes, scripts en
buttons. Een sensor kan een historiekaart voor 1, 6 of 24 uur openen.
- **Scherminstellingen:** standby-tijd, normale en gedimde helderheid,
nachturen, klok, terug naar de hoofdpagina en optioneel swipen tussen pagina's.
- **Guition-rotatie:** 0°, 90°, 180° of 270°, direct vanuit de beheerpagina.
De native LVGL-rotatie draait beeld en touch samen. De CYD behoudt zijn vaste
oriëntatie en eigen kalibratie.
- **Inspector:** controleer entiteiten, status en configuratie in ESP Screens.
Actiefeedback laat zien dat een opdracht onderweg is.
Functies hangen af van de mogelijkheden die Home Assistant voor een entiteit
meldt. De app moet blijven draaien om de schermen van actuele gegevens te voorzien.
## Installeren vanuit Home Assistant
Voor Home Assistant OS met Apps/Add-ons op **aarch64 of amd64**:
1. Open de appwinkel en voeg deze repository toe:
`https://github.com/MaxGramser/homeassistant_espscreen`.
2. Installeer **ESP Screen Manager**, start de app en open **ESP Screens**.
ESPHome Device Builder is optioneel: de ESPHome-CLI zit al in deze app.
3. Kies **Nieuw scherm**, selecteer CYD of Guition en geef een unieke naam.
Gebruik **Bewaar profiel in ESP Screens**. Bestaande `wifi_ssid` en
`wifi_password` in ESPHome `secrets.yaml` worden hergebruikt; bij een verse
installatie vraagt de wizard de wifi eenmalig. API- en OTA-sleutels worden
uniek aangemaakt en in je eigen apparaat-YAML bewaard.
4. Sluit het scherm met een USB-datakabel aan op de **Home Assistant-machine**.
Open **Firmware & USB**, kies het eigen profiel en de juiste USB-poort en
start **Bouwen & installeren**. Een eerste build kan meerdere minuten duren.
5. **CYD:** doorloop de kalibratie op het scherm. **Guition:** gebruikt GT911
zonder resistieve kalibratie. Koppel daarna het ontdekte ESPHome-apparaat in
**Instellingen → Apparaten & diensten**. Gebruik bij een sleutelvraag de
`api.encryption.key` uit je eigen YAML. Geef het apparaat toestemming om
Home Assistant-acties uit te voeren.
6. Selecteer het scherm in ESP Screens, kies je tegels en klik
**Opslaan & naar scherm**. Test vervolgens de fysieke bediening.
Je kunt later vanuit **Firmware & USB → Wifi / OTA** nieuwe firmware installeren.
Gebruik voor een bestaand scherm altijd het bestaande profiel; opnieuw een
installatieprofiel aanmaken genereert nieuwe sleutels.
## Tegels en kleuren aanpassen
Open **Tegels instellen**, klik een tegel in het schermvoorbeeld en open
**Bediening & weergave instellen**. Kies bij **Pastel achtergrond** een kleur,
zoals rood of groen. Pas eventueel de naam, klikactie, mini-slider of grote
waarde aan. Klik **Opslaan & naar scherm** om de wijzigingen toe te passen.
Dit vereist na de eerste ondersteunende firmware-update geen nieuwe flash.
Een kleur is een vaste keuze voor die tegel: hij blijft dus bijvoorbeeld rood
wanneer je het alles-uit-script gebruikt. De entiteitsstatus en actiefeedback
blijven afzonderlijk zichtbaar.
## Updates en behoud van je instellingen
| Wijziging | Actie |
| --- | --- |
| Tegels, namen, kleuren, volgorde of scherminstellingen | Opslaan in ESP Screens; geen firmwareflash |
| Nieuwe versie van de beheerpagina | ESP Screen Manager updaten in de HA-appwinkel |
| Nieuwe functie op het fysieke scherm | Bestaand profiel bijwerken via Firmware & USB → Wifi / OTA |
De eigen YAML en wifi/API/OTA-instellingen blijven in de ESPHome-configmap.
Tegelindelingen en opties staan in de permanente appdata. CYD-kalibratie en
schermvoorkeuren blijven op het apparaat opgeslagen. Updates vervangen deze
gebruikersgegevens niet. Maak wel normale Home Assistant-back-ups en bewaar je
apparaatprofielen; een app verwijderen of flashgeheugen wissen is geen update.
Zie [releasegeschiedenis](screen_manager/CHANGELOG.md) en
[releases en protocolcompatibiliteit](docs/RELEASING.md).
## Handleidingen en hulp bij installatie
- [Complete installatie vanuit ESP Screens](docs/EASY_SETUP.md)
- [Guition-hardware, montage en rotatie](docs/GUITION.md)
- [CYD-kalibratie en USB-diagnose](docs/CALIBREREN.md)
- [Fysieke acceptatietest](docs/ACCEPTATIE.md)
- [Instructies voor developers en LLM's](AGENTS.md)
Geef een developer of LLM een schone kopie van deze repository en bijvoorbeeld:
> Lees AGENTS.md, README.md en docs/EASY_SETUP.md. Help me dit CYD- of
> Guition-scherm via USB op mijn Home Assistant te installeren. Identificeer
> het bord en gebruik mijn bestaande profiel als dat er al is. Begeleid
> kalibratie, HA-koppeling, tegelkeuze en fysieke tests. Houd sleutels lokaal
> en geef aan welke controles werkelijk zijn uitgevoerd.
Een build bewijst niet dat fysieke touch of het paneelbeeld goed is. De eigenaar
moet het beeld controleren en de gevraagde tikken uitvoeren.
<details>
<summary>Oudere handmatige CYD-installatie via een computer</summary>
Onderstaande route gebruikt het oudere handmatige profiel met maximaal tien
tegels. De positiebeperkingen hiervan gelden niet voor de twintig runtime-tegels
van ESP Screen Manager. Gebruik voor nieuwe installaties bij voorkeur de route
hierboven; de handmatige instructies blijven beschikbaar voor onderhoud.
# CYD Home Assistant-bedieningsscherm
@@ -234,3 +349,5 @@ Project-, ESPHome-driver- en fontlicenties staan respectievelijk in `LICENSE`,
`components/xpt2046/LICENSE` en `fonts/`. Historische borddiagnose staat in
[CYD_STABILITY.md](CYD_STABILITY.md); volg voor een **nieuwe** installatie de
handleidingen hierboven.
</details>
+1 -1
View File
@@ -36,7 +36,7 @@ struct Tile {
std::array<float,24> history{};
bool has_history = false;
float battery = NAN, volume = NAN;
uint32_t supported = 0;
uint32_t supported = 0, background = 0;
std::string revision, pending_revision;
uint32_t pending_since = 0;
bool pending = false, confirmed = false, local_feedback = false;
+16 -7
View File
@@ -1,5 +1,6 @@
#pragma once
#include "runtime_model.h"
#include "tile_palette.h"
#include "screen_settings.h"
#include "esphome/core/preferences.h"
#include "cyd_ui.h"
@@ -136,6 +137,7 @@ inline std::string receive(const std::string &payload) {
std::string revision = string(root["state"]); serializeJson(a, revision);
tile.observe(revision);
auto options = root["o"];
tile.background = tile_palette::color(string(options["background"],16));
tile.tap = string(options["tap"]); if (tile.tap.empty()) tile.tap="auto";
tile.display = string(options["display"]); if (tile.display.empty()) tile.display="standard";
tile.inline_control = string(options["inline"]); if (tile.inline_control.empty()) tile.inline_control="none";
@@ -531,19 +533,20 @@ inline void render(lv_obj_t *room) {
auto color=lv_color_hex(accent);
if(t.domain()=="light" && on && t.has_hs_color)
color=lv_color_hsv_to_rgb(t.hue%360,t.saturation,100);
auto circle_color=available?lv_color_mix(color,lv_color_hex(light_theme?0xFFFFFF:0x263B50),light_theme?38:65):lv_color_hex(light_theme?0xF0F0F0:0x263B50);
bool dark_text=light_theme || t.background!=0;
auto circle_color=available?lv_color_mix(color,lv_color_hex(dark_text?0xFFFFFF:0x263B50),dark_text?38:65):lv_color_hex(dark_text?0xF0F0F0:0x263B50);
// Darken the foreground slightly: very pale bulbs still need a visible icon.
auto icon_color=available?lv_color_mix(color,lv_color_hex(light_theme?0x333333:0xFFFFFF),light_theme?205:185):lv_color_hex(0x9E9E9E);
auto icon_color=available?lv_color_mix(color,lv_color_hex(dark_text?0x333333:0xFFFFFF),dark_text?205:185):lv_color_hex(0x9E9E9E);
lv_obj_set_style_bg_color(w.slider,color,LV_PART_INDICATOR);
lv_obj_set_style_bg_color(w.slider,lv_color_mix(color,lv_color_hex(light_theme?0xFFFFFF:0x263B50),30),LV_PART_MAIN);
lv_obj_set_style_bg_color(w.tile, lv_color_hex(light_theme ? 0xFFFFFF : (on ? 0xF5F1E8 : 0x526C85)), 0);
lv_obj_set_style_bg_color(w.slider,lv_color_mix(color,lv_color_hex(dark_text?0xFFFFFF:0x263B50),30),LV_PART_MAIN);
lv_obj_set_style_bg_color(w.tile, lv_color_hex(t.background ? t.background : (light_theme ? 0xFFFFFF : (on ? 0xF5F1E8 : 0x526C85))), 0);
lv_obj_set_style_border_width(w.tile, 1, 0);
lv_obj_set_style_border_opa(w.tile, LV_OPA_COVER, 0);
lv_obj_set_style_border_color(w.tile, lv_color_hex(light_theme ? 0xDDDDDD : (on ? 0xF5F1E8 : 0x9CB3C8)), 0);
lv_obj_set_style_border_color(w.tile, t.background ? lv_color_mix(lv_color_hex(t.background),lv_color_hex(0x000000),220) : lv_color_hex(light_theme ? 0xDDDDDD : (on ? 0xF5F1E8 : 0x9CB3C8)), 0);
lv_obj_set_style_bg_color(w.circle,circle_color,0);
lv_obj_set_style_text_color(w.icon,icon_color,0);
lv_obj_set_style_text_color(w.title, lv_color_hex(light_theme ? 0x1B1B1B : (on ? 0x172232 : 0xF3F5F7)), 0);
lv_obj_set_style_text_color(w.value, lv_color_hex(light_theme ? 0x616161 : (on ? 0x46525E : 0xF0F4F8)), 0);
lv_obj_set_style_text_color(w.title, lv_color_hex(dark_text ? 0x1B1B1B : (on ? 0x172232 : 0xF3F5F7)), 0);
lv_obj_set_style_text_color(w.value, lv_color_hex(t.background ? 0x46525E : (light_theme ? 0x616161 : (on ? 0x46525E : 0xF0F4F8))), 0);
}
}
@@ -563,6 +566,12 @@ inline bool check_tile_geometry() {
fits=fits && value.y2<track.y1 && track.y2<=content.y2;
}
if(!fits)ESP_LOGE("ui_test","Tile geometry FAIL slot=%u title_y=%d..%d value_y=%d..%d content_y=%d..%d",(unsigned)w.index,title.y1,title.y2,value.y1,value.y2,content.y1,content.y2);
if(w.index<model.count && model.tiles[w.index].background){
bool palette_ok=lv_color_eq(lv_obj_get_style_bg_color(w.tile,LV_PART_MAIN),lv_color_hex(model.tiles[w.index].background)) &&
lv_color_eq(lv_obj_get_style_text_color(w.title,LV_PART_MAIN),lv_color_hex(0x1B1B1B));
if(!palette_ok)ESP_LOGE("ui_test","Tile palette FAIL slot=%u",(unsigned)w.index);
fits=fits && palette_ok;
}
ok=ok && fits;
}
return ok;
+19
View File
@@ -0,0 +1,19 @@
#pragma once
#include <cstdint>
#include <string>
namespace tile_palette {
// Match the editor palette; all backgrounds are chosen for dark text.
inline uint32_t color(const std::string &name) {
if(name=="red")return 0xFADADD;
if(name=="orange")return 0xFFE1C6;
if(name=="yellow")return 0xFFF0C2;
if(name=="green")return 0xD9EEDC;
if(name=="mint")return 0xD5F0EA;
if(name=="blue")return 0xD9EAFB;
if(name=="purple")return 0xE9DDF5;
if(name=="pink")return 0xF7DDEC;
if(name=="gray")return 0xE5E7EB;
return 0; // Automatic/default, including unknown future palette names.
}
}
+50 -58
View File
@@ -1,12 +1,6 @@
# Installeren vanuit ESP Screens (vanaf 0.2.0)
# Installeren en beheren vanuit ESP Screens
De makkelijkste route is nu één app: **ESP Screen Manager**. Deze kan zelf
ESPHome-profielen bewaren, bouwen en via USB of OTA installeren. Zie de
[complete stappen voor deze route](WHATS_NEW_020.md#firmware-zonder-een-tweede-beheerpagina).
De instructies hieronder blijven bruikbaar als je ESPHome Device Builder wilt
blijven gebruiken. Beide routes behouden dezelfde eigen YAML en secrets.
# Een nieuw scherm, van USB naar dagelijks gebruik
Een nieuw scherm, van USB naar dagelijks gebruik
Met **ESP Screen Manager** kies je je tegels in Home Assistant. Je zoekt op
naam, apparaat, ruimte of entity-ID, zet ze in de gewenste volgorde en klikt
@@ -14,7 +8,8 @@ op **Opslaan & naar scherm**. Daarna blijft de status automatisch actueel.
Je hoeft voor andere tegels **niet opnieuw te flashen**.
Dit werkt met Home Assistant OS op een 64-bits Raspberry Pi of een amd64-machine,
ESPHome Device Builder en een van deze exacte schermvarianten:
en een van deze exacte schermvarianten. De ESPHome-CLI zit in ESP Screen Manager;
ESPHome Device Builder is optioneel:
| Keuze | Hardware |
| --- | --- |
@@ -25,63 +20,55 @@ Andere schermen met ongeveer dezelfde naam kunnen andere pinnen hebben. Gebruik
het bordprofiel dat bij de hardware hoort. Gebruik een USB-kabel die data ondersteunt.
De wallbox-relais worden niet gebruikt.
## 1. Installeer de twee apps
## 1. Installeer ESP Screen Manager
1. Open **Instellingen → Apps → Installeer een app** (in oudere HA-versies:
**Instellingen → Add-ons → Add-onwinkel**).
2. Installeer **ESPHome Device Builder**, start deze en zet hem in de zijbalk.
Gebruik ESPHome **2026.6.2 of nieuwer**. De release is met 2026.6.2 getest.
3. Open in de appwinkel het menu rechtsboven → **Repositories**. Voeg toe:
2. Open het menu rechtsboven → **Repositories** en voeg toe:
`https://github.com/MaxGramser/homeassistant_espscreen`.
4. Zoek **ESP Screen Manager**, installeer en start deze. Zet **Starten bij
opstarten** en **Tonen in zijbalk** aan. Open de webinterface.
3. Installeer en start **ESP Screen Manager**. Zet **Starten bij opstarten**
en **Tonen in zijbalk** aan. Open de webinterface **ESP Screens**.
De beheerpagina draait binnen Home Assistant en gebruikt je HA-aanmelding.
Je hoeft geen extra gebruiker, MQTT, blueprint of long-lived token in te stellen.
Installeer voor normaal gebruik de GitHub-versie: een handmatig gekopieerde lokale
test-add-on ontvangt geen updates uit GitHub.
Deze app bevat de geteste ESPHome 2026.6.2-CLI en draait binnen je HA-aanmelding.
Een tweede ESPHome-beheerpagina, MQTT, blueprint of long-lived token is niet nodig.
Gebruik de GitHub-versie voor updates; een lokale test-add-on is een andere app.
## 2. Download je eigen installatie-YAML
## 2. Maak en bewaar je eigen apparaatprofiel
Klik in ESP Screens op **Nieuw scherm**. Kies CYD of Guition, een herkenbare naam
en een unieke apparaatnaam zoals `scherm-keuken`. Klik **Maak installatie-YAML**. Gebruik **Kopieer YAML** om de tekst meteen in
ESPHome te plakken, of **Download bestand**. Op een HTTP-verbinding kan Chrome
downloads blokkeren; de kopieeroptie blijft bruikbaar.
Klik **Nieuw scherm**. Kies CYD of Guition, een herkenbare naam en een unieke
apparaatnaam, bijvoorbeeld `scherm-keuken`. Klik **Bewaar profiel in ESP Screens**.
Bij **Bewaar profiel in ESP Screens** controleert de wizard automatisch de bestaande
ESPHome `secrets.yaml`. Zijn `wifi_ssid` en `wifi_password` aanwezig, dan hoef je
geen wifi in te vullen. Alleen bij een eerste installatie zonder secretsbestand
vraagt hij die gegevens één keer. Bestaande secrets worden niet overschreven.
De wizard controleert de bestaande ESPHome `secrets.yaml`. Met `wifi_ssid` en
`wifi_password` aanwezig hoef je geen wifi in te vullen. Alleen als er nog geen
secretsbestand is, vraagt de wizard je 2,4GHz-wifi eenmalig. Een bestaand bestand
met ontbrekende of ongeldige wifi-sleutels moet je eerst herstellen; het wordt
niet stilzwijgend overschreven.
Dit bestand bevat unieke API- en OTA-sleutels. Bewaar het. Maak voor ieder nieuw
scherm een nieuw bestand. Download voor een bestaand scherm niet telkens een nieuw
bestand: daarmee zou je nieuwe sleutels genereren.
Je apparaat-YAML bevat unieke API- en OTA-sleutels. Bewaar dit profiel en gebruik
het opnieuw bij updates. Voor een bestaand scherm telkens een nieuw profiel
maken genereert nieuwe sleutels en is niet de updateroute.
Open **ESPHome Device Builder → Secrets** en vul eenmaal je 2,4GHz-wifi in:
```yaml
wifi_ssid: "Jouw wifi"
wifi_password: "Jouw wifiwachtwoord"
```
Andere bestaande secrets mogen blijven staan. Gebruik geen gedeelde API-sleutel
voor alle nieuwe schermen; de gedownloade YAML bevat al een eigen sleutel.
Wil je ESPHome Device Builder gebruiken, kies dan **Maak installatie-YAML** en
kopieer/download die YAML naar een eigen apparaat daar. Beide routes gebruiken
dezelfde firmwarepakketten. Wifi blijft in ESPHome `secrets.yaml`; API- en
OTA-sleutels staan in het eigen apparaatprofiel.
## 3. Eerste flash via USB op de Raspberry
1. Klik in ESPHome op **New device**, gebruik dezelfde unieke naam en sla de
directe installatie over. Kies zo nodig ESP32 als tijdelijke wizardkeuze.
2. Klik **Edit** bij het nieuwe apparaat. Vervang de **hele inhoud** door je
gedownloade YAML en sla op. Het pakket levert zelf de juiste hardwareconfiguratie.
3. Sluit het scherm met USB aan op de Raspberry waarop Home Assistant draait.
4. Klik **Install → Plug into the computer running ESPHome Device Builder**.
Kies de USB-seriële poort van dit scherm. Bij meerdere schermen: sluit ze voor
de eerste installatie één voor één aan.
5. Wacht op een geslaagde build én upload. De eerste build kan op een Raspberry
lang duren. Laat deze afronden. Het scherm maakt daarna verbinding met wifi.
1. Sluit het scherm met een **USB-datakabel** aan op de machine waarop Home
Assistant draait. Bij meerdere borden: identificeer eerst de juiste poort,
of sluit ze voor de eerste installatie één voor één aan.
2. Open **Firmware & USB** in ESP Screens en kies het zojuist bewaarde profiel.
3. Kies bij **Installeren naar** de USB-poort van dit scherm.
4. Klik **Bouwen & installeren** en wacht op een geslaagde build én upload.
De eerste build kan op een Raspberry meerdere minuten duren.
5. Het scherm herstart en verbindt met wifi. Latere firmware-updates kunnen via
**Wifi / OTA** in dezelfde pagina, met het bestaande profiel.
Een browseroptie **Plug into this computer** bedoelt de computer waarop je browser
draait, niet de Raspberry. Kies die alleen wanneer het scherm aan die computer zit.
Een USB-kabel aan je laptop is niet zichtbaar als USB-poort van de Raspberry.
Gebruik voor die route de ESPHome-CLI op de laptop met je eigen profiel, of de
browserinstallatie van ESPHome Device Builder. De stappen hierboven gebruiken
uitsluitend ESP Screens op de HA-machine.
**CYD:** bij de eerste start verschijnt de kalibratie. Tik het zichtbare kruisje
drie keer rustig aan, houd elke tik kort vast en volg steeds het volgende kruisje.
@@ -112,7 +99,9 @@ domeinfilters met gekleurde iconen. Je kunt maximaal twintig tegels toevoegen.
Het schermvoorbeeld toont hun plaats: twee kolommen, zes tegels per pagina.
Sleep een tegel naar een andere tegel om te ordenen. Klik op een tegel voor
een eigen naam, de pijltjes voor volgorde en **Bediening & weergave instellen**:
klikgedrag, een mini-slider of een grote waarde waar ondersteund. Een lege
klikgedrag, een mini-slider of een grote waarde waar ondersteund. Kies bij
**Pastel achtergrond** een eigen kleur met donkere tekst; **Standaard** herstelt
de normale weergave. Hiervoor is firmware 0.2.10+ nodig. Een lege
tegel brengt je naar de zoekbalk; toevoegen vult de eerstvolgende vrije positie.
Het voorbeeld toont de indeling, geen live sensorwaarden.
Klik **Opslaan & naar scherm** om je wijzigingen door te sturen.
@@ -144,7 +133,7 @@ zodra het scherm terugkomt. De app moet blijven draaien voor actuele tegeldata.
| --- | --- | --- |
| Andere entiteiten, namen of volgorde | Opslaan in ESP Screens | Wifi, sleutels, kalibratie |
| Nieuwe beheerpagina/appversie | Appwinkel → ESP Screen Manager → Update | Alle indelingen in `/data/screens.json` |
| Nieuwe schermfunctie/kaart | ESPHome → bestaand apparaat → Install → Wirelessly | Eigen YAML, sleutels en CYD-kalibratie; app stuurt tegels opnieuw |
| Nieuwe schermfunctie/kaart | Firmware & USB → bestaand profiel → Wifi / OTA | Eigen YAML, sleutels en CYD-kalibratie; app stuurt tegels opnieuw |
De eigen YAML verwijst naar de firmwarepakketten in `main`. Bij een nieuwe build
haalt ESPHome de nieuwste gepubliceerde pakket- en componentcode op. Je vervangt
@@ -152,7 +141,7 @@ je eigen YAML dus niet door een nieuw downloadbestand. Wifi, naam en sleutels
staan buiten het gedeelde pakket en blijven gelijk.
Maak vóór updates een Home Assistant-back-up inclusief ESP Screen Manager en
ESPHome Device Builder. **Verwijderen/herinstalleren** van een app is niet hetzelfde
de eigen ESPHome-configuraties. **Verwijderen/herinstalleren** van een app is niet hetzelfde
als updaten; daarmee kun je de gegevensmap wissen. Houd de apparaatnaam en de
entity-ID van **Tegelinstellingen** gelijk, zodat de bestaande indeling gekoppeld blijft.
@@ -207,7 +196,9 @@ Hierna vragen wijzigingen aan deze instellingen geen nieuwe firmwareflash.
| Helderheid nacht | 0–100%, maximaal normale helderheid | 10% |
| Klok tonen | Aan/uit | Aan |
| Tijdnotatie | 24 of 12 uur, zonder AM/PM | 24 uur |
| Terug naar pagina 1 | Bij standby; anders huidige pagina onthouden | Uit |
| Terug naar pagina 1 | Sluit ook detailmenu’s bij standby | Uit |
| Vegen tussen pagina’s | Native horizontale swipe, firmware 0.2.7+ | Uit |
| Guition draaien | 0°, 90°, 180°, 270°, firmware 0.2.9+ | 0° |
Nachturen gebruiken de tijdzone van het ESPHome-apparaat en de tijd uit HA.
Zonder geldige tijd gebruikt het scherm de gewone standbyhelderheid; gelijke
@@ -226,5 +217,6 @@ Bij oudere firmware toont de beheerpagina dat eerst een update nodig is.
De tegels blijven bruikbaar. Handmatige YAML-profielen blijven hun substitutions
gebruiken; voor beheer via deze app gebruik je het Easy Setup-pakket.
De gemelde Guition-paneelstrepen worden apart onderzocht. Deze instellingenupdate
wijzigt geen displaytimings of driver en is geen bewezen oplossing voor die strepen.
De huidige Guition gebruikt de native ST7701S-configuratie; zie
[de hardwarevergelijking](GUITION_FACTORY_REFERENCE.md). Instellingen en
tegelkleuren veranderen geen paneeltimings. Controleer beeld en touch fysiek.
+8 -7
View File
@@ -39,15 +39,16 @@ alleen zichtbaar voor de Guition nadat zijn nieuwe firmware door HA is ontdekt.
De CYD blijft op zijn bestaande oriëntatie met zijn eigen kalibratie.
Zes tegels van **218 × 108 pixels** per pagina, 12px tussenruimte en een
aparte navigatiestrook. Vanaf zeven tegels verschijnt pagina twee; tot zes
verdwijnt de navigatie. Grotere letters, iconen, dimmers en kleurkeuzes; de
climatekaart heeft een grotere temperatuurweergave. Een egaal blauwgrijze
achtergrond, duidelijk omlijnde blauwe uitgeschakelde tegels en lichte actieve tegels maken
de status herkenbaar. Standby begint na tien minuten zonder aanraking.
aparte navigatiestrook. In ESP Screen Manager passen twintig tegels op maximaal
vier pagina’s; tot zes verdwijnt de navigatie. De huidige interface heeft een
lichtgrijze achtergrond, witte kaarten en gekleurde domeiniconen. Vanaf 0.2.10 kun
je per tegel een pastel achtergrond kiezen met donkere tekst. Standby begint
standaard na tien minuten zonder aanraking en is instelbaar in de beheerpagina.
De bestaande tegelacties, climatebediening en vacuumkaart zijn behouden.
De vacuumkaart blijft gekoppeld aan tegel 6. Posities 8/10 zijn eenvoudige
actietegels; zie [TEGELS.md](TEGELS.md) voor de ondersteunde bindingen.
Alle kaarttypen zijn beschikbaar op alle twintig runtime-posities. Alleen in
het oude handmatige profiel blijft de vacuumkaart op tegel 6 en hebben posities
8/10 beperkingen; zie [TEGELS.md](TEGELS.md).
## Nieuwe installatie
+10
View File
@@ -111,3 +111,13 @@ De firmware bewaart de hoek als afzonderlijke uint32 op key `0x524F5431`; de
bestaande Settings-structuur en CYD-kalibratie blijven ongewijzigd. Alleen de
Guition activeert de rotatiecallback. De diagnostische entity `Guition schermtype`
maakt deze capability herkenbaar, ook als het scherm offline of hernoemd is.
### Compatibiliteit 0.2.10
`tiles[].options.background` is een optionele paletnaam binnen opslagversie 1.
Op de draad staat dit in het bestaande `o`-object. Oudere firmware negeert het
veld; nieuwe firmware valt bij onbekende namen terug op de normale kleuren.
De app accepteert uitsluitend het lichte palet uit `TILE_BACKGROUNDS`. Een oude
editor die `background` weglaat behoudt de opgeslagen kleur voor dezelfde entity;
expliciet `auto` herstelt de standaard. Geen gewijzigde voorkeurstructuur of
sleutels, geen nieuwe firmwareflash nodig voor latere kleurkeuzes.
+24
View File
@@ -0,0 +1,24 @@
# 0.2.10 — pastel tegelkleuren en actuele documentatie
De editor levert negen lichte kleuren plus Standaard. Dezelfde paletwaarden
worden in firmware gebruikt. De gekozen achtergrond blijft vast bij een
statuswisseling; iconen, status en actiefeedback blijven de entiteit volgen.
Titels zijn bij een eigen kleur donker op zowel Guition als CYD.
## Uitgevoerd
- 51 Python-tests geslaagd, inclusief overeenkomst tussen editor- en
firmwarepalet, minimaal 7:1 titelcontrast en 4,5:1 statuscontrast, validatie
van kleuren en behoud bij appherstart/opslaan vanuit een oude editor.
- Alle negen C++-testprogramma's geslaagd; JavaScript-syntax gecontroleerd.
- Beide runtimefirmwares gebouwd met ESPHome 2026.6.2 en via OTA op de vooraf
geïdentificeerde Guition en CYD gezet. Eigen sleutels en kalibratie behouden.
- Ook beide handmatige firmwareprofielen bouwen succesvol.
- Op beide schermen met hun bestaande indeling: tien paginacontroles,
vijftig overlaycycli en de slidertest geslaagd.
- De renderdiagnose controleert bij gekleurde tegels ook de werkelijk
toegepaste LVGL-achtergrond en donkere titelkleur.
De README en Easy Setup beschrijven nu de één-app-route met de ingebouwde
ESPHome-CLI. De oude handmatige CYD-route blijft ingeklapt beschikbaar en wordt
expliciet onderscheiden van de runtime-indeling met twintig tegels.
+1 -1
View File
@@ -1,7 +1,7 @@
# Guition ESP32-S3-4848S040 / 4-inch EU wallbox, 480x480 IPS + GT911.
# Use guition-device.yaml; see docs/GUITION.md. CYD hardware is a separate profile.
substitutions:
SCREEN_FIRMWARE_VERSION: "0.2.9"
SCREEN_FIRMWARE_VERSION: "0.2.10"
DYNAMIC_TILES: "false"
DASHBOARD_INBOX_INTERNAL: "true"
DEVICE_NAME: "guition-wallbox"
+1 -1
View File
@@ -58,7 +58,7 @@
############################################################
substitutions:
SCREEN_FIRMWARE_VERSION: "0.2.9"
SCREEN_FIRMWARE_VERSION: "0.2.10"
DYNAMIC_TILES: "false"
DASHBOARD_INBOX_INTERNAL: "true"
DEVICE_NAME: "cyd-new"
+1 -1
View File
@@ -59,7 +59,7 @@
############################################################
substitutions:
SCREEN_FIRMWARE_VERSION: "0.2.9"
SCREEN_FIRMWARE_VERSION: "0.2.10"
DYNAMIC_TILES: "true"
DASHBOARD_INBOX_INTERNAL: "false"
DEVICE_NAME: "cyd-new"
+1 -1
View File
@@ -2,7 +2,7 @@
# Guition ESP32-S3-4848S040 / 4-inch EU wallbox, 480x480 IPS + GT911.
# Use guition-device.yaml; see docs/GUITION.md. CYD hardware is a separate profile.
substitutions:
SCREEN_FIRMWARE_VERSION: "0.2.9"
SCREEN_FIRMWARE_VERSION: "0.2.10"
DYNAMIC_TILES: "true"
DASHBOARD_INBOX_INTERNAL: "false"
DEVICE_NAME: "guition-new"
+6
View File
@@ -1,3 +1,9 @@
## 0.2.10
- Kies per tegel een pastel achtergrond: rood, oranje, geel, groen, mint, blauw, paars, roze of grijs. Standaard herstelt de normale kleuren. De keuze is zichtbaar in het schermvoorbeeld en werkt met donkere tekst op Guition én CYD.
- Tegelkleuren blijven behouden bij appupdates en bij opslaan vanuit een oudere beheerpagina. Installeer firmware 0.2.10 op het scherm om de kleuren weer te geven.
- README en Easy Setup beschrijven de huidige één-app-installatie, twintig tegels, inspector, rotatie en updates via de ingebouwde ESPHome-CLI.
## 0.2.9
- Guition: kies 0°, 90°, 180° of 270° onder Scherminstellingen. Na opslaan draait de interface direct mee, inclusief touch. De hoek blijft bewaard na herstart; een nieuwe flash per hoek is niet nodig.
+17 -1
View File
@@ -10,6 +10,20 @@ REPO = 'https://github.com/MaxGramser/homeassistant_espscreen'
REFS = {'cyd': 'main', 'guition': 'main'}
ATTRS = frozenset('brightness percentage current_position current_temperature temperature current_humidity min_temp max_temp target_temp_step supported_color_modes hvac_modes hs_color color_temp_kelvin min_color_temp_kelvin max_color_temp_kelvin fan_speed_list unit_of_measurement battery_level fan_speed volume_level media_title options min max step temperature_unit supported_features'.split())
TILE_BACKGROUNDS = {
'auto': {'label': 'Standaard', 'color': None},
'red': {'label': 'Rood', 'color': '#FADADD'},
'orange': {'label': 'Oranje', 'color': '#FFE1C6'},
'yellow': {'label': 'Geel', 'color': '#FFF0C2'},
'green': {'label': 'Groen', 'color': '#D9EEDC'},
'mint': {'label': 'Mint', 'color': '#D5F0EA'},
'blue': {'label': 'Blauw', 'color': '#D9EAFB'},
'purple': {'label': 'Paars', 'color': '#E9DDF5'},
'pink': {'label': 'Roze', 'color': '#F7DDEC'},
'gray': {'label': 'Grijs', 'color': '#E5E7EB'},
}
# Additive schema 1 extension. An absent object retains old firmware/YAML defaults.
SETTING_RULES = {
'standby_enabled': (True, None, None),
@@ -72,8 +86,10 @@ def validate_layout(data):
item = {'entity': tile['entity'], 'name': name.strip()}
if 'options' in tile:
options = tile['options']
if not isinstance(options, dict) or set(options) - {'tap', 'display', 'inline', 'history_hours'}:
if not isinstance(options, dict) or set(options) - {'tap', 'display', 'inline', 'history_hours', 'background'}:
raise ValueError('Onbekende tegelinstellingen.')
if 'background' in options and (not isinstance(options['background'],str) or options['background'] not in TILE_BACKGROUNDS):
raise ValueError('Kies een pastel achtergrondkleur uit het palet.')
choices = {'tap': ('auto', 'detail', 'toggle', 'none'), 'display': ('standard', 'watch'), 'inline': ('none', 'slider')}
domain = tile['entity'].split('.')[0]
for key, allowed in choices.items():
+5 -2
View File
@@ -12,7 +12,7 @@ import math
from firmware import Firmware
from aiohttp import ClientSession, ClientTimeout, WSMsgType, web
from core import discover, installation_yaml, packets, state_message, validate_layout, validate_settings
from core import TILE_BACKGROUNDS, discover, installation_yaml, packets, state_message, validate_layout, validate_settings
LOG = logging.getLogger('screen_manager')
@@ -191,6 +191,9 @@ class Manager:
raise ValueError('Rotatie vereist een Guition met firmware 0.2.9 of nieuwer.')
old_tiles = {t['entity']:t for t in self.layouts.get(inbox,{}).get('tiles',[])}
for tile in layout['tiles']:
old_options=old_tiles.get(tile['entity'],{}).get('options',{})
if 'options' in tile and 'background' not in tile['options'] and 'background' in old_options:
tile['options']['background']=old_options['background']
if 'options' not in tile and 'options' in old_tiles.get(tile['entity'],{}):
tile['options'] = old_tiles[tile['entity']]['options'].copy()
known = {e['id'] for e in self.inventory()[1]}
@@ -320,7 +323,7 @@ def create_app(manager, development=False):
for screen in screens:
screen['layout'] = manager.layouts.get(screen['id'], {'title': 'Thuis', 'tiles': []})
screen['delivery'] = manager.status.get(screen['id'], 'Kies je eerste tegels')
return web.json_response({'csrf': csrf, 'connected': manager.ha.online, 'screens': screens, 'entities': entities})
return web.json_response({'csrf': csrf, 'connected': manager.ha.online, 'screens': screens, 'entities': entities, 'backgrounds': TILE_BACKGROUNDS})
async def save(request):
manager.save(request.match_info['inbox'], await request.json())
return web.json_response({'saved': True})
+24 -1
View File
@@ -249,6 +249,8 @@ function renderPreview() {
const card = node("button", undefined, "preview-tile");
if (tile) {
const name = tile.name || inventory.entities.find(e => e.id === tile.entity)?.name || tile.entity;
const background=inventory.backgrounds?.[tile.options?.background]?.color;
if(background)card.style.backgroundColor=background;
card.append(domainBadge(tile.entity), node("strong", name));
card.draggable = true;
card.ondragstart = (e) => { dragIndex = slot; e.dataTransfer.setData("text/plain", String(slot)); };
@@ -358,6 +360,27 @@ function renderTiles() {
if (!e.target.closest("input, select, button, summary, .tile-options"))
options.open = !options.open;
};
const palette = node("fieldset", undefined, "tile-palette");
palette.append(node("legend", "Pastel achtergrond"));
const swatches = node("div", undefined, "palette-swatches");
for(const [key, choice] of Object.entries(inventory.backgrounds || {})) {
const button=node("button", undefined, "palette-choice");
button.type="button";
button.setAttribute("aria-label", `Achtergrond: ${choice.label}`);
button.setAttribute("aria-pressed", String((tile.options?.background || "auto") === key));
const sample=node("span", undefined, "palette-sample");
if(choice.color)sample.style.backgroundColor=choice.color;
else sample.classList.add("palette-auto");
button.append(sample,node("span",choice.label));
button.onclick=()=>{
tile.options={...tile.options,background:key};
for(const other of swatches.children)other.setAttribute("aria-pressed",String(other===button));
markDirty();renderPreview();
};
swatches.append(button);
}
palette.append(swatches,node("small", "Donkere tekst blijft leesbaar. Kies Standaard voor de normale kleuren. Vereist schermfirmware 0.2.10+."));
options.append(palette);
const controls = {};
const domain = tile.entity.split(".")[0];
const fields = [
@@ -803,7 +826,7 @@ async function inspect(entity) {
card.append(
node(
"small",
`Kleine slider: ${options.inline === "slider" ? "ja" : "nee"} · Weergave: ${options.display === "watch" ? "grote waarde" : "standaard"}`,
`Kleine slider: ${options.inline === "slider" ? "ja" : "nee"} · Weergave: ${options.display === "watch" ? "grote waarde" : "standaard"} · Achtergrond: ${inventory.backgrounds?.[options.background || "auto"]?.label || "Standaard"}`,
),
);
$("#inspection-summary").append(card);
+10
View File
@@ -720,3 +720,13 @@ pre {
#tiles > .selected-tile { background: #f8fafc; border-color: #aac4df; }
.picker { position: sticky; top: 16px; }
@media (max-width: 800px) { .picker { position: static; } }
.tile-palette { margin: 12px 0; padding: 12px; border: 1px solid #d8dfe5; border-radius: 12px; }
.tile-palette legend { font-weight: 650; padding: 0 5px; }
.palette-swatches { display: grid; grid-template-columns: repeat(auto-fit, minmax(66px, 1fr)); gap: 8px; margin-bottom: 10px; }
.palette-choice { display: flex; flex-direction: column; align-items: center; gap: 5px; padding: 6px; color: #1b1b1b; background: white; border: 2px solid transparent; border-radius: 10px; font-size: 12px; }
.palette-choice[aria-pressed="true"] { border-color: #1674ae; background: #edf6ff; }
.palette-choice:focus-visible { outline: 3px solid #1674ae; outline-offset: 2px; }
.palette-sample { width: 36px; height: 28px; border-radius: 7px; border: 1px solid #0002; }
.palette-auto { background: linear-gradient(135deg, #fff 50%, #e5e7eb 50%); }
.tile-palette small { color: #52616e; }
+1 -1
View File
@@ -1,5 +1,5 @@
name: ESP Screen Manager
version: "0.2.9"
version: "0.2.10"
slug: esp_screen_manager
description: Kies tegels voor je CYD en Guition touchscreen, zonder opnieuw flashen.
url: https://github.com/MaxGramser/homeassistant_espscreen
+9
View File
@@ -0,0 +1,9 @@
#include "components/smart_display/tile_palette.h"
#include <cassert>
int main() {
assert(tile_palette::color("auto")==0);
assert(tile_palette::color("")==0);
assert(tile_palette::color("unknown-future-choice")==0);
assert(tile_palette::color("red")!=0);
assert(tile_palette::color("green")!=tile_palette::color("red"));
}
+39
View File
@@ -0,0 +1,39 @@
import re
import tempfile
import unittest
from pathlib import Path
import test_portal
from core import TILE_BACKGROUNDS, validate_layout
def luminance(color):
rgb=[int(color[i:i+2],16)/255 for i in (1,3,5)]
linear=[v/12.92 if v<=0.04045 else ((v+0.055)/1.055)**2.4 for v in rgb]
return sum(v*w for v,w in zip(linear,(.2126,.7152,.0722)))
class PaletteTests(unittest.IsolatedAsyncioTestCase):
def test_palette_matches_firmware_and_has_readable_text(self):
header=(Path(__file__).resolve().parents[1]/'components/smart_display/tile_palette.h').read_text()
native=dict(re.findall(r'name=="(\w+)"\)return 0x([A-F0-9]+)',header))
expected={k:v['color'][1:] for k,v in TILE_BACKGROUNDS.items() if v['color']}
self.assertEqual(native,expected)
for color in expected.values():
for foreground,minimum in (('#1B1B1B',7),('#46525E',4.5)):
self.assertGreaterEqual((luminance('#'+color)+.05)/(luminance(foreground)+.05),minimum)
async def test_old_editor_preserves_color_and_explicit_auto_clears(self):
with tempfile.TemporaryDirectory() as tmp:
m=test_portal.ManagerTests().setup_manager(Path(tmp)/'screens.json')
layout={'title':'Thuis','tiles':[{'entity':'light.a','options':{'background':'red','inline':'slider'}}]}
m.save('text.screen',layout)
m.save('text.screen',{'title':'Nieuw','tiles':[{'entity':'light.a','options':{'inline':'none'}}]})
fresh=test_portal.ManagerTests().setup_manager(m.path)
tile=fresh.layouts['text.screen']['tiles'][0]
self.assertEqual(tile['options'],{'background':'red','inline':'none'})
await fresh.sync_one('text.screen',fresh.layouts['text.screen'])
self.assertEqual(fresh.ha.messages[1][1]['o']['background'],'red')
fresh.save('text.screen',{'title':'Nieuw','tiles':[{'entity':'light.a','options':{'background':'auto'}}]})
self.assertEqual(fresh.layouts['text.screen']['tiles'][0]['options']['background'],'auto')
def test_unapproved_colors_rejected(self):
for value in ('#000000','url(test)','unknown',None,{},42):
with self.assertRaises(ValueError):validate_layout({'title':'Thuis','tiles':[{'entity':'light.a','options':{'background':value}}]})