diff --git a/include/lv_conf_v7.h b/include/lv_conf_v7.h index e2adf67ea..c13dcb2bd 100644 --- a/include/lv_conf_v7.h +++ b/include/lv_conf_v7.h @@ -863,6 +863,10 @@ typedef struct { // uint8_t swipeid:4; void* ext; // char* action; +#if USE_OBJ_ALIAS > 0 + uint16_t aliashash; + char *alias; +#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..2db1c3c7f 100644 --- a/include/user_config_override-template.h +++ b/include/user_config_override-template.h @@ -158,5 +158,6 @@ //#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 #endif // HASP_USER_CONFIG_OVERRIDE_H diff --git a/src/hasp/hasp_attribute.cpp b/src/hasp/hasp_attribute.cpp index 9e7205c73..458c944da 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, payload); + } else { + *text = (char*)my_obj_get_alias(obj); + } + } +#endif // #if USE_OBJ_ALIAS > 0 + return HASP_ATTR_TYPE_STR; } @@ -2183,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 } @@ -2195,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); @@ -2698,6 +2722,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..63871e177 100644 --- a/src/hasp/hasp_attribute.h +++ b/src/hasp/hasp_attribute.h @@ -18,9 +18,11 @@ 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); +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); @@ -501,6 +503,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..66f3c67e8 100644 --- a/src/hasp/hasp_attribute_helper.h +++ b/src/hasp/hasp_attribute_helper.h @@ -825,6 +825,58 @@ static uint16_t my_btnmatrix_get_count(const lv_obj_t* btnm) return ext->btn_cnt; } +#if USE_OBJ_ALIAS > 0 +/** + * Get the text of alias + * @param obj pointer to perent object + * @return alias text + */ +const char* my_obj_get_alias(lv_obj_t* obj) +{ + if(!obj) return NULL; + + return obj->user_data.alias; +} + +/** + * Set the alias of an object + * @param obj pointer to object + * @param text alias 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, UINT16_MAX, true); + + // store alias hash in object + obj->user_data.aliashash = hash; + + // 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 + str[size] = '\0'; // safety 0 termination + obj->user_data.alias = str; + } + + 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..ee9f3c2b4 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); @@ -184,6 +186,59 @@ 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) +{ + bool result = false; + + 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, true); + 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(); + + /* search object 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) { + 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++; + } + + return result; +} +#endif // #if USE_OBJ_ALIAS > 0 + static void dispatch_input(const char* topic, const char* payload) { #if HASP_USE_GPIO > 0 @@ -310,7 +365,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++) { @@ -611,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 cb7e112cd..9a140cd02 100644 --- a/src/hasp/hasp_event.cpp +++ b/src/hasp/hasp_event.cpp @@ -114,6 +114,10 @@ void delete_event_handler(lv_obj_t* obj, lv_event_t event) 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 ============================ */ @@ -276,12 +280,29 @@ 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); + + 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 +320,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); } @@ -313,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); } @@ -445,12 +494,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 +601,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); } @@ -590,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); } @@ -826,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); + } } /** @@ -859,6 +951,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,10 +964,33 @@ 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); - // 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 @@ -906,6 +1022,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 +1031,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/hasp_object.cpp b/src/hasp/hasp_object.cpp index c8b989cec..017e33025 100644 --- a/src/hasp/hasp_object.cpp +++ b/src/hasp/hasp_object.cpp @@ -68,6 +68,70 @@ bool hasp_find_id_from_obj(const lv_obj_t* obj, uint8_t* pageid, uint8_t* objid) return true; } +#if USE_OBJ_ALIAS > 0 +/** + * 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, bool toreturn, hasp_cmd_process_data_t *data) +{ + lv_obj_t* result = NULL; + + 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, "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) { + LOG_DEBUG(TAG_HASP, "alias match"); + + 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 * 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); + } + + if (toreturn) return result; + + child = lv_obj_get_child_back(obj, child); + } + + return result; +} +#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; @@ -126,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); } @@ -150,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 9a8b81699..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, @@ -100,6 +112,10 @@ 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 +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); 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..0d309e0eb 100644 --- a/src/hasp/hasp_parser.cpp +++ b/src/hasp/hasp_parser.cpp @@ -167,13 +167,29 @@ 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) +/** *************************************************************************** + * @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; - 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 || digits) { + 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..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); + 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); diff --git a/src/hasp_gui.cpp b/src/hasp_gui.cpp index 13caf3176..f86697825 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, NULL}; +#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..8e9d3f25c 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, NULL}; +#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) { 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); }