From 5c8626d49bff9f97ca060774d3c425e73f56cc26 Mon Sep 17 00:00:00 2001 From: marsman7 Date: Sun, 24 Mar 2024 12:36:27 +0100 Subject: [PATCH 1/6] add feature: object alias --- include/lv_conf_v7.h | 3 ++ include/user_config_override-template.h | 7 +++ src/hasp/hasp_attribute.cpp | 13 ++++++ src/hasp/hasp_attribute.h | 1 + src/hasp/hasp_attribute_helper.h | 36 +++++++++++++++ src/hasp/hasp_dispatch.cpp | 59 ++++++++++++++++++++++++- src/hasp/hasp_object.cpp | 51 +++++++++++++++++++++ src/hasp/hasp_object.h | 11 +++++ src/hasp/hasp_parser.cpp | 11 +++-- src/hasp/hasp_parser.h | 2 +- src/hasp_gui.cpp | 5 +++ src/hasp_oobe.cpp | 4 ++ 12 files changed, 198 insertions(+), 5 deletions(-) diff --git a/include/lv_conf_v7.h b/include/lv_conf_v7.h index e2adf67ea..47aefb0a5 100644 --- a/include/lv_conf_v7.h +++ b/include/lv_conf_v7.h @@ -863,6 +863,9 @@ typedef struct { // uint8_t swipeid:4; void* ext; // char* action; +#if USE_OBJ_ALIAS > 0 + uint16_t aliashash; +#endif // #if USE_OBJ_ALIAS > 0 } lv_obj_user_data_t; /*1: enable `lv_obj_realaign()` based on `lv_obj_align()` parameters*/ diff --git a/include/user_config_override-template.h b/include/user_config_override-template.h index 2d6c97c78..d5a1b1413 100644 --- a/include/user_config_override-template.h +++ b/include/user_config_override-template.h @@ -158,5 +158,12 @@ //#define HASP_DEBUG_OBJ_TREE // Output all objects to the log on page changes //#define HASP_LOG_LEVEL LOG_LEVEL_VERBOSE // LOG_LEVEL_* can be DEBUG, VERBOSE, TRACE, INFO, WARNING, ERROR, CRITICAL, ALERT, FATAL, SILENT //#define HASP_LOG_TASKS // Also log the Taskname and watermark of ESP32 tasks +#define USE_OBJ_ALIAS 1 // Enable store object alias und accept commands for objects with alias1 + +#if USE_OBJ_ALIAS > 0 +#ifndef LV_USE_USER_DATA + #define LV_USE_USER_DATA +#endif +#endif #endif // HASP_USER_CONFIG_OVERRIDE_H diff --git a/src/hasp/hasp_attribute.cpp b/src/hasp/hasp_attribute.cpp index dd0eb83c6..f2e58af3a 100644 --- a/src/hasp/hasp_attribute.cpp +++ b/src/hasp/hasp_attribute.cpp @@ -1794,6 +1794,16 @@ static hasp_attribute_type_t attribute_common_text(lv_obj_t* obj, uint16_t attr_ } } +#if USE_OBJ_ALIAS > 0 + if(attr_hash == ATTR_ALIAS) { + if(update) { + my_obj_set_alias(obj, attr_hash, payload); + } else { + *text = (char*)my_obj_get_alias(obj); + } + } +#endif // #if USE_OBJ_ALIAS > 0 + return HASP_ATTR_TYPE_STR; } @@ -2698,6 +2708,9 @@ void hasp_process_obj_attribute(lv_obj_t* obj, const char* attribute, const char // LOG_WARNING(TAG_HASP, F(D_ATTRIBUTE_OBSOLETE D_ATTRIBUTE_INSTEAD), attribute, "text"); case ATTR_TEXT: case ATTR_TEMPLATE: +#if USE_OBJ_ALIAS > 0 + case ATTR_ALIAS: +#endif // #if USE_OBJ_ALIAS > 0 ret = attribute_common_text(obj, attr_hash, payload, &text, update); break; diff --git a/src/hasp/hasp_attribute.h b/src/hasp/hasp_attribute.h index 1e431a2f7..d935aa17b 100644 --- a/src/hasp/hasp_attribute.h +++ b/src/hasp/hasp_attribute.h @@ -501,6 +501,7 @@ _HASP_ATTRIBUTE(SCALE_END_LINE_WIDTH, scale_end_line_width, lv_style_int_t) #define ATTR_GROUPID 48986 #define ATTR_OBJID 41010 #define ATTR_OBJ 53623 +#define ATTR_ALIAS 33840 #define ATTR_TEXT_MAC 38107 #define ATTR_TEXT_IP 41785 diff --git a/src/hasp/hasp_attribute_helper.h b/src/hasp/hasp_attribute_helper.h index 888b691c3..cc46967c5 100644 --- a/src/hasp/hasp_attribute_helper.h +++ b/src/hasp/hasp_attribute_helper.h @@ -825,6 +825,42 @@ static uint16_t my_btnmatrix_get_count(const lv_obj_t* btnm) return ext->btn_cnt; } +#if USE_OBJ_ALIAS > 0 +/** + * Find object with given alias + * @param obj pointer to perent object + * @param alias hash to be searched for + * @return Null at the moment in further text of alias + */ +static const char* my_obj_get_alias(const lv_obj_t* obj) +{ +#if LV_USE_USER_DATA + if (obj->user_data.aliashash > 0) { +// const char hashtext[6] = {0}; +// itoa(obj->user_data.aliashash, (char*)hashtext, 10); +// return hashtext; + } +#endif + return NULL; +} + +/** + * Set the alias of an object + * @param obj pointer to object + * @param attr_hash alias hash to store in object user data + * @param text alias text - not used further + */ +static void my_obj_set_alias(lv_obj_t* obj, uint16_t attr_hash, const char* text) +{ +#if LV_USE_USER_DATA + obj->user_data.aliashash = Parser::get_sdbm(text); + + LOG_DEBUG(TAG_HASP, "set alias hash [%s] [%d]", text, obj->user_data.aliashash); +#endif + return; +} +#endif // USE_OBJ_ALIAS + #if 0 static bool attribute_lookup_lv_property(uint16_t hash, uint8_t * prop) { diff --git a/src/hasp/hasp_dispatch.cpp b/src/hasp/hasp_dispatch.cpp index 03b0da9de..da50c34ab 100644 --- a/src/hasp/hasp_dispatch.cpp +++ b/src/hasp/hasp_dispatch.cpp @@ -184,6 +184,53 @@ static inline bool dispatch_parse_button_attribute(const char* topic_p, const ch return true; } +#if USE_OBJ_ALIAS > 0 +static inline bool dispatch_parse_alias_attribute(const char* topic_p, const char* payload, bool update) +{ + + if(*topic_p != '@') return false; // obligated @ + + topic_p++; + + const char *pSeperator = strchr(topic_p, '.'); + uint16_t aliaslen = (uint16_t)(pSeperator-topic_p); + + uint16_t aliashash = Parser::get_sdbm(topic_p, aliaslen); + topic_p = pSeperator; + + if(*topic_p != '.') return false; // obligated separator + + topic_p++; + + LOG_DEBUG(TAG_MSGR, "parse alias attribute : obj alias hash[%d] command[%s] payload[%s]", aliashash, topic_p, payload); + + lv_obj_t *top = lv_layer_top(); + lv_obj_t *scr = lv_scr_act(); + + LOG_DEBUG(TAG_MSGR, "parse alias attribute : page 0 childs[%d] current page childs[%d]", lv_obj_count_children(top), lv_obj_count_children(scr)); + + /* search object on page 0 */ + lv_obj_t* obj = NULL; + if (obj = hasp_find_obj_from_alias(top, aliashash)) { + /* Object found on page 0 */ + } + + /* search object on all other pages include subpages (tabview) */ + uint8_t page = HASP_START_PAGE; + while ((page <= HASP_NUM_PAGES && obj == NULL)) { + obj = hasp_find_obj_from_alias(haspPages.get_obj(page), aliashash); + page++; + } + + if(obj) { + hasp_process_obj_attribute(obj, topic_p, payload, update); + return true; + } + + return false; +} +#endif // #if USE_OBJ_ALIAS > 0 + static void dispatch_input(const char* topic, const char* payload) { #if HASP_USE_GPIO > 0 @@ -310,7 +357,17 @@ static void dispatch_command(const char* topic, const char* payload, bool update { /* ================================= Standard payload commands ======================================= */ - if(dispatch_parse_button_attribute(topic, payload, update)) return; // matched pxby.attr, first for speed + if(dispatch_parse_button_attribute(topic, payload, update)) { + LOG_DEBUG(TAG_MSGR, "dispatch object matched pxby.attr"); + return; // matched pxby.attr, first for speed + } + +#if USE_OBJ_ALIAS > 0 + if(dispatch_parse_alias_attribute(topic, payload, update)) { + LOG_DEBUG(TAG_MSGR, "dispatch object matched alias.attr"); + return; // matched alias.attr + } +#endif // #if USE_OBJ_ALIAS > 0 // check and execute commands from commands array for(int i = 0; i < nCommands; i++) { diff --git a/src/hasp/hasp_object.cpp b/src/hasp/hasp_object.cpp index c8b989cec..40740d06f 100644 --- a/src/hasp/hasp_object.cpp +++ b/src/hasp/hasp_object.cpp @@ -68,6 +68,57 @@ bool hasp_find_id_from_obj(const lv_obj_t* obj, uint8_t* pageid, uint8_t* objid) return true; } +#if USE_OBJ_ALIAS > 0 +/** + * Find object with given alias + * @param obj pointer to perent object + * @param alias hash to be searched for + * @return pointer to found object or NULL if nothing was found + */ +lv_obj_t* hasp_find_obj_from_alias(const lv_obj_t* obj, uint16_t alias, uint8_t level) +{ + if(!obj || level > 10) return NULL; + + level++; + + lv_obj_t* child = lv_obj_get_child_back(obj, NULL); + while(child) { + LOG_DEBUG(TAG_HASP, "find obj from alias : level[%d] objtype[%s] alias hash[%d]", level, obj_get_type_name(child), child->user_data.aliashash); + + if (alias == child->user_data.aliashash) { + level--; + return child; + } + + if(obj_check_type(child, LV_HASP_TABVIEW)) { + /* search in all tab */ + lv_tabview_ext_t * tv_ext = (lv_tabview_ext_t *)lv_obj_get_ext_attr(child); + lv_obj_t * tv_content = lv_page_get_scrollable(tv_ext->content); + lv_obj_t * tv_tab = lv_obj_get_child_back(tv_content, NULL); + lv_obj_t * tab_scrl; + lv_obj_t * tab_child; + + while(tv_tab != NULL) { + tab_scrl = lv_page_get_scrollable(tv_tab); + + LOG_DEBUG(TAG_HASP, "find obj from alias : level[%d] objtype[%s] childs[%d]", level, obj_get_type_name(tv_tab), lv_obj_count_children(tab_scrl)); + + tab_child = hasp_find_obj_from_alias(tab_scrl, alias, level); + if (tab_child) { + level--; + return tab_child; + } + tv_tab = lv_obj_get_child_back(tv_content, tv_tab); + } + } + child = lv_obj_get_child_back(obj, child); + } + + level--; + return NULL; +} +#endif // #if USE_OBJ_ALIAS > 0 + void hasp_object_tree(const lv_obj_t* parent, uint8_t pageid, uint16_t level) { if(parent == nullptr) return; diff --git a/src/hasp/hasp_object.h b/src/hasp/hasp_object.h index 9a8b81699..316072f52 100644 --- a/src/hasp/hasp_object.h +++ b/src/hasp/hasp_object.h @@ -100,6 +100,17 @@ lv_obj_t* hasp_find_obj_from_parent_id(lv_obj_t* parent, uint8_t objid); lv_obj_t* hasp_find_obj_from_page_id(uint8_t pageid, uint8_t objid); bool hasp_find_id_from_obj(const lv_obj_t* obj, uint8_t* pageid, uint8_t* objid); +#if USE_OBJ_ALIAS > 0 +/** + * Find object with given alias + * @param obj pointer to perent object + * @param alias hash to be searched for + * @param level level of the search depth, is incremented in each level + * @return pointer to found object or NULL if nothing was found + */ +lv_obj_t* hasp_find_obj_from_alias(const lv_obj_t* obj, uint16_t alias, uint8_t level = 0); +#endif // #if USE_OBJ_ALIAS + void hasp_object_tree(const lv_obj_t* parent, uint8_t pageid, uint16_t level); void object_dispatch_state(uint8_t pageid, uint8_t btnid, const char* payload); diff --git a/src/hasp/hasp_parser.cpp b/src/hasp/hasp_parser.cpp index a44a97413..ddc937e05 100644 --- a/src/hasp/hasp_parser.cpp +++ b/src/hasp/hasp_parser.cpp @@ -169,11 +169,16 @@ void Parser::get_event_name(uint8_t eventid, char* buffer, size_t size) /* 16-bit hashing function http://www.cse.yorku.ca/~oz/hash.html */ /* all possible attributes are hashed and checked if they are unique */ -uint16_t Parser::get_sdbm(const char* str) +uint16_t Parser::get_sdbm(const char* str, uint16_t len) { uint16_t hash = 0; - while(char c = tolower(*str++)) - if(c > 57 || c < 48) hash = c + (hash << 6) - hash; // exclude numbers which can cause collisions + char c; + while( (c = tolower(*str++) ) && len) { + if(c > 57 || c < 48) { + hash = c + (hash << 6) - hash; // exclude numbers which can cause collisions + } + len--; + } return hash; } diff --git a/src/hasp/hasp_parser.h b/src/hasp/hasp_parser.h index d1c44beab..c4a3b2f07 100644 --- a/src/hasp/hasp_parser.h +++ b/src/hasp/hasp_parser.h @@ -15,7 +15,7 @@ class Parser { static bool get_event_state(uint8_t eventid); static void get_event_name(uint8_t eventid, char* buffer, size_t size); static uint8_t get_action_id(const char* action); - static uint16_t get_sdbm(const char* str); + static uint16_t get_sdbm(const char* str, uint16_t len = UINT16_MAX); static bool is_true(const char* s); static bool is_true(JsonVariant json); static bool is_only_digits(const char* s); diff --git a/src/hasp_gui.cpp b/src/hasp_gui.cpp index 13caf3176..61198db8c 100644 --- a/src/hasp_gui.cpp +++ b/src/hasp_gui.cpp @@ -352,7 +352,12 @@ void guiSetup() #endif /* Initialize Global progress bar*/ +#if USE_OBJ_ALIAS > 0 + lv_obj_user_data_t udata = (lv_obj_user_data_t){10, 0, 10, NULL, 0}; +#else lv_obj_user_data_t udata = (lv_obj_user_data_t){10, 0, 10}; +#endif // #if USE_OBJ_ALIAS > 0 + lv_obj_t* bar = lv_bar_create(lv_layer_sys(), NULL); lv_obj_set_user_data(bar, udata); lv_obj_set_hidden(bar, true); diff --git a/src/hasp_oobe.cpp b/src/hasp_oobe.cpp index 1e9cb932f..2e2eae611 100644 --- a/src/hasp_oobe.cpp +++ b/src/hasp_oobe.cpp @@ -190,7 +190,11 @@ static void oobeSetupSsid(void) lv_coord_t leftmargin, topmargin, voffset; lv_align_t labelpos; +#if USE_OBJ_ALIAS > 0 + lv_obj_user_data_t udata = {0, 0, 0, NULL, 0}; +#else lv_obj_user_data_t udata = {0, 0, 0}; +#endif lv_disp_t* disp = lv_disp_get_default(); if(disp->driver.hor_res <= disp->driver.ver_res) { From 76f434738354a025a191a47617f3febe222cdb17 Mon Sep 17 00:00:00 2001 From: marsman7 Date: Thu, 28 Mar 2024 19:57:10 +0100 Subject: [PATCH 2/6] add store alias text and make it reversible --- include/lv_conf_v7.h | 3 +- include/user_config_override-template.h | 6 -- src/hasp/hasp_attribute.h | 1 + src/hasp/hasp_attribute_helper.h | 45 +++++---- src/hasp/hasp_dispatch.cpp | 2 + src/hasp/hasp_event.cpp | 117 ++++++++++++++++++++++-- src/hasp_gui.cpp | 2 +- src/hasp_oobe.cpp | 2 +- 8 files changed, 147 insertions(+), 31 deletions(-) diff --git a/include/lv_conf_v7.h b/include/lv_conf_v7.h index 47aefb0a5..c13dcb2bd 100644 --- a/include/lv_conf_v7.h +++ b/include/lv_conf_v7.h @@ -863,8 +863,9 @@ typedef struct { // uint8_t swipeid:4; void* ext; // char* action; -#if USE_OBJ_ALIAS > 0 +#if USE_OBJ_ALIAS > 0 uint16_t aliashash; + char *alias; #endif // #if USE_OBJ_ALIAS > 0 } lv_obj_user_data_t; diff --git a/include/user_config_override-template.h b/include/user_config_override-template.h index d5a1b1413..2db1c3c7f 100644 --- a/include/user_config_override-template.h +++ b/include/user_config_override-template.h @@ -160,10 +160,4 @@ //#define HASP_LOG_TASKS // Also log the Taskname and watermark of ESP32 tasks #define USE_OBJ_ALIAS 1 // Enable store object alias und accept commands for objects with alias1 -#if USE_OBJ_ALIAS > 0 -#ifndef LV_USE_USER_DATA - #define LV_USE_USER_DATA -#endif -#endif - #endif // HASP_USER_CONFIG_OVERRIDE_H diff --git a/src/hasp/hasp_attribute.h b/src/hasp/hasp_attribute.h index d935aa17b..9468a809d 100644 --- a/src/hasp/hasp_attribute.h +++ b/src/hasp/hasp_attribute.h @@ -21,6 +21,7 @@ void my_obj_set_swipe(lv_obj_t* obj, const char* tag); const char* my_obj_get_tag(lv_obj_t* obj); const char* my_obj_get_action(lv_obj_t* obj); const char* my_obj_get_swipe(lv_obj_t* obj); +const char* my_obj_get_alias(lv_obj_t* obj); void my_btnmatrix_map_clear(lv_obj_t* obj); void my_msgbox_map_clear(lv_obj_t* obj); void my_line_clear_points(lv_obj_t* obj); diff --git a/src/hasp/hasp_attribute_helper.h b/src/hasp/hasp_attribute_helper.h index cc46967c5..b401fbd6d 100644 --- a/src/hasp/hasp_attribute_helper.h +++ b/src/hasp/hasp_attribute_helper.h @@ -827,36 +827,49 @@ static uint16_t my_btnmatrix_get_count(const lv_obj_t* btnm) #if USE_OBJ_ALIAS > 0 /** - * Find object with given alias + * Get the text of alias * @param obj pointer to perent object - * @param alias hash to be searched for - * @return Null at the moment in further text of alias + * @return alias text */ -static const char* my_obj_get_alias(const lv_obj_t* obj) +const char* my_obj_get_alias(lv_obj_t* obj) { -#if LV_USE_USER_DATA - if (obj->user_data.aliashash > 0) { -// const char hashtext[6] = {0}; -// itoa(obj->user_data.aliashash, (char*)hashtext, 10); -// return hashtext; - } -#endif - return NULL; + if(!obj) return NULL; + + return obj->user_data.alias; } /** * Set the alias of an object * @param obj pointer to object * @param attr_hash alias hash to store in object user data - * @param text alias text - not used further + * @param text alias text */ static void my_obj_set_alias(lv_obj_t* obj, uint16_t attr_hash, const char* text) { -#if LV_USE_USER_DATA + // If exist old alias, free up memory + if(obj->user_data.alias) { + hasp_free(obj->user_data.alias); + obj->user_data.alias = NULL; + } + + // new alias is blank + if(text == NULL || text[0] == '\0') { + obj->user_data.aliashash = 0; + obj->user_data.alias = NULL; + } + + // store alias text + const size_t size = strlen(text); + if(char* str = (char*)hasp_malloc(size + 1)) { + strncpy(str, text, size + 1); // copy include 0 termination + str[size] = '\0'; // safety 0 termination + obj->user_data.alias = str; + } + + // store alias hash obj->user_data.aliashash = Parser::get_sdbm(text); - LOG_DEBUG(TAG_HASP, "set alias hash [%s] [%d]", text, obj->user_data.aliashash); -#endif + LOG_INFO(TAG_HASP, "set user data alias [%s] [%d]", obj->user_data.alias, obj->user_data.aliashash); return; } #endif // USE_OBJ_ALIAS diff --git a/src/hasp/hasp_dispatch.cpp b/src/hasp/hasp_dispatch.cpp index da50c34ab..629460f3b 100644 --- a/src/hasp/hasp_dispatch.cpp +++ b/src/hasp/hasp_dispatch.cpp @@ -86,6 +86,8 @@ void dispatch_state_eventid(const char* topic, hasp_event_t eventid) char payload[32]; char eventname[8]; + LOG_INFO(TAG_MQTT, "dispatch_state_eventid topic[%s] eid[%d]", topic, (uint16_t)eventid); + Parser::get_event_name(eventid, eventname, sizeof(eventname)); if(eventid == HASP_EVENT_ON || eventid == HASP_EVENT_OFF) { snprintf_P(payload, sizeof(payload), PSTR("{\"state\":\"%s\"}"), eventname); diff --git a/src/hasp/hasp_event.cpp b/src/hasp/hasp_event.cpp index cb7e112cd..e5ceb136e 100644 --- a/src/hasp/hasp_event.cpp +++ b/src/hasp/hasp_event.cpp @@ -276,12 +276,31 @@ static void event_object_val_event(lv_obj_t* obj, uint8_t eventid, int16_t val) { char data[512]; { - char eventname[8]; - Parser::get_event_name(eventid, eventname, sizeof(eventname)); - if(const char* tag = my_obj_get_tag(obj)) - snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\",\"val\":%d,\"tag\":%s}"), eventname, val, tag); - else - snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\",\"val\":%d}"), eventname, val); + char eventname[8]; + Parser::get_event_name(eventid, eventname, sizeof(eventname)); + +/* + if(const char* tag = my_obj_get_tag(obj)) + snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\",\"val\":%d,\"tag\":%s}"), eventname, val, tag); + else + snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\",\"val\":%d}"), eventname, val); +*/ + + snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\",\"val\":%d"), eventname, val); + + LOG_INFO(TAG_MQTT, "event_object_val_event pdata[%d] len[%d] pend[%d] eid[%d] val[%d] char[%d]", &data, strlen(data), &data[strlen(data)], eventid, val, (uint8_t)data[strlen(data)]); + + if (const char* tag = my_obj_get_tag(obj)) { + snprintf_P(&data[strlen(data)], sizeof(data)-strlen(data), PSTR(",\"tag\":%s"), tag); + } + +#if USE_OBJ_ALIAS > 0 + if (const char* alias = my_obj_get_alias(obj)) { + snprintf_P(&data[strlen(data)], sizeof(data)-strlen(data), PSTR(",\"alias\":\"%s\""), alias); + } +#endif // #if USE_OBJ_ALIAS > 0 + + snprintf_P(&data[strlen(data)], sizeof(data)-strlen(data), PSTR("}")); } event_send_object_data(obj, data); } @@ -299,12 +318,29 @@ static void event_object_selection_changed(lv_obj_t* obj, uint8_t eventid, int16 char eventname[8]; Parser::get_event_name(eventid, eventname, sizeof(eventname)); + +/* if(const char* tag = my_obj_get_tag(obj)) snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\",\"val\":%d,\"text\":%s,\"tag\":%s}"), eventname, val, serialized_text, tag); else snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\",\"val\":%d,\"text\":%s}"), eventname, val, serialized_text); +*/ + + snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\",\"val\":%d,\"text\":%s"), eventname, val, serialized_text); + + if (const char* tag = my_obj_get_tag(obj)) { + snprintf_P(&data[strlen(data)], sizeof(data)-strlen(data), PSTR(",\"tag\":%s"), tag); + } + +#if USE_OBJ_ALIAS > 0 + if (const char* alias = my_obj_get_alias(obj)) { + snprintf_P(&data[strlen(data)], sizeof(data)-strlen(data), PSTR(",\"alias\":\"%s\""), alias); + } +#endif // #if USE_OBJ_ALIAS > 0 + + snprintf_P(&data[strlen(data)], sizeof(data)-strlen(data), PSTR("}")); } event_send_object_data(obj, data); } @@ -445,12 +481,28 @@ void textarea_event_handler(lv_obj_t* obj, lv_event_t event) { char eventname[8]; Parser::get_event_name(hasp_event_id, eventname, sizeof(eventname)); +/* if(const char* tag = my_obj_get_tag(obj)) snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\",\"text\":\"%s\",\"tag\":%s}"), eventname, lv_textarea_get_text(obj), tag); else snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\",\"text\":\"%s\"}"), eventname, lv_textarea_get_text(obj)); +*/ + + snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\",\"text\":\"%s\""), eventname, lv_textarea_get_text(obj)); + + if (const char* tag = my_obj_get_tag(obj)) { + snprintf_P(&data[strlen(data)], sizeof(data)-strlen(data), PSTR(",\"tag\":%s"), tag); + } + +#if USE_OBJ_ALIAS > 0 + if (const char* alias = my_obj_get_alias(obj)) { + snprintf_P(&data[strlen(data)], sizeof(data)-strlen(data), PSTR(",\"alias\":\"%s\""), alias); + } +#endif // #if USE_OBJ_ALIAS > 0 + + snprintf_P(&data[strlen(data)], sizeof(data)-strlen(data), PSTR("}")); } event_send_object_data(obj, data); @@ -536,10 +588,26 @@ void generic_event_handler(lv_obj_t* obj, lv_event_t event) { char eventname[8]; Parser::get_event_name(last_value_sent, eventname, sizeof(eventname)); +/* if(const char* tag = my_obj_get_tag(obj)) snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\",\"tag\":%s}"), eventname, tag); else snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\"}"), eventname); +*/ + + snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\""), eventname); + + if (const char* tag = my_obj_get_tag(obj)) { + snprintf_P(&data[strlen(data)], sizeof(data)-strlen(data), PSTR(",\"tag\":%s"), tag); + } + +#if USE_OBJ_ALIAS > 0 + if (const char* alias = my_obj_get_alias(obj)) { + snprintf_P(&data[strlen(data)], sizeof(data)-strlen(data), PSTR(",\"alias\":\"%s\""), alias); + } +#endif // #if USE_OBJ_ALIAS > 0 + + snprintf_P(&data[strlen(data)], sizeof(data)-strlen(data), PSTR("}")); } event_send_object_data(obj, data); } @@ -859,6 +927,7 @@ void cpicker_event_handler(lv_obj_t* obj, lv_event_t event) hsv = lv_color_rgb_to_hsv(c32.ch.red, c32.ch.green, c32.ch.blue); last_color_sent = color; +/* if(const char* tag = my_obj_get_tag(obj)) snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\",\"color\":\"#%02x%02x%02x\",\"r\":%d,\"g\":%d,\"b\":%d,\"h\":%d,\"s\":%" @@ -871,6 +940,25 @@ void cpicker_event_handler(lv_obj_t* obj, lv_event_t event) "d,\"v\":%d}"), eventname, c32.ch.red, c32.ch.green, c32.ch.blue, c32.ch.red, c32.ch.green, c32.ch.blue, hsv.h, hsv.s, hsv.v); +*/ + + snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\",\"color\":\"#%02x%02x%02x\",\"r\":%d,\"g\":%d,\"b\":%d," + "\"h\":%d,\"s\":%d,\"v\":%d"), + eventname, c32.ch.red, c32.ch.green, c32.ch.blue, c32.ch.red, c32.ch.green, c32.ch.blue, hsv.h, + hsv.s, hsv.v); + + if (const char* tag = my_obj_get_tag(obj)) { + snprintf_P(&data[strlen(data)], sizeof(data)-strlen(data), PSTR(",\"tag\":%s"), tag); + } + +#if USE_OBJ_ALIAS > 0 + if (const char* alias = my_obj_get_alias(obj)) { + snprintf_P(&data[strlen(data)], sizeof(data)-strlen(data), PSTR(",\"alias\":\"%s\""), alias); + } +#endif // #if USE_OBJ_ALIAS > 0 + + snprintf_P(&data[strlen(data)], sizeof(data)-strlen(data), PSTR("}")); + } event_send_object_data(obj, data); @@ -906,6 +994,7 @@ void calendar_event_handler(lv_obj_t* obj, lv_event_t event) last_value_sent = val; last_obj_sent = obj; +/* if(const char* tag = my_obj_get_tag(obj)) snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\",\"val\":\"%d\",\"text\":\"%04d-%02d-%02dT00:00:00Z\",\"tag\":%s}"), @@ -914,6 +1003,22 @@ void calendar_event_handler(lv_obj_t* obj, lv_event_t event) snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\",\"val\":\"%d\",\"text\":\"%04d-%02d-%02dT00:00:00Z\"}"), eventname, date->day, date->year, date->month, date->day); +*/ + + snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\",\"val\":\"%d\",\"text\":\"%04d-%02d-%02dT00:00:00Z\""), + eventname, date->day, date->year, date->month, date->day); + + if (const char* tag = my_obj_get_tag(obj)) { + snprintf_P(&data[strlen(data)], sizeof(data)-strlen(data), PSTR(",\"tag\":%s"), tag); + } + +#if USE_OBJ_ALIAS > 0 + if (const char* alias = my_obj_get_alias(obj)) { + snprintf_P(&data[strlen(data)], sizeof(data)-strlen(data), PSTR(",\"alias\":\"%s\""), alias); + } +#endif // #if USE_OBJ_ALIAS > 0 + + snprintf_P(&data[strlen(data)], sizeof(data)-strlen(data), PSTR("}")); } event_send_object_data(obj, data); diff --git a/src/hasp_gui.cpp b/src/hasp_gui.cpp index 61198db8c..f86697825 100644 --- a/src/hasp_gui.cpp +++ b/src/hasp_gui.cpp @@ -353,7 +353,7 @@ void guiSetup() /* Initialize Global progress bar*/ #if USE_OBJ_ALIAS > 0 - lv_obj_user_data_t udata = (lv_obj_user_data_t){10, 0, 10, NULL, 0}; + lv_obj_user_data_t udata = (lv_obj_user_data_t){10, 0, 10, NULL, 0, NULL}; #else lv_obj_user_data_t udata = (lv_obj_user_data_t){10, 0, 10}; #endif // #if USE_OBJ_ALIAS > 0 diff --git a/src/hasp_oobe.cpp b/src/hasp_oobe.cpp index 2e2eae611..8e9d3f25c 100644 --- a/src/hasp_oobe.cpp +++ b/src/hasp_oobe.cpp @@ -191,7 +191,7 @@ static void oobeSetupSsid(void) lv_coord_t leftmargin, topmargin, voffset; lv_align_t labelpos; #if USE_OBJ_ALIAS > 0 - lv_obj_user_data_t udata = {0, 0, 0, NULL, 0}; + lv_obj_user_data_t udata = {0, 0, 0, NULL, 0, NULL}; #else lv_obj_user_data_t udata = {0, 0, 0}; #endif From 136c2e92bd0fa4116fe84618d52fabd27be0850c Mon Sep 17 00:00:00 2001 From: marsman7 Date: Sun, 31 Mar 2024 14:57:51 +0200 Subject: [PATCH 3/6] warning for duplicate alias added --- include/user_config_override-template.h | 1 + src/hasp/hasp_attribute_helper.h | 38 +++++++++++++++++++++---- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/include/user_config_override-template.h b/include/user_config_override-template.h index 2db1c3c7f..453712e3d 100644 --- a/include/user_config_override-template.h +++ b/include/user_config_override-template.h @@ -159,5 +159,6 @@ //#define HASP_LOG_LEVEL LOG_LEVEL_VERBOSE // LOG_LEVEL_* can be DEBUG, VERBOSE, TRACE, INFO, WARNING, ERROR, CRITICAL, ALERT, FATAL, SILENT //#define HASP_LOG_TASKS // Also log the Taskname and watermark of ESP32 tasks #define USE_OBJ_ALIAS 1 // Enable store object alias und accept commands for objects with alias1 +#define USE_ALIAS_ALLOW_DUPLICATES 0 #endif // HASP_USER_CONFIG_OVERRIDE_H diff --git a/src/hasp/hasp_attribute_helper.h b/src/hasp/hasp_attribute_helper.h index b401fbd6d..84bca7b84 100644 --- a/src/hasp/hasp_attribute_helper.h +++ b/src/hasp/hasp_attribute_helper.h @@ -846,7 +846,36 @@ const char* my_obj_get_alias(lv_obj_t* obj) */ static void my_obj_set_alias(lv_obj_t* obj, uint16_t attr_hash, const char* text) { - // If exist old alias, free up memory + // calculate hash + uint16_t hash = Parser::get_sdbm(text); + +#if USE_ALIAS_ALLOW_DUPLICATES < 1 + lv_obj_t *top = lv_layer_top(); + lv_obj_t *scr = lv_scr_act(); + + // search object on page 0 + lv_obj_t* tempobj = NULL; + if (tempobj = hasp_find_obj_from_alias(top, hash)) { + // Object found on page 0 + } + + // search object on all other pages include subpages (tabview) + uint8_t page = HASP_START_PAGE; + while ((page <= HASP_NUM_PAGES && tempobj == NULL)) { + tempobj = hasp_find_obj_from_alias(haspPages.get_obj(page), hash); + page++; + } + + if (tempobj) { + LOG_WARNING(TAG_HASP, "Warning! Alias hash for \"%s\" already exists. Alias not stored!", text); + return; // Store no duplicates + } +#endif + + // store alias hash in object + obj->user_data.aliashash = hash; + + // If exist old alias string, free up memory if(obj->user_data.alias) { hasp_free(obj->user_data.alias); obj->user_data.alias = NULL; @@ -858,7 +887,7 @@ static void my_obj_set_alias(lv_obj_t* obj, uint16_t attr_hash, const char* text obj->user_data.alias = NULL; } - // store alias text + // allocate mem for store alias text and save the pointer in object const size_t size = strlen(text); if(char* str = (char*)hasp_malloc(size + 1)) { strncpy(str, text, size + 1); // copy include 0 termination @@ -866,10 +895,7 @@ static void my_obj_set_alias(lv_obj_t* obj, uint16_t attr_hash, const char* text obj->user_data.alias = str; } - // store alias hash - obj->user_data.aliashash = Parser::get_sdbm(text); - - LOG_INFO(TAG_HASP, "set user data alias [%s] [%d]", obj->user_data.alias, obj->user_data.aliashash); + LOG_DEBUG(TAG_HASP, "set user data alias [%s] [%d]", obj->user_data.alias, obj->user_data.aliashash); return; } #endif // USE_OBJ_ALIAS From 4d4621c82649089b830cb8bb32db6f3df0686b81 Mon Sep 17 00:00:00 2001 From: marsman7 Date: Mon, 1 Apr 2024 17:09:22 +0200 Subject: [PATCH 4/6] improve mem leak an delete object with alias --- src/hasp/hasp_attribute.cpp | 2 +- src/hasp/hasp_attribute.h | 1 + src/hasp/hasp_attribute_helper.h | 29 +++++++++++++++-------------- src/hasp/hasp_event.cpp | 1 + 4 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/hasp/hasp_attribute.cpp b/src/hasp/hasp_attribute.cpp index f01fe8611..5c629ceac 100644 --- a/src/hasp/hasp_attribute.cpp +++ b/src/hasp/hasp_attribute.cpp @@ -1797,7 +1797,7 @@ static hasp_attribute_type_t attribute_common_text(lv_obj_t* obj, uint16_t attr_ #if USE_OBJ_ALIAS > 0 if(attr_hash == ATTR_ALIAS) { if(update) { - my_obj_set_alias(obj, attr_hash, payload); + my_obj_set_alias(obj, payload); } else { *text = (char*)my_obj_get_alias(obj); } diff --git a/src/hasp/hasp_attribute.h b/src/hasp/hasp_attribute.h index 9468a809d..63871e177 100644 --- a/src/hasp/hasp_attribute.h +++ b/src/hasp/hasp_attribute.h @@ -18,6 +18,7 @@ void my_obj_set_value_str_text(lv_obj_t* obj, uint8_t part, lv_state_t state, co void my_obj_set_tag(lv_obj_t* obj, const char* tag); void my_obj_set_action(lv_obj_t* obj, const char* tag); void my_obj_set_swipe(lv_obj_t* obj, const char* tag); +void my_obj_set_alias(lv_obj_t* obj, const char* text); const char* my_obj_get_tag(lv_obj_t* obj); const char* my_obj_get_action(lv_obj_t* obj); const char* my_obj_get_swipe(lv_obj_t* obj); diff --git a/src/hasp/hasp_attribute_helper.h b/src/hasp/hasp_attribute_helper.h index 84bca7b84..331b7a035 100644 --- a/src/hasp/hasp_attribute_helper.h +++ b/src/hasp/hasp_attribute_helper.h @@ -841,11 +841,24 @@ const char* my_obj_get_alias(lv_obj_t* obj) /** * Set the alias of an object * @param obj pointer to object - * @param attr_hash alias hash to store in object user data * @param text alias text */ -static void my_obj_set_alias(lv_obj_t* obj, uint16_t attr_hash, const char* text) +void my_obj_set_alias(lv_obj_t* obj, const char* text) { + // If exist old alias string, free up memory + if(obj->user_data.alias) { + hasp_free(obj->user_data.alias); + obj->user_data.aliashash = 0; + obj->user_data.alias = NULL; + } + + // new alias is blank + if(text == NULL || text[0] == '\0') { + obj->user_data.aliashash = 0; + obj->user_data.alias = NULL; + return; + } + // calculate hash uint16_t hash = Parser::get_sdbm(text); @@ -875,18 +888,6 @@ static void my_obj_set_alias(lv_obj_t* obj, uint16_t attr_hash, const char* text // store alias hash in object obj->user_data.aliashash = hash; - // If exist old alias string, free up memory - if(obj->user_data.alias) { - hasp_free(obj->user_data.alias); - obj->user_data.alias = NULL; - } - - // new alias is blank - if(text == NULL || text[0] == '\0') { - obj->user_data.aliashash = 0; - obj->user_data.alias = NULL; - } - // allocate mem for store alias text and save the pointer in object const size_t size = strlen(text); if(char* str = (char*)hasp_malloc(size + 1)) { diff --git a/src/hasp/hasp_event.cpp b/src/hasp/hasp_event.cpp index e5ceb136e..1e346f8bd 100644 --- a/src/hasp/hasp_event.cpp +++ b/src/hasp/hasp_event.cpp @@ -111,6 +111,7 @@ void delete_event_handler(lv_obj_t* obj, lv_event_t event) my_obj_set_value_str_text(obj, part, LV_STATE_DISABLED + LV_STATE_DEFAULT, NULL); my_obj_set_value_str_text(obj, part, LV_STATE_DISABLED + LV_STATE_CHECKED, NULL); } + my_obj_set_alias(obj, (char*)NULL); my_obj_set_tag(obj, (char*)NULL); my_obj_set_action(obj, (char*)NULL); my_obj_set_swipe(obj, (char*)NULL); From deb1408646b0646f70b1e6914211549c5ee964a2 Mon Sep 17 00:00:00 2001 From: marsman7 Date: Fri, 5 Apr 2024 23:14:59 +0200 Subject: [PATCH 5/6] alias functionality expanded and optimised --- include/user_config_override-template.h | 1 - src/hasp/hasp_attribute.cpp | 42 +++++++---- src/hasp/hasp_attribute_helper.h | 24 ------- src/hasp/hasp_dispatch.cpp | 54 ++++++++++----- src/hasp/hasp_event.cpp | 39 +++++++++-- src/hasp/hasp_object.cpp | 92 ++++++++++++++++--------- src/hasp/hasp_object.h | 21 +++--- src/sys/gpio/hasp_gpio.cpp | 12 +++- 8 files changed, 180 insertions(+), 105 deletions(-) diff --git a/include/user_config_override-template.h b/include/user_config_override-template.h index 453712e3d..2db1c3c7f 100644 --- a/include/user_config_override-template.h +++ b/include/user_config_override-template.h @@ -159,6 +159,5 @@ //#define HASP_LOG_LEVEL LOG_LEVEL_VERBOSE // LOG_LEVEL_* can be DEBUG, VERBOSE, TRACE, INFO, WARNING, ERROR, CRITICAL, ALERT, FATAL, SILENT //#define HASP_LOG_TASKS // Also log the Taskname and watermark of ESP32 tasks #define USE_OBJ_ALIAS 1 // Enable store object alias und accept commands for objects with alias1 -#define USE_ALIAS_ALLOW_DUPLICATES 0 #endif // HASP_USER_CONFIG_OVERRIDE_H diff --git a/src/hasp/hasp_attribute.cpp b/src/hasp/hasp_attribute.cpp index 5c629ceac..458c944da 100644 --- a/src/hasp/hasp_attribute.cpp +++ b/src/hasp/hasp_attribute.cpp @@ -2193,6 +2193,15 @@ static hasp_attribute_type_t attribute_common_val(lv_obj_t* obj, int32_t& val, b val = lv_tabview_get_tab_act(obj); break; + case LV_HASP_CPICKER: + if(update) { + lv_cpicker_set_color(obj, lv_color_hex(val)); + } else { + lv_color_t color = lv_cpicker_get_color(obj); + val = lv_color_to32(color); + } + break; + default: return HASP_ATTR_TYPE_NOT_FOUND; // not found } @@ -2205,23 +2214,28 @@ bool attribute_set_normalized_value(lv_obj_t* obj, hasp_update_value_t& value) if(value.min == value.max) return false; // would cause divide by zero error int32_t val; - int32_t min; - int32_t max; - if(!my_obj_get_range(obj, min, max)) return false; // range could not be determined - // Limit the value between min and max, adjust if power = 0 - if(value.power == 0 || value.val <= value.min) { - val = value.min; - } else if(value.val >= value.max) { - val = value.max; - } else { - val = value.val; - } + if (obj_get_type(obj) != LV_HASP_CPICKER) { + int32_t min; + int32_t max; + if(!my_obj_get_range(obj, min, max)) return false; // range could not be determined - if(min == 0 && max == 1) { - val = val != value.min; // Toggles are set to 0 when val = min, otherwise 1 + // Limit the value between min and max, adjust if power = 0 + if(value.power == 0 || value.val <= value.min) { + val = value.min; + } else if(value.val >= value.max) { + val = value.max; + } else { + val = value.val; + } + + if(min == 0 && max == 1) { + val = val != value.min; // Toggles are set to 0 when val = min, otherwise 1 + } else { + val = map(val, value.min, value.max, min, max); + } } else { - val = map(val, value.min, value.max, min, max); + val = value.val; } attribute_common_val(obj, val, true); diff --git a/src/hasp/hasp_attribute_helper.h b/src/hasp/hasp_attribute_helper.h index 331b7a035..af33a9b7f 100644 --- a/src/hasp/hasp_attribute_helper.h +++ b/src/hasp/hasp_attribute_helper.h @@ -862,29 +862,6 @@ void my_obj_set_alias(lv_obj_t* obj, const char* text) // calculate hash uint16_t hash = Parser::get_sdbm(text); -#if USE_ALIAS_ALLOW_DUPLICATES < 1 - lv_obj_t *top = lv_layer_top(); - lv_obj_t *scr = lv_scr_act(); - - // search object on page 0 - lv_obj_t* tempobj = NULL; - if (tempobj = hasp_find_obj_from_alias(top, hash)) { - // Object found on page 0 - } - - // search object on all other pages include subpages (tabview) - uint8_t page = HASP_START_PAGE; - while ((page <= HASP_NUM_PAGES && tempobj == NULL)) { - tempobj = hasp_find_obj_from_alias(haspPages.get_obj(page), hash); - page++; - } - - if (tempobj) { - LOG_WARNING(TAG_HASP, "Warning! Alias hash for \"%s\" already exists. Alias not stored!", text); - return; // Store no duplicates - } -#endif - // store alias hash in object obj->user_data.aliashash = hash; @@ -896,7 +873,6 @@ void my_obj_set_alias(lv_obj_t* obj, const char* text) obj->user_data.alias = str; } - LOG_DEBUG(TAG_HASP, "set user data alias [%s] [%d]", obj->user_data.alias, obj->user_data.aliashash); return; } #endif // USE_OBJ_ALIAS diff --git a/src/hasp/hasp_dispatch.cpp b/src/hasp/hasp_dispatch.cpp index 629460f3b..86cbdd0b7 100644 --- a/src/hasp/hasp_dispatch.cpp +++ b/src/hasp/hasp_dispatch.cpp @@ -189,6 +189,7 @@ static inline bool dispatch_parse_button_attribute(const char* topic_p, const ch #if USE_OBJ_ALIAS > 0 static inline bool dispatch_parse_alias_attribute(const char* topic_p, const char* payload, bool update) { + bool result = false; if(*topic_p != '@') return false; // obligated @ @@ -207,29 +208,34 @@ static inline bool dispatch_parse_alias_attribute(const char* topic_p, const cha LOG_DEBUG(TAG_MSGR, "parse alias attribute : obj alias hash[%d] command[%s] payload[%s]", aliashash, topic_p, payload); lv_obj_t *top = lv_layer_top(); - lv_obj_t *scr = lv_scr_act(); - - LOG_DEBUG(TAG_MSGR, "parse alias attribute : page 0 childs[%d] current page childs[%d]", lv_obj_count_children(top), lv_obj_count_children(scr)); /* search object on page 0 */ - lv_obj_t* obj = NULL; - if (obj = hasp_find_obj_from_alias(top, aliashash)) { - /* Object found on page 0 */ + hasp_cmd_process_data_t data = {.topic_p = topic_p, .payload = payload, .update = update}; + LOG_DEBUG(TAG_MSGR, "parse alias attribute : search page 0 childs[%d]", lv_obj_count_children(top)); + if (hasp_find_obj_from_alias(top, aliashash, false, &data)) { + result = true; + } + + /* search object on currently visible page first include subpages (tabview) */ + uint8_t current_page = haspPages.get(); + LOG_DEBUG(TAG_MSGR, "parse alias attribute : search page %d childs[%d]", current_page, lv_obj_count_children(haspPages.get_obj(current_page))); + if (hasp_find_obj_from_alias(haspPages.get_obj(current_page), aliashash, false, &data)) { + result = true; } /* search object on all other pages include subpages (tabview) */ uint8_t page = HASP_START_PAGE; - while ((page <= HASP_NUM_PAGES && obj == NULL)) { - obj = hasp_find_obj_from_alias(haspPages.get_obj(page), aliashash); + while (page <= HASP_NUM_PAGES) { + if (page != current_page) { + LOG_DEBUG(TAG_MSGR, "parse alias attribute : search page %d childs[%d]", page, lv_obj_count_children(haspPages.get_obj(page))); + if (hasp_find_obj_from_alias(haspPages.get_obj(page), aliashash, false, &data)) { + result = true; + } + } page++; } - if(obj) { - hasp_process_obj_attribute(obj, topic_p, payload, update); - return true; - } - - return false; + return result; } #endif // #if USE_OBJ_ALIAS > 0 @@ -670,16 +676,28 @@ void dispatch_config(const char* topic, const char* payload, uint8_t source) void dispatch_normalized_group_values(hasp_update_value_t& value) { - if(value.group == 0) return; +// if(value.group == 0) return; #if HASP_USE_GPIO > 0 - gpio_set_normalized_group_values(value); // Update GPIO states first + if(value.group) { + gpio_set_normalized_group_values(value); // Update GPIO states first + } +#endif + +#if USE_OBJ_ALIAS == 0 + if(value.group) +#else + if(value.group || value.alias) #endif - object_set_normalized_group_values(value); // Update onsreen objects except originating obj + { + object_set_normalized_group_values(value); // Update onsreen objects except originating obj + } LOG_VERBOSE(TAG_MSGR, F("GROUP %d value %d (%d-%d)"), value.group, value.val, value.min, value.max); #if HASP_USE_GPIO > 0 - gpio_output_group_values(value.group); // Output new gpio values + if(value.group) { + gpio_output_group_values(value.group); // Output new gpio values + } #endif } diff --git a/src/hasp/hasp_event.cpp b/src/hasp/hasp_event.cpp index 1e346f8bd..9a140cd02 100644 --- a/src/hasp/hasp_event.cpp +++ b/src/hasp/hasp_event.cpp @@ -111,10 +111,13 @@ void delete_event_handler(lv_obj_t* obj, lv_event_t event) my_obj_set_value_str_text(obj, part, LV_STATE_DISABLED + LV_STATE_DEFAULT, NULL); my_obj_set_value_str_text(obj, part, LV_STATE_DISABLED + LV_STATE_CHECKED, NULL); } - my_obj_set_alias(obj, (char*)NULL); my_obj_set_tag(obj, (char*)NULL); my_obj_set_action(obj, (char*)NULL); my_obj_set_swipe(obj, (char*)NULL); + +#if USE_OBJ_ALIAS > 0 + my_obj_set_alias(obj, (char*)NULL); +#endif // #if USE_OBJ_ALIAS > 0 } /* ============================== Timer Event ============================ */ @@ -289,8 +292,6 @@ static void event_object_val_event(lv_obj_t* obj, uint8_t eventid, int16_t val) snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\",\"val\":%d"), eventname, val); - LOG_INFO(TAG_MQTT, "event_object_val_event pdata[%d] len[%d] pend[%d] eid[%d] val[%d] char[%d]", &data, strlen(data), &data[strlen(data)], eventid, val, (uint8_t)data[strlen(data)]); - if (const char* tag = my_obj_get_tag(obj)) { snprintf_P(&data[strlen(data)], sizeof(data)-strlen(data), PSTR(",\"tag\":%s"), tag); } @@ -350,7 +351,18 @@ static void event_object_selection_changed(lv_obj_t* obj, uint8_t eventid, int16 static inline void event_update_group(uint8_t group, lv_obj_t* obj, bool power, int32_t val, int32_t min, int32_t max) { - hasp_update_value_t value = {.obj = obj, .group = group, .min = min, .max = max, .val = val, .power = power}; + hasp_update_value_t value = { + .obj = obj + , .group = group + , .min = min + , .max = max + , .val = val + , .power = power +#if USE_OBJ_ALIAS > 0 + , .alias = obj->user_data.aliashash +#endif + }; + dispatch_normalized_group_values(value); } @@ -659,7 +671,12 @@ void toggle_event_handler(lv_obj_t* obj, lv_event_t event) event_object_val_event(obj, hasp_event_id, last_value_sent); // Update group objects and gpios on release - if(obj->user_data.groupid && hasp_event_id == HASP_EVENT_UP) { +#if USE_OBJ_ALIAS == 0 + if(obj->user_data.groupid && hasp_event_id == HASP_EVENT_UP) +#else + if((obj->user_data.groupid || obj->user_data.aliashash) && hasp_event_id == HASP_EVENT_UP) +#endif + { event_update_group(obj->user_data.groupid, obj, last_value_sent, last_value_sent, HASP_EVENT_OFF, HASP_EVENT_ON); } @@ -895,8 +912,14 @@ void slider_event_handler(lv_obj_t* obj, lv_event_t event) last_obj_sent = obj; event_object_val_event(obj, hasp_event_id, val); +#if USE_OBJ_ALIAS == 0 if(obj->user_data.groupid && (hasp_event_id == HASP_EVENT_CHANGED || hasp_event_id == HASP_EVENT_UP) && min != max) +#else + if((obj->user_data.groupid || obj->user_data.aliashash) && (hasp_event_id == HASP_EVENT_CHANGED || hasp_event_id == HASP_EVENT_UP) && min != max) +#endif + { event_update_group(obj->user_data.groupid, obj, !!val, val, min, max); + } } /** @@ -963,7 +986,11 @@ void cpicker_event_handler(lv_obj_t* obj, lv_event_t event) } event_send_object_data(obj, data); - // event_update_group(obj->user_data.groupid, obj, val, min, max); +#if USE_OBJ_ALIAS > 0 + if(obj->user_data.aliashash && hasp_event_id == HASP_EVENT_UP) { + event_update_group(0, obj, true, lv_color_to32(color), 0x000000, 0x00ffffff); + } +#endif } #if LV_USE_CALENDAR > 0 diff --git a/src/hasp/hasp_object.cpp b/src/hasp/hasp_object.cpp index 40740d06f..017e33025 100644 --- a/src/hasp/hasp_object.cpp +++ b/src/hasp/hasp_object.cpp @@ -70,52 +70,65 @@ bool hasp_find_id_from_obj(const lv_obj_t* obj, uint8_t* pageid, uint8_t* objid) #if USE_OBJ_ALIAS > 0 /** - * Find object with given alias - * @param obj pointer to perent object - * @param alias hash to be searched for - * @return pointer to found object or NULL if nothing was found + * Recursive function that find object with given alias and process payload, + * return after all objects checked + * + * @param obj Pointer to perent object + * @param alias Hash to be searched for + * @param toreturn If true, the function returns in case of a match + * @param data Data for hasp_process_obj_attribute() + * @return pointer to last founded object or NULL if nothing was found */ -lv_obj_t* hasp_find_obj_from_alias(const lv_obj_t* obj, uint16_t alias, uint8_t level) +lv_obj_t* hasp_find_obj_from_alias(const lv_obj_t* obj, uint16_t alias, bool toreturn, hasp_cmd_process_data_t *data) { - if(!obj || level > 10) return NULL; + lv_obj_t* result = NULL; - level++; + if(!obj || !alias) return NULL; + + // check of page self of match alias + if (alias == obj->user_data.aliashash) { + // alias match page self + LOG_DEBUG(TAG_HASP, "page alias match"); + + if (data) { + hasp_process_obj_attribute((lv_obj_t*)obj, data->topic_p, data->payload, data->update); + } + result = (lv_obj_t*)obj; + if (toreturn) return result; + } lv_obj_t* child = lv_obj_get_child_back(obj, NULL); while(child) { - LOG_DEBUG(TAG_HASP, "find obj from alias : level[%d] objtype[%s] alias hash[%d]", level, obj_get_type_name(child), child->user_data.aliashash); + LOG_DEBUG(TAG_HASP, "search alias : objid[%d] objtype[%s] ahash[%d]" + , child->user_data.id, obj_get_type_name(child), child->user_data.aliashash); if (alias == child->user_data.aliashash) { - level--; - return child; - } + LOG_DEBUG(TAG_HASP, "alias match"); - if(obj_check_type(child, LV_HASP_TABVIEW)) { - /* search in all tab */ + if (data) { + hasp_process_obj_attribute((lv_obj_t*)child, data->topic_p, data->payload, data->update); + } + result = child; + if (toreturn) return result; + } + + if (obj_check_type(child, LV_HASP_TABVIEW)) { lv_tabview_ext_t * tv_ext = (lv_tabview_ext_t *)lv_obj_get_ext_attr(child); - lv_obj_t * tv_content = lv_page_get_scrollable(tv_ext->content); - lv_obj_t * tv_tab = lv_obj_get_child_back(tv_content, NULL); - lv_obj_t * tab_scrl; - lv_obj_t * tab_child; - - while(tv_tab != NULL) { - tab_scrl = lv_page_get_scrollable(tv_tab); + lv_obj_t * tabs = lv_page_get_scrollable(tv_ext->content); + // Recursive call for tabs + result = hasp_find_obj_from_alias(tabs, alias, toreturn, data); + } else if (obj_check_type(child, LV_HASP_TAB)) { + lv_obj_t* tab_content_area = lv_obj_get_child_back(child, NULL); + // Recursive call for tab content + result = hasp_find_obj_from_alias(tab_content_area, alias, toreturn, data); + } - LOG_DEBUG(TAG_HASP, "find obj from alias : level[%d] objtype[%s] childs[%d]", level, obj_get_type_name(tv_tab), lv_obj_count_children(tab_scrl)); + if (toreturn) return result; - tab_child = hasp_find_obj_from_alias(tab_scrl, alias, level); - if (tab_child) { - level--; - return tab_child; - } - tv_tab = lv_obj_get_child_back(tv_content, tv_tab); - } - } child = lv_obj_get_child_back(obj, child); } - level--; - return NULL; + return result; } #endif // #if USE_OBJ_ALIAS > 0 @@ -177,7 +190,14 @@ void object_set_group_values(lv_obj_t* parent, hasp_update_value_t& value) if(parent == nullptr) return; // Update object if it's in the same group - if(value.group == parent->user_data.groupid && value.obj != parent) { +#if USE_OBJ_ALIAS == 0 + if(value.group == parent->user_data.groupid && value.obj != parent) +#else + if(value.obj != parent && + ((value.group > 0 && value.group == parent->user_data.groupid) || + (value.alias > 0 && value.alias == parent->user_data.aliashash))) +#endif + { attribute_set_normalized_value(parent, value); } @@ -201,13 +221,19 @@ void object_set_group_values(lv_obj_t* parent, hasp_update_value_t& value) // SHOULD only by called from DISPATCH void object_set_normalized_group_values(hasp_update_value_t& value) { +#if USE_OBJ_ALIAS == 0 if(value.group == 0 || value.min == value.max) return; +#else + if((value.group == 0 && value.alias == 0) || value.min == value.max) return; +#endif uint8_t page = haspPages.get(); object_set_group_values(haspPages.get_obj(page), value); // Update visible objects first for(uint8_t i = 0; i < HASP_NUM_PAGES; i++) { - if(i != page) object_set_group_values(haspPages.get_obj(i), value); + if(i != page) { + object_set_group_values(haspPages.get_obj(i), value); + } } } diff --git a/src/hasp/hasp_object.h b/src/hasp/hasp_object.h index 316072f52..e41f00c56 100644 --- a/src/hasp/hasp_object.h +++ b/src/hasp/hasp_object.h @@ -36,8 +36,20 @@ typedef struct int32_t max; int32_t val; bool power; +#if USE_OBJ_ALIAS > 0 + uint16_t alias; +#endif } hasp_update_value_t; +#if USE_OBJ_ALIAS > 0 +typedef struct +{ + const char* topic_p; + const char* payload; + bool update; +} hasp_cmd_process_data_t; +#endif + enum lv_hasp_obj_type_t { /* Containers */ LV_HASP_SCREEN = 1, @@ -101,14 +113,7 @@ lv_obj_t* hasp_find_obj_from_page_id(uint8_t pageid, uint8_t objid); bool hasp_find_id_from_obj(const lv_obj_t* obj, uint8_t* pageid, uint8_t* objid); #if USE_OBJ_ALIAS > 0 -/** - * Find object with given alias - * @param obj pointer to perent object - * @param alias hash to be searched for - * @param level level of the search depth, is incremented in each level - * @return pointer to found object or NULL if nothing was found - */ -lv_obj_t* hasp_find_obj_from_alias(const lv_obj_t* obj, uint16_t alias, uint8_t level = 0); +lv_obj_t* hasp_find_obj_from_alias(const lv_obj_t* obj, uint16_t alias, bool toreturn, hasp_cmd_process_data_t *data); #endif // #if USE_OBJ_ALIAS void hasp_object_tree(const lv_obj_t* parent, uint8_t pageid, uint16_t level); diff --git a/src/sys/gpio/hasp_gpio.cpp b/src/sys/gpio/hasp_gpio.cpp index 0094f80bb..1e27c2009 100644 --- a/src/sys/gpio/hasp_gpio.cpp +++ b/src/sys/gpio/hasp_gpio.cpp @@ -54,7 +54,17 @@ static inline void gpio_input_event(uint8_t pin, hasp_event_t eventid); static inline void gpio_update_group(uint8_t group, lv_obj_t* obj, bool power, int32_t val, int32_t min, int32_t max) { - hasp_update_value_t value = {.obj = obj, .group = group, .min = min, .max = max, .val = val, .power = power}; + hasp_update_value_t value = { + .obj = obj + , .group = group + , .min = min + , .max = max + , .val = val + , .power = power +#if USE_OBJ_ALIAS > 0 + , .alias = 0 +#endif + }; dispatch_normalized_group_values(value); } From ef592a849fd5e07befcbabddb65765c14004a8f2 Mon Sep 17 00:00:00 2001 From: marsman7 Date: Mon, 22 Apr 2024 20:08:40 +0200 Subject: [PATCH 6/6] extends hash calculation --- src/hasp/hasp_attribute_helper.h | 2 +- src/hasp/hasp_dispatch.cpp | 2 +- src/hasp/hasp_parser.cpp | 19 +++++++++++++++---- src/hasp/hasp_parser.h | 2 +- 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/hasp/hasp_attribute_helper.h b/src/hasp/hasp_attribute_helper.h index af33a9b7f..66f3c67e8 100644 --- a/src/hasp/hasp_attribute_helper.h +++ b/src/hasp/hasp_attribute_helper.h @@ -860,7 +860,7 @@ void my_obj_set_alias(lv_obj_t* obj, const char* text) } // calculate hash - uint16_t hash = Parser::get_sdbm(text); + uint16_t hash = Parser::get_sdbm(text, UINT16_MAX, true); // store alias hash in object obj->user_data.aliashash = hash; diff --git a/src/hasp/hasp_dispatch.cpp b/src/hasp/hasp_dispatch.cpp index 86cbdd0b7..ee9f3c2b4 100644 --- a/src/hasp/hasp_dispatch.cpp +++ b/src/hasp/hasp_dispatch.cpp @@ -198,7 +198,7 @@ static inline bool dispatch_parse_alias_attribute(const char* topic_p, const cha const char *pSeperator = strchr(topic_p, '.'); uint16_t aliaslen = (uint16_t)(pSeperator-topic_p); - uint16_t aliashash = Parser::get_sdbm(topic_p, aliaslen); + uint16_t aliashash = Parser::get_sdbm(topic_p, aliaslen, true); topic_p = pSeperator; if(*topic_p != '.') return false; // obligated separator diff --git a/src/hasp/hasp_parser.cpp b/src/hasp/hasp_parser.cpp index ddc937e05..0d309e0eb 100644 --- a/src/hasp/hasp_parser.cpp +++ b/src/hasp/hasp_parser.cpp @@ -167,14 +167,25 @@ void Parser::get_event_name(uint8_t eventid, char* buffer, size_t size) } } -/* 16-bit hashing function http://www.cse.yorku.ca/~oz/hash.html */ -/* all possible attributes are hashed and checked if they are unique */ -uint16_t Parser::get_sdbm(const char* str, uint16_t len) +/** *************************************************************************** + * @brief 16-bit hashing function http://www.cse.yorku.ca/~oz/hash.html + * all possible attributes are hashed and checked if they are unique + * + * To calculate the attribute hashes, digits must be "false", otherwise + * attributes such as "bg_color01" will not work. I think for aliases + * digits is better "true", so that lamp1 and lamp2 provide a different hash. + * + * @param str : pointer to text to be hashed + * @param len : maximum number of characters on which the hash is calculated + * @param digis : false=digits are not included; true=digits are included + * @return hash of given text + ************************************************************************** **/ +uint16_t Parser::get_sdbm(const char* str, uint16_t len, bool digits) { uint16_t hash = 0; char c; while( (c = tolower(*str++) ) && len) { - if(c > 57 || c < 48) { + if(c > 57 || c < 48 || digits) { hash = c + (hash << 6) - hash; // exclude numbers which can cause collisions } len--; diff --git a/src/hasp/hasp_parser.h b/src/hasp/hasp_parser.h index c4a3b2f07..c3521d0a3 100644 --- a/src/hasp/hasp_parser.h +++ b/src/hasp/hasp_parser.h @@ -15,7 +15,7 @@ class Parser { static bool get_event_state(uint8_t eventid); static void get_event_name(uint8_t eventid, char* buffer, size_t size); static uint8_t get_action_id(const char* action); - static uint16_t get_sdbm(const char* str, uint16_t len = UINT16_MAX); + static uint16_t get_sdbm(const char* str, uint16_t len = UINT16_MAX, bool digits=false); static bool is_true(const char* s); static bool is_true(JsonVariant json); static bool is_only_digits(const char* s);