Add persistent native Guition rotation to screen settings
This commit is contained in:
@@ -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();
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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'):
|
||||||
|
|||||||
@@ -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'):
|
||||||
|
|||||||
@@ -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,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
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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)
|
||||||
Reference in New Issue
Block a user