Show actual vacuum state when opening its detail card

This commit is contained in:
Max Gramser
2026-09-12 17:12:44 +02:00
parent f6efefc229
commit 732a220df5
10 changed files with 41 additions and 11 deletions
+1
View File
@@ -41,6 +41,7 @@ struct Tile {
uint32_t pending_since = 0; uint32_t pending_since = 0;
bool pending = false, confirmed = false, local_feedback = false; bool pending = false, confirmed = false, local_feedback = false;
bool loading(uint32_t now) const { return pending && (now-pending_since < 1000 || (!confirmed && !local_feedback && now-pending_since < 6000)); } bool loading(uint32_t now) const { return pending && (now-pending_since < 1000 || (!confirmed && !local_feedback && now-pending_since < 6000)); }
bool awaiting_action(uint32_t now) const { return loading(now) && !local_feedback; }
void begin(uint32_t now, bool local=false) { pending=true; pending_since=now; confirmed=false; local_feedback=local; pending_revision=revision; } void begin(uint32_t now, bool local=false) { pending=true; pending_since=now; confirmed=false; local_feedback=local; pending_revision=revision; }
void observe(const std::string &next) { revision=next; if (pending && revision!=pending_revision) confirmed=true; } void observe(const std::string &next) { revision=next; if (pending && revision!=pending_revision) confirmed=true; }
std::string domain() const { return entity.substr(0, entity.find('.')); } std::string domain() const { return entity.substr(0, entity.find('.')); }
+8 -5
View File
@@ -200,6 +200,7 @@ inline const lv_font_t *detail_font=nullptr;
inline lv_obj_t *detail_actions[16]{}; inline lv_obj_t *detail_actions[16]{};
inline unsigned detail_action_count=0; inline unsigned detail_action_count=0;
inline lv_obj_t *detail_status=nullptr; inline lv_obj_t *detail_status=nullptr;
inline lv_obj_t *detail_badge_status=nullptr;
inline lv_obj_t *detail_label(lv_obj_t *parent,const std::string &text,int x,int y,int width) { inline lv_obj_t *detail_label(lv_obj_t *parent,const std::string &text,int x,int y,int width) {
auto *label=lv_label_create(parent);lv_label_set_text(label,text.c_str());lv_obj_set_pos(label,x,y);lv_obj_set_width(label,width); auto *label=lv_label_create(parent);lv_label_set_text(label,text.c_str());lv_obj_set_pos(label,x,y);lv_obj_set_width(label,width);
lv_obj_set_style_text_font(label,detail_font,0);lv_obj_set_style_text_color(label,lv_color_hex(light_theme?0x202020:0xFFFFFF),0); lv_obj_set_style_text_font(label,detail_font,0);lv_obj_set_style_text_color(label,lv_color_hex(light_theme?0x202020:0xFFFFFF),0);
@@ -275,7 +276,7 @@ inline void show_detail(unsigned index){
if(index>=model.count)return;detail_index=index;auto &t=model.tiles[index]; if(index>=model.count)return;detail_index=index;auto &t=model.tiles[index];
if(!detail_font)detail_font=lv_obj_get_style_text_font(widgets[index].title,LV_PART_MAIN); if(!detail_font)detail_font=lv_obj_get_style_text_font(widgets[index].title,LV_PART_MAIN);
if(!detail_root){detail_root=lv_obj_create(lv_screen_active());lv_obj_remove_style_all(detail_root);lv_obj_set_size(detail_root,lv_pct(100),lv_pct(100));lv_obj_remove_flag(detail_root,LV_OBJ_FLAG_SCROLLABLE);} if(!detail_root){detail_root=lv_obj_create(lv_screen_active());lv_obj_remove_style_all(detail_root);lv_obj_set_size(detail_root,lv_pct(100),lv_pct(100));lv_obj_remove_flag(detail_root,LV_OBJ_FLAG_SCROLLABLE);}
detail_action_count=0;detail_status=nullptr;lv_obj_clean(detail_root);lv_obj_remove_flag(detail_root,LV_OBJ_FLAG_HIDDEN);lv_obj_move_foreground(detail_root); detail_action_count=0;detail_status=nullptr;detail_badge_status=nullptr;lv_obj_clean(detail_root);lv_obj_remove_flag(detail_root,LV_OBJ_FLAG_HIDDEN);lv_obj_move_foreground(detail_root);
lv_obj_set_style_bg_color(detail_root,lv_color_hex(light_theme?0xE7E7E7:0x202A38),0);lv_obj_set_style_bg_opa(detail_root,LV_OPA_COVER,0); lv_obj_set_style_bg_color(detail_root,lv_color_hex(light_theme?0xE7E7E7:0x202A38),0);lv_obj_set_style_bg_opa(detail_root,LV_OPA_COVER,0);
int width=lv_display_get_horizontal_resolution(lv_display_get_default()), height=lv_display_get_vertical_resolution(lv_display_get_default()); int width=lv_display_get_horizontal_resolution(lv_display_get_default()), height=lv_display_get_vertical_resolution(lv_display_get_default());
bool large=width>=480;int pad=large?20:10, top=large?100:62, gap=large?12:6,bh=large?58:34,cw=(width-pad*2-gap)/2; bool large=width>=480;int pad=large?20:10, top=large?100:62, gap=large?12:6,bh=large?58:34,cw=(width-pad*2-gap)/2;
@@ -301,7 +302,8 @@ inline void show_detail(unsigned index){
shape(robot,29,59,26,5,0x00A6ED,3); shape(robot,29,59,26,5,0x00A6ED,3);
detail_label(hero,t.state=="cleaning"?"Aan het werk":t.state=="returning"?"Even opladen":t.state=="paused"?"Even pauze":"Klaar voor je huis",154,24,260); detail_label(hero,t.state=="cleaning"?"Aan het werk":t.state=="returning"?"Even opladen":t.state=="paused"?"Even pauze":"Klaar voor je huis",154,24,260);
auto *badge=shape(hero,154,59,240,32,muted,16); auto *badge=shape(hero,154,59,240,32,muted,16);
auto *status=detail_label(badge,t.loading(esphome::millis())?"Opdracht verstuurd...":state,12,5,218); auto *status=detail_label(badge,t.awaiting_action(esphome::millis())?"Opdracht verstuurd...":state,12,5,218);
detail_badge_status=status;
lv_obj_set_style_text_color(status,lv_color_hex(light_theme?0x087BA8:0xFFFFFF),0); lv_obj_set_style_text_color(status,lv_color_hex(light_theme?0x087BA8:0xFFFFFF),0);
detail_label(hero,std::isfinite(t.battery)?"Batterij "+std::to_string((int)t.battery)+"%":"Verbonden via Home Assistant",154,107,260); detail_label(hero,std::isfinite(t.battery)?"Batterij "+std::to_string((int)t.battery)+"%":"Verbonden via Home Assistant",154,107,260);
detail_button(t.state=="cleaning"?"Pauzeer schoonmaken":"Start schoonmaken",pad,260,width-2*pad,58,t.state=="cleaning"?1:0); detail_button(t.state=="cleaning"?"Pauzeer schoonmaken":"Start schoonmaken",pad,260,width-2*pad,58,t.state=="cleaning"?1:0);
@@ -508,10 +510,11 @@ inline void render(lv_obj_t *room) {
} }
inline void tick() { inline void tick() {
if(detail_root && !lv_obj_has_flag(detail_root,LV_OBJ_FLAG_HIDDEN) && detail_index<model.count){ if(detail_root && !lv_obj_has_flag(detail_root,LV_OBJ_FLAG_HIDDEN) && detail_index<model.count){
auto &t=model.tiles[detail_index];bool waiting=t.loading(esphome::millis())&&!t.local_feedback; auto &t=model.tiles[detail_index];bool waiting=t.awaiting_action(esphome::millis());
for(unsigned i=0;i<detail_action_count;++i){if(waiting||!fresh()||!t.available())lv_obj_add_state(detail_actions[i],LV_STATE_DISABLED);else lv_obj_remove_state(detail_actions[i],LV_STATE_DISABLED);} for(unsigned i=0;i<detail_action_count;++i){if(waiting||!fresh()||!t.available())lv_obj_add_state(detail_actions[i],LV_STATE_DISABLED);else lv_obj_remove_state(detail_actions[i],LV_STATE_DISABLED);}
if(waiting && detail_status)lv_label_set_text(detail_status,t.confirmed?"Bevestigd door Home Assistant":"Opdracht verstuurd..."); std::string status=waiting?(t.confirmed?"Bevestigd door Home Assistant":"Opdracht verstuurd..."):detail_state(t);
else if(detail_status){std::string state=detail_state(t);lv_label_set_text(detail_status,(state+(t.unit.empty()?"":" "+t.unit)).c_str());} if(detail_status)label(detail_status,status+(!waiting && !t.unit.empty()?" "+t.unit:""));
if(detail_badge_status)label(detail_badge_status,status);
} }
if(!enabled)return; if(!enabled)return;
bool redraw=false; bool redraw=false;
+22
View File
@@ -0,0 +1,22 @@
# Vacuumstatus 0.2.5
Een tegel openen gebruikt korte lokale feedback. Het statuslabel in de grote
vacuumkaart zag deze feedback ten onrechte als een echte opdracht en werd daarna
niet meer bijgewerkt. De kaart onderscheidt nu lokale feedback van een verstuurde
HA-actie. De kop en de statusbadge worden beide bijgewerkt: bij openen de actuele
status (bijvoorbeeld In dock), alleen na een opdracht de actiefeedback.
Gedeelde firmwarecorrectie voor Guition en CYD. Geen wijzigingen aan indelingen,
instellingen, opslagversie, voorkeurensleutels of paneelaansturing.
- 42 Python-tests en alle acht C++-regressieprogramma's geslaagd.
- Regressie voor lokale feedback versus echte acties en het verlopen van de
wachttijd toegevoegd aan de bestaande action-feedback-test.
- Gegenereerde pakketten met `--check` en Git-diff gecontroleerd.
- Alle vier ESPHome-builds geslaagd: Easy Setup en handmatige profielen van
Guition en CYD.
- Guition via OTA bijgewerkt; HA bevestigt firmware 0.2.5 en online-status.
- Vacuumkaart op de echte Guition via previewservice geopend, zonder HA-actie.
Interne LVGL-opname toont **In dock** in zowel de kop als de robotbadge.
Fysiek aantikken door de eigenaar is niet door deze preview vervangen.
- CYD niet aangesloten; alleen softwaretests en builds uitgevoerd.
+1 -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.3" SCREEN_FIRMWARE_VERSION: "0.2.5"
DYNAMIC_TILES: "false" DYNAMIC_TILES: "false"
DASHBOARD_INBOX_INTERNAL: "true" DASHBOARD_INBOX_INTERNAL: "true"
DEVICE_NAME: "guition-wallbox" DEVICE_NAME: "guition-wallbox"
+1 -1
View File
@@ -58,7 +58,7 @@
############################################################ ############################################################
substitutions: substitutions:
SCREEN_FIRMWARE_VERSION: "0.2.3" SCREEN_FIRMWARE_VERSION: "0.2.5"
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.3" SCREEN_FIRMWARE_VERSION: "0.2.5"
DYNAMIC_TILES: "true" DYNAMIC_TILES: "true"
DASHBOARD_INBOX_INTERNAL: "false" DASHBOARD_INBOX_INTERNAL: "false"
DEVICE_NAME: "cyd-new" DEVICE_NAME: "cyd-new"
+1 -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.3" SCREEN_FIRMWARE_VERSION: "0.2.5"
DYNAMIC_TILES: "true" DYNAMIC_TILES: "true"
DASHBOARD_INBOX_INTERNAL: "false" DASHBOARD_INBOX_INTERNAL: "false"
DEVICE_NAME: "guition-new" DEVICE_NAME: "guition-new"
+4
View File
@@ -1,3 +1,7 @@
## 0.2.5
- Firmware: een vacuumkaart openen toont de echte status, geen opdrachtmelding. Het statuslabel in de robotkaart blijft ook na een actie actueel.
## 0.2.4 ## 0.2.4
- Visuele tegelkiezer met domeiniconen, zachte kleuren en een klikbaar schermvoorbeeld van zes tegels per pagina. Selecteer een tegel om de instellingen te openen; sleep tegels in het voorbeeld om te ordenen. Geen firmware-update nodig. - Visuele tegelkiezer met domeiniconen, zachte kleuren en een klikbaar schermvoorbeeld van zes tegels per pagina. Selecteer een tegel om de instellingen te openen; sleep tegels in het voorbeeld om te ordenen. Geen firmware-update nodig.
+1 -1
View File
@@ -1,5 +1,5 @@
name: ESP Screen Manager name: ESP Screen Manager
version: "0.2.4" version: "0.2.5"
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
+1 -1
View File
@@ -1,3 +1,3 @@
#include "components/smart_display/runtime_model.h" #include "components/smart_display/runtime_model.h"
#include <cassert> #include <cassert>
int main(){runtime_tiles::Tile t;t.revision="off";t.begin(100);assert(t.loading(200));t.observe("off");assert(!t.confirmed);t.observe("on");assert(t.confirmed);assert(t.loading(999));assert(!t.loading(1100));t.begin(2000);t.observe("on");assert(t.loading(7999));assert(!t.loading(8000));t.begin(0xFFFFFFF0);assert(t.loading(20));t.begin(100,true);assert(t.loading(1099));assert(!t.loading(1100));} int main(){runtime_tiles::Tile t;t.revision="off";t.begin(100);assert(t.loading(200));assert(t.awaiting_action(200));t.observe("off");assert(!t.confirmed);t.observe("on");assert(t.confirmed);assert(t.loading(999));assert(!t.loading(1100));t.begin(2000);t.observe("on");assert(t.loading(7999));assert(!t.loading(8000));assert(!t.awaiting_action(8000));t.begin(0xFFFFFFF0);assert(t.loading(20));t.begin(100,true);assert(t.loading(1099));assert(!t.awaiting_action(1099));assert(!t.loading(1100));}