Add persistent native Guition rotation to screen settings

This commit is contained in:
Max Gramser
2026-09-12 18:29:06 +02:00
parent 8171629678
commit 0109bfd6d2
15 changed files with 155 additions and 12 deletions
+16 -1
View File
@@ -15,6 +15,9 @@ namespace runtime_tiles {
inline bool enabled = false; inline bool enabled = false;
inline bool light_theme = false; inline bool light_theme = false;
inline bool swipe_pages = false; inline bool swipe_pages = false;
inline uint32_t rotation = 0;
inline bool rotation_supported = false;
inline esphome::ESPPreferenceObject rotation_preference;
inline esphome::ESPPreferenceObject swipe_preference; inline esphome::ESPPreferenceObject swipe_preference;
inline Model model; inline Model model;
inline std::string inbox; inline std::string inbox;
@@ -30,6 +33,11 @@ inline void load_settings() {
swipe_preference = esphome::global_preferences->make_preference<uint32_t>(0x53575031); swipe_preference = esphome::global_preferences->make_preference<uint32_t>(0x53575031);
uint32_t swipe_saved=0; uint32_t swipe_saved=0;
if(swipe_preference.load(&swipe_saved))swipe_pages=swipe_saved==1; if(swipe_preference.load(&swipe_saved))swipe_pages=swipe_saved==1;
if(rotation_supported){
rotation_preference=esphome::global_preferences->make_preference<uint32_t>(0x524F5431);
uint32_t saved=0;
if(rotation_preference.load(&saved) && saved<=270 && saved%90==0)rotation=saved;
}
screen_settings::Settings saved; screen_settings::Settings saved;
if (settings_preference.load(&saved) && saved.valid()) screen_settings::current = saved; if (settings_preference.load(&saved) && saved.valid()) screen_settings::current = saved;
} }
@@ -94,17 +102,24 @@ inline std::string receive(const std::string &payload) {
entities.push_back(entity.as<std::string>()); entities.push_back(entity.as<std::string>());
} }
if(!root["swipe_pages"].isNull() && !root["swipe_pages"].is<bool>())return false; if(!root["swipe_pages"].isNull() && !root["swipe_pages"].is<bool>())return false;
if(!root["rotation"].isNull() && (!root["rotation"].is<unsigned>() ||
root["rotation"].as<unsigned>()>270 || root["rotation"].as<unsigned>()%90!=0))return false;
inbox = string(root["inbox"], 160); inbox = string(root["inbox"], 160);
bool changed = false; bool changed = false;
if (!model.set_layout(entities, string(root["title"], 96), changed)) return false; if (!model.set_layout(entities, string(root["title"], 96), changed)) return false;
if(root["swipe_pages"].is<bool>() && swipe_pages!=root["swipe_pages"].as<bool>()){ if(root["swipe_pages"].is<bool>() && swipe_pages!=root["swipe_pages"].as<bool>()){
swipe_pages=root["swipe_pages"].as<bool>();uint32_t saved=swipe_pages?1:0;swipe_preference.save(&saved); swipe_pages=root["swipe_pages"].as<bool>();uint32_t saved=swipe_pages?1:0;swipe_preference.save(&saved);
} }
bool rotation_changed=false;
if(rotation_supported && root["rotation"].is<unsigned>() && rotation!=root["rotation"].as<unsigned>()){
rotation=root["rotation"].as<unsigned>();rotation_preference.save(&rotation);rotation_changed=true;
}
if (!(settings == screen_settings::current)) { if (!(settings == screen_settings::current)) {
screen_settings::current = settings; screen_settings::current = settings;
settings_preference.save(&settings); // ESPHome batches flash writes; no write on keepalive. settings_preference.save(&settings); // ESPHome batches flash writes; no write on keepalive.
if (settings_changed) settings_changed(); rotation_changed=true;
} }
if(rotation_changed && settings_changed)settings_changed();
if (changed) { active_index = -1; for (auto &w : widgets) w.cached_active = -1; if (dismiss) dismiss(); } if (changed) { active_index = -1; for (auto &w : widgets) w.cached_active = -1; if (dismiss) dismiss(); }
last_received = esphome::millis(); last_received = esphome::millis();
if (layout_changed) layout_changed(); if (layout_changed) layout_changed();
+14
View File
@@ -24,6 +24,20 @@ geen `calibration.yaml` of XPT2046-correctie over.
## Interface ## Interface
### Montage en schermrotatie (runtime 0.2.9+)
Installeer Guition-firmware 0.2.9 en ESP Screen Manager 0.2.9. Open het scherm
in de beheerpagina, ga naar **Scherminstellingen** en kies bij **Scherm draaien**
0°, 90°, 180° of 270°, met de klok mee. Klik op opslaan. Een firmwareflash is
daarna niet meer nodig om de hoek te wijzigen. De instelling blijft in de appdata
en op het scherm bewaard na een herstart.
Dit gebruikt de native ESPHome/LVGL-rotatie voor beeld én touch, zonder wijzigingen
aan de paneelinitialisatie of GT911-spiegeling. Controleer na montage de vier
hoeken en de navigatie fysiek; een renderproef test geen aanrakingen. De optie is
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 Zes tegels van **218 × 108 pixels** per pagina, 12px tussenruimte en een
aparte navigatiestrook. Vanaf zeven tegels verschijnt pagina twee; tot zes aparte navigatiestrook. Vanaf zeven tegels verschijnt pagina twee; tot zes
verdwijnt de navigatie. Grotere letters, iconen, dimmers en kleurkeuzes; de verdwijnt de navigatie. Grotere letters, iconen, dimmers en kleurkeuzes; de
+10
View File
@@ -101,3 +101,13 @@ breng de indeling eerst terug tot tien of herstel hun gegevensback-up bij rollba
`settings.swipe_pages` is additief in opslagversie 1. Op de draad staat het buiten `settings.swipe_pages` is additief in opslagversie 1. Op de draad staat het buiten
het ongewijzigde elfvelden-settingsobject. De bestaande preferences blijven gelijk; het ongewijzigde elfvelden-settingsobject. De bestaande preferences blijven gelijk;
alleen swipe gebruikt een nieuwe eigen uint32-key `0x53575031`, standaard uit. alleen swipe gebruikt een nieuwe eigen uint32-key `0x53575031`, standaard uit.
### Compatibiliteit 0.2.9
Guition-rotatie is additief als `settings.rotation` in appdata, uitsluitend
0/90/180/270. Oude beheerpagina's die het veld weglaten behouden de opgeslagen
hoek. Op de draad staat `rotation` naast het ongewijzigde elfvelden-settingsobject.
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.
+23
View File
@@ -0,0 +1,23 @@
# 0.2.9 — Guition-rotatie
De beheerpagina biedt kwartslagen voor de Guition. De native ESPHome 2026.6.2
LVGL-component draait beeld en touch samen. De paneelinitialisatie, GT911-transform
en CYD-kalibratie zijn niet aangepast. De aparte opgeslagen hoek verandert de
bestaande settingsstructuur en preference-keys niet.
- 48 Python-tests geslaagd, inclusief ongeldige hoeken, behoud na appherstart en
opslaan vanuit een oude browser, bordherkenning bij offline status en behoud
van het elfvelden-wireprotocol.
- Alle acht C++-testprogramma's geslaagd; JavaScript-syntax gecontroleerd.
- Beide runtime- en beide handmatige firmwareprofielen gebouwd.
- Guition-runtime op het geïdentificeerde apparaat via OTA geïnstalleerd.
- Renderdiagnose na opdrachten voor 0°, 90°, 180° en 270°: per stand tien
paginacontroles en vijftig overlaycycli geslaagd. Deze controle bedient geen
HA-apparaten en is geen fysieke touchmeting.
De definitieve Guition-build bevat daarnaast een uitlezing van de gewenste én
werkelijk door LVGL gebruikte hoek via `ui_state`. Na de definitieve OTA-flash
en herstart meldden beide 270°: de voorkeur bleef behouden en werd toegepast.
Daarna is de testhoek weer naar 0° teruggezet. Fysieke touchacceptatie is
afzonderlijk nodig; de bestaande `tools/verify_gt911.py --rotation` ondersteunt
alle vier de hoeken.
+14 -1
View File
@@ -1,7 +1,7 @@
# Guition ESP32-S3-4848S040 / 4-inch EU wallbox, 480x480 IPS + GT911. # 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. # Use guition-device.yaml; see docs/GUITION.md. CYD hardware is a separate profile.
substitutions: substitutions:
SCREEN_FIRMWARE_VERSION: "0.2.8" SCREEN_FIRMWARE_VERSION: "0.2.9"
DYNAMIC_TILES: "false" DYNAMIC_TILES: "false"
DASHBOARD_INBOX_INTERNAL: "true" DASHBOARD_INBOX_INTERNAL: "true"
DEVICE_NAME: "guition-wallbox" DEVICE_NAME: "guition-wallbox"
@@ -617,6 +617,7 @@ esphome:
runtime_tiles::watch_font = id(headline)->get_lv_font(); runtime_tiles::watch_font = id(headline)->get_lv_font();
runtime_tiles::enabled = std::string("${DYNAMIC_TILES}") == "true"; runtime_tiles::enabled = std::string("${DYNAMIC_TILES}") == "true";
if (!runtime_tiles::enabled) return; if (!runtime_tiles::enabled) return;
runtime_tiles::rotation_supported = true;
runtime_tiles::load_settings(); runtime_tiles::load_settings();
runtime_tiles::settings_changed = []() { id(apply_screen_settings).execute(); }; runtime_tiles::settings_changed = []() { id(apply_screen_settings).execute(); };
runtime_tiles::dismiss = []() { runtime_tiles::dismiss = []() {
@@ -778,6 +779,7 @@ api:
(unsigned)(millis() - id(last_touch_ms)), id(display_dimmed)); (unsigned)(millis() - id(last_touch_ms)), id(display_dimmed));
ESP_LOGI("ui_diag", "navigation page=%d runtime_detail=%d", id(tile_page), ESP_LOGI("ui_diag", "navigation page=%d runtime_detail=%d", id(tile_page),
runtime_tiles::detail_root && !lv_obj_has_flag(runtime_tiles::detail_root, LV_OBJ_FLAG_HIDDEN)); runtime_tiles::detail_root && !lv_obj_has_flag(runtime_tiles::detail_root, LV_OBJ_FLAG_HIDDEN));
ESP_LOGI("ui_diag", "rotation=%u actual=%u", (unsigned)runtime_tiles::rotation, (unsigned)id(screen_lvgl).get_rotation());
lv_area_t nav, grid; lv_area_t nav, grid;
lv_obj_update_layout(id(home_page)->obj); lv_obj_update_layout(id(home_page)->obj);
lv_obj_get_coords(id(page_next), &nav); lv_obj_get_coords(id(page_next), &nav);
@@ -1334,6 +1336,11 @@ binary_sensor:
# - Used by the UI to display fan presets when applicable # - Used by the UI to display fan presets when applicable
# ---------------------------------------------------------- # ----------------------------------------------------------
text_sensor: text_sensor:
- platform: template
name: "Guition schermtype"
entity_category: diagnostic
update_interval: never
lambda: 'return {"guition"};'
- platform: template - platform: template
name: "Schermfirmware" name: "Schermfirmware"
entity_category: diagnostic entity_category: diagnostic
@@ -1683,6 +1690,7 @@ display:
lvgl: lvgl:
id: screen_lvgl
on_draw_start: on_draw_start:
- lambda: 'id(rendered_frames)++;' - lambda: 'id(rendered_frames)++;'
displays: displays:
@@ -4546,6 +4554,11 @@ script:
then: then:
- lambda: |- - lambda: |-
const auto &settings = screen_settings::current; const auto &settings = screen_settings::current;
if(runtime_tiles::enabled && static_cast<unsigned>(id(screen_lvgl).get_rotation())!=runtime_tiles::rotation){
cyd::touch_guard.consume();
if(lv_indev_get_act())lv_indev_wait_release(lv_indev_get_act());
id(screen_lvgl).set_rotation(static_cast<esphome::display::DisplayRotation>(runtime_tiles::rotation));
}
if (id(display_dimmed) && !settings.standby_enabled) { if (id(display_dimmed) && !settings.standby_enabled) {
id(display_dimmed) = false; id(display_dimmed) = false;
} }
+1 -1
View File
@@ -58,7 +58,7 @@
############################################################ ############################################################
substitutions: substitutions:
SCREEN_FIRMWARE_VERSION: "0.2.8" SCREEN_FIRMWARE_VERSION: "0.2.9"
DYNAMIC_TILES: "false" DYNAMIC_TILES: "false"
DASHBOARD_INBOX_INTERNAL: "true" DASHBOARD_INBOX_INTERNAL: "true"
DEVICE_NAME: "cyd-new" DEVICE_NAME: "cyd-new"
+1 -1
View File
@@ -59,7 +59,7 @@
############################################################ ############################################################
substitutions: substitutions:
SCREEN_FIRMWARE_VERSION: "0.2.8" SCREEN_FIRMWARE_VERSION: "0.2.9"
DYNAMIC_TILES: "true" DYNAMIC_TILES: "true"
DASHBOARD_INBOX_INTERNAL: "false" DASHBOARD_INBOX_INTERNAL: "false"
DEVICE_NAME: "cyd-new" DEVICE_NAME: "cyd-new"
+14 -1
View File
@@ -2,7 +2,7 @@
# Guition ESP32-S3-4848S040 / 4-inch EU wallbox, 480x480 IPS + GT911. # 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. # Use guition-device.yaml; see docs/GUITION.md. CYD hardware is a separate profile.
substitutions: substitutions:
SCREEN_FIRMWARE_VERSION: "0.2.8" SCREEN_FIRMWARE_VERSION: "0.2.9"
DYNAMIC_TILES: "true" DYNAMIC_TILES: "true"
DASHBOARD_INBOX_INTERNAL: "false" DASHBOARD_INBOX_INTERNAL: "false"
DEVICE_NAME: "guition-new" DEVICE_NAME: "guition-new"
@@ -621,6 +621,7 @@ esphome:
runtime_tiles::watch_font = id(headline)->get_lv_font(); runtime_tiles::watch_font = id(headline)->get_lv_font();
runtime_tiles::enabled = std::string("${DYNAMIC_TILES}") == "true"; runtime_tiles::enabled = std::string("${DYNAMIC_TILES}") == "true";
if (!runtime_tiles::enabled) return; if (!runtime_tiles::enabled) return;
runtime_tiles::rotation_supported = true;
runtime_tiles::load_settings(); runtime_tiles::load_settings();
runtime_tiles::settings_changed = []() { id(apply_screen_settings).execute(); }; runtime_tiles::settings_changed = []() { id(apply_screen_settings).execute(); };
runtime_tiles::dismiss = []() { runtime_tiles::dismiss = []() {
@@ -782,6 +783,7 @@ api:
(unsigned)(millis() - id(last_touch_ms)), id(display_dimmed)); (unsigned)(millis() - id(last_touch_ms)), id(display_dimmed));
ESP_LOGI("ui_diag", "navigation page=%d runtime_detail=%d", id(tile_page), ESP_LOGI("ui_diag", "navigation page=%d runtime_detail=%d", id(tile_page),
runtime_tiles::detail_root && !lv_obj_has_flag(runtime_tiles::detail_root, LV_OBJ_FLAG_HIDDEN)); runtime_tiles::detail_root && !lv_obj_has_flag(runtime_tiles::detail_root, LV_OBJ_FLAG_HIDDEN));
ESP_LOGI("ui_diag", "rotation=%u actual=%u", (unsigned)runtime_tiles::rotation, (unsigned)id(screen_lvgl).get_rotation());
lv_area_t nav, grid; lv_area_t nav, grid;
lv_obj_update_layout(id(home_page)->obj); lv_obj_update_layout(id(home_page)->obj);
lv_obj_get_coords(id(page_next), &nav); lv_obj_get_coords(id(page_next), &nav);
@@ -1287,6 +1289,11 @@ binary_sensor:
# - Used by the UI to display fan presets when applicable # - Used by the UI to display fan presets when applicable
# ---------------------------------------------------------- # ----------------------------------------------------------
text_sensor: text_sensor:
- platform: template
name: "Guition schermtype"
entity_category: diagnostic
update_interval: never
lambda: 'return {"guition"};'
- platform: template - platform: template
name: "Schermfirmware" name: "Schermfirmware"
entity_category: diagnostic entity_category: diagnostic
@@ -1616,6 +1623,7 @@ display:
lvgl: lvgl:
id: screen_lvgl
on_draw_start: on_draw_start:
- lambda: 'id(rendered_frames)++;' - lambda: 'id(rendered_frames)++;'
displays: displays:
@@ -4479,6 +4487,11 @@ script:
then: then:
- lambda: |- - lambda: |-
const auto &settings = screen_settings::current; const auto &settings = screen_settings::current;
if(runtime_tiles::enabled && static_cast<unsigned>(id(screen_lvgl).get_rotation())!=runtime_tiles::rotation){
cyd::touch_guard.consume();
if(lv_indev_get_act())lv_indev_wait_release(lv_indev_get_act());
id(screen_lvgl).set_rotation(static_cast<esphome::display::DisplayRotation>(runtime_tiles::rotation));
}
if (id(display_dimmed) && !settings.standby_enabled) { if (id(display_dimmed) && !settings.standby_enabled) {
id(display_dimmed) = false; id(display_dimmed) = false;
} }
+5
View File
@@ -1,3 +1,8 @@
## 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.
- Installeer eerst Guition-firmware 0.2.9 voor deze optie. De CYD behoudt zijn vaste oriëntatie en kalibratie.
## 0.2.8 ## 0.2.8
- Firmware: vaste tekstbreedtes voor nette afkapping met puntjes. Ondertitels gebruiken de beschikbare ruimte, ook bij korte titels. - Firmware: vaste tekstbreedtes voor nette afkapping met puntjes. Ondertitels gebruiken de beschikbare ruimte, ook bij korte titels.
+5
View File
@@ -24,6 +24,7 @@ SETTING_RULES = {
'clock_24h': (True, None, None), 'clock_24h': (True, None, None),
'home_on_standby': (False, None, None), 'home_on_standby': (False, None, None),
'swipe_pages': (False, None, None), 'swipe_pages': (False, None, None),
'rotation': (0, 0, 270),
} }
def validate_settings(data): def validate_settings(data):
@@ -36,6 +37,7 @@ def validate_settings(data):
valid = type(value) is bool valid = type(value) is bool
else: else:
valid = type(value) is int and minimum <= value <= maximum valid = type(value) is int and minimum <= value <= maximum
if key == "rotation": valid = valid and value in (0, 90, 180, 270)
if not valid: if not valid:
raise ValueError(f'Ongeldige waarde voor {key}.') raise ValueError(f'Ongeldige waarde voor {key}.')
clean[key] = value clean[key] = value
@@ -129,6 +131,8 @@ def discover(registry, states, devices, areas):
area_map = {a['area_id']: a['name'] for a in areas} area_map = {a['area_id']: a['name'] for a in areas}
versions = {item.get('device_id'): states.get(item['entity_id'], {}).get('state', 'onbekend') for item in registry versions = {item.get('device_id'): states.get(item['entity_id'], {}).get('state', 'onbekend') for item in registry
if item.get('platform') == 'esphome' and item.get('original_name') == 'Schermfirmware'} if item.get('platform') == 'esphome' and item.get('original_name') == 'Schermfirmware'}
boards = {item.get("device_id"): "guition" for item in registry
if item.get("platform") == "esphome" and item.get("original_name") == "Guition schermtype"}
screens, entities = [], [] screens, entities = [], []
for item in registry: for item in registry:
eid = item['entity_id'] eid = item['entity_id']
@@ -138,6 +142,7 @@ def discover(registry, states, devices, areas):
if item.get('platform') == 'esphome' and eid.startswith('text.') and item.get('original_name') == 'Tegelinstellingen' and not item.get('disabled_by'): if item.get('platform') == 'esphome' and eid.startswith('text.') and item.get('original_name') == 'Tegelinstellingen' and not item.get('disabled_by'):
screens.append({'id': eid, 'name': device.get('name_by_user') or device.get('name') or eid, screens.append({'id': eid, 'name': device.get('name_by_user') or device.get('name') or eid,
'firmware': versions.get(item.get('device_id'), 'onbekend'), 'firmware': versions.get(item.get('device_id'), 'onbekend'),
'board': boards.get(item.get('device_id'), 'unknown'),
'area': area, 'online': state.get('state') not in (None, 'unknown', 'unavailable'), 'area': area, 'online': state.get('state') not in (None, 'unknown', 'unavailable'),
'status': state.get('state', 'Niet verbonden')}) 'status': state.get('state', 'Niet verbonden')})
if not entity_id(eid) or item.get('disabled_by'): if not entity_id(eid) or item.get('disabled_by'):
+8 -1
View File
@@ -184,6 +184,11 @@ class Manager:
layout['settings'] = self.layouts[inbox]['settings'].copy() layout['settings'] = self.layouts[inbox]['settings'].copy()
if 'settings' in layout and 'swipe_pages' not in data.get('settings',{}): if 'settings' in layout and 'swipe_pages' not in data.get('settings',{}):
layout['settings']['swipe_pages']=self.layouts.get(inbox,{}).get('settings',{}).get('swipe_pages',False) layout['settings']['swipe_pages']=self.layouts.get(inbox,{}).get('settings',{}).get('swipe_pages',False)
if 'settings' in layout and 'rotation' not in data.get('settings',{}):
layout['settings']['rotation']=self.layouts.get(inbox,{}).get('settings',{}).get('rotation',0)
screen=next(s for s in self.inventory()[0] if s['id']==inbox)
if layout.get('settings',{}).get('rotation',0) and screen.get('board')!='guition':
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',[])} old_tiles = {t['entity']:t for t in self.layouts.get(inbox,{}).get('tiles',[])}
for tile in layout['tiles']: for tile in layout['tiles']:
if 'options' not in tile and 'options' in old_tiles.get(tile['entity'],{}): if 'options' not in tile and 'options' in old_tiles.get(tile['entity'],{}):
@@ -211,8 +216,10 @@ class Manager:
return return
messages = [{'v': 1, 'op': 'layout', 'inbox': inbox, 'title': layout['title'], 'entities': [t['entity'] for t in layout['tiles']]}] messages = [{'v': 1, 'op': 'layout', 'inbox': inbox, 'title': layout['title'], 'entities': [t['entity'] for t in layout['tiles']]}]
if 'settings' in layout: if 'settings' in layout:
messages[0]['settings'] = {k:v for k,v in layout['settings'].items() if k!='swipe_pages'} messages[0]['settings'] = {k:v for k,v in layout['settings'].items() if k not in ('swipe_pages','rotation')}
messages[0]['swipe_pages'] = layout['settings'].get('swipe_pages',False) messages[0]['swipe_pages'] = layout['settings'].get('swipe_pages',False)
if next((s.get('board') for s in self.inventory()[0] if s['id']==inbox),None)=='guition':
messages[0]['rotation'] = layout['settings'].get('rotation',0)
for i,tile in enumerate(layout['tiles']): for i,tile in enumerate(layout['tiles']):
message=state_message(i,tile,self.ha.states) message=state_message(i,tile,self.ha.states)
if tile['entity'].startswith('sensor.') and hasattr(self.ha,'history'): if tile['entity'].startswith('sensor.') and hasattr(self.ha,'history'):
+9 -3
View File
@@ -81,6 +81,7 @@ const settingDefinitions = [
["show_clock", "Klok tonen", "check", true], ["show_clock", "Klok tonen", "check", true],
["clock_24h", "24-uursklok (uit = 12 uur)", "check", true], ["clock_24h", "24-uursklok (uit = 12 uur)", "check", true],
["home_on_standby", "Na standby terug naar pagina 1", "check", false], ["home_on_standby", "Na standby terug naar pagina 1", "check", false],
["rotation", "Scherm draaien (met de klok mee)", "rotation", 0],
["swipe_pages", "Vegen tussen pagina’s (firmware 0.2.7+)", "check", false], ["swipe_pages", "Vegen tussen pagina’s (firmware 0.2.7+)", "check", false],
]; ];
function renderSettings() { function renderSettings() {
@@ -93,20 +94,25 @@ function renderSettings() {
const container = $("#settings-fields"); const container = $("#settings-fields");
container.replaceChildren(); container.replaceChildren();
for (const [key, title, kind, , min, max] of settingDefinitions) { for (const [key, title, kind, , min, max] of settingDefinitions) {
if(key === "rotation" && inventory.screens.find(s => s.id === selected)?.board !== "guition") continue;
const label = node( const label = node(
"label", "label",
undefined, undefined,
`setting ${kind === "check" ? "setting-check" : ""}`, `setting ${kind === "check" ? "setting-check" : ""}`,
); );
const caption = node("span", title), const caption = node("span", title),
input = node("input"), input = node(kind === "rotation" ? "select" : "input"),
output = node("output"); output = node("output");
input.id = `setting-${key}`; input.id = `setting-${key}`;
input.type = if(kind !== "rotation") input.type =
kind === "check" ? "checkbox" : kind === "minutes" ? "number" : kind; kind === "check" ? "checkbox" : kind === "minutes" ? "number" : kind;
input.setAttribute("aria-label", title); input.setAttribute("aria-label", title);
input.required = kind === "minutes" || kind === "time"; input.required = kind === "minutes" || kind === "time";
if (kind === "check") input.checked = values[key]; if(kind === "rotation") {
for(const angle of [0,90,180,270]) { const option=node("option", `${angle}°`); option.value=angle; input.append(option); }
input.value=values[key];
}
else if (kind === "check") input.checked = values[key];
else if (kind === "time") else if (kind === "time")
input.value = `${String(Math.floor(values[key] / 60)).padStart(2, "0")}:${String(values[key] % 60).padStart(2, "0")}`; input.value = `${String(Math.floor(values[key] / 60)).padStart(2, "0")}:${String(values[key] % 60).padStart(2, "0")}`;
else { else {
+1 -1
View File
@@ -1,5 +1,5 @@
name: ESP Screen Manager name: ESP Screen Manager
version: "0.2.8" version: "0.2.9"
slug: esp_screen_manager slug: esp_screen_manager
description: Kies tegels voor je CYD en Guition touchscreen, zonder opnieuw flashen. description: Kies tegels voor je CYD en Guition touchscreen, zonder opnieuw flashen.
url: https://github.com/MaxGramser/homeassistant_espscreen url: https://github.com/MaxGramser/homeassistant_espscreen
+2 -2
View File
@@ -122,11 +122,11 @@ class ManagerTests(unittest.IsolatedAsyncioTestCase):
with self.assertRaises(ValueError): fresh.save('text.screen',{**saved,'settings':{'brightness':0}}) with self.assertRaises(ValueError): fresh.save('text.screen',{**saved,'settings':{'brightness':0}})
self.assertEqual(path.read_bytes(),before) self.assertEqual(path.read_bytes(),before)
await fresh.sync_one('text.screen',saved) await fresh.sync_one('text.screen',saved)
self.assertEqual(fresh.ha.messages[0][1]['settings'],{k:v for k,v in settings.items() if k!='swipe_pages'}) self.assertEqual(fresh.ha.messages[0][1]['settings'],{k:v for k,v in settings.items() if k not in ('swipe_pages','rotation')})
await fresh.sync_one('text.screen',saved) await fresh.sync_one('text.screen',saved)
self.assertEqual(len(fresh.ha.messages),2) self.assertEqual(len(fresh.ha.messages),2)
await fresh.sync_one('text.screen',saved,True) await fresh.sync_one('text.screen',saved,True)
self.assertEqual(fresh.ha.messages[2][1]['settings'],{k:v for k,v in settings.items() if k!='swipe_pages'}) self.assertEqual(fresh.ha.messages[2][1]['settings'],{k:v for k,v in settings.items() if k not in ('swipe_pages','rotation')})
async def test_reorder_aborts_old_batch(self): async def test_reorder_aborts_old_batch(self):
with tempfile.TemporaryDirectory() as temp: with tempfile.TemporaryDirectory() as temp:
+32
View File
@@ -0,0 +1,32 @@
import tempfile
import unittest
from pathlib import Path
import test_portal
from core import validate_settings
class RotationTests(unittest.IsolatedAsyncioTestCase):
def test_only_quarter_turns(self):
for angle in (0,90,180,270):
self.assertEqual(validate_settings({'rotation':angle})['rotation'],angle)
for angle in (-90,45,360,True,90.0,'90'):
with self.assertRaises(ValueError):validate_settings({'rotation':angle})
async def test_legacy_wire_and_saved_rotation_survive_old_browser(self):
with tempfile.TemporaryDirectory() as tmp:
m=test_portal.ManagerTests().setup_manager(Path(tmp)/'screens.json')
layout={'title':'Thuis','tiles':[{'entity':'light.a'}],'settings':{'rotation':90}}
with self.assertRaises(ValueError):m.save('text.screen',layout)
m.ha.registry[0]['device_id']='guition'
m.ha.registry.append({'entity_id':'sensor.board','device_id':'guition','platform':'esphome','original_name':'Guition schermtype'})
# Capability stays discoverable with the panel offline or renamed.
m.ha.states['sensor.board']={'state':'unavailable'}
m.save('text.screen',layout)
await m.sync_one('text.screen',m.layouts['text.screen'])
wire=m.ha.messages[0][1]
self.assertEqual(wire['rotation'],90)
self.assertEqual(len(wire['settings']),11)
self.assertNotIn('rotation',wire['settings'])
m.save('text.screen',{'title':'Anders','tiles':layout['tiles'],'settings':{'brightness':80}})
self.assertEqual(m.layouts['text.screen']['settings']['rotation'],90)
fresh=test_portal.ManagerTests().setup_manager(m.path)
self.assertEqual(fresh.layouts['text.screen']['settings']['rotation'],90)