Redesign action property

This commit is contained in:
fvanroie 2023-01-11 13:46:58 +01:00
parent b0ba6a7f2b
commit 8209625f1e
7 changed files with 191 additions and 99 deletions

View File

@ -787,12 +787,13 @@ typedef void* lv_font_user_data_t;
/*Declare the type of the user data of object (can be e.g. `void *`, `int`, `struct`)*/
typedef struct {
uint8_t id:8;
uint8_t objid:8;
uint8_t objid:6;
uint8_t transitionid:4;
uint8_t actionid:4;
uint8_t groupid:4;
uint8_t swipeid:4;
void* tag;
char* action;
} lv_obj_user_data_t;
/*1: enable `lv_obj_realaign()` based on `lv_obj_align()` parameters*/

View File

@ -1630,6 +1630,18 @@ static hasp_attribute_type_t attribute_common_tag(lv_obj_t* obj, uint16_t attr_h
}
break; // attribute_found
case ATTR_ACTION:
if(update) {
my_obj_set_action(obj, payload);
} else {
if(my_obj_get_action(obj)) {
*text = (char*)my_obj_get_action(obj);
} else {
strcpy_P(*text, "null"); // TODO : Literal String
}
}
break; // attribute_found
default:
return HASP_ATTR_TYPE_NOT_FOUND;
}
@ -2636,6 +2648,7 @@ void hasp_process_obj_attribute(lv_obj_t* obj, const char* attribute, const char
ret = attribute_common_align(obj, attribute, payload, &text, update);
break;
case ATTR_TAG:
case ATTR_ACTION:
ret = attribute_common_tag(obj, attr_hash, payload, &text, update);
break;
case ATTR_JSONL:
@ -2662,13 +2675,13 @@ void hasp_process_obj_attribute(lv_obj_t* obj, const char* attribute, const char
// case ATTR_BTN_POS:
case ATTR_ACTION:
if(update)
obj->user_data.actionid = Parser::get_action_id(payload);
else
val = obj->user_data.actionid;
ret = HASP_ATTR_TYPE_INT;
break;
/* case ATTR_ACTION:
if(update)
obj->user_data.actionid = Parser::get_action_id(payload);
else
val = obj->user_data.actionid;
ret = HASP_ATTR_TYPE_INT;
break;*/
// case ATTR_SYMBOL:
// (update) ? lv_dropdown_set_symbol(obj, payload) :

View File

@ -16,6 +16,7 @@ lv_chart_series_t* my_chart_get_series(lv_obj_t* chart, uint8_t ser_num);
void my_obj_set_value_str_text(lv_obj_t* obj, uint8_t part, lv_state_t state, const char* text);
void my_obj_set_tag(lv_obj_t* obj, const char* tag);
void my_obj_set_action(lv_obj_t* obj, const char* tag);
const char* my_obj_get_tag(lv_obj_t* obj);
void my_btnmatrix_map_clear(lv_obj_t* obj);
void my_msgbox_map_clear(lv_obj_t* obj);
@ -482,8 +483,8 @@ _HASP_ATTRIBUTE(SCALE_END_LINE_WIDTH, scale_end_line_width, lv_style_int_t)
// Spinner
#define ATTR_SPEED 14375
#define ATTR_THICKNESS 24180
//#define ATTR_ARC_LENGTH 755 - use ATTR_ANGLE
// #define ATTR_DIRECTION 32415 - see Dropdown
// #define ATTR_ARC_LENGTH 755 - use ATTR_ANGLE
// #define ATTR_DIRECTION 32415 - see Dropdown
// Line
#define ATTR_POINTS 8643

View File

@ -95,6 +95,42 @@ const char* my_obj_get_tag(lv_obj_t* obj)
return (char*)obj->user_data.tag;
}
// the action data is stored as SERIALIZED JSON data
void my_obj_set_action(lv_obj_t* obj, const char* action)
{
// release old action
if(obj->user_data.action) {
hasp_free(obj->user_data.action);
obj->user_data.action = NULL;
}
// new action is blank
if(action == NULL || action[0] == '\0') return;
// create new action
{
StaticJsonDocument<512> doc;
// size_t len = action ? strlen(action) : 0;
// check if it is a proper JSON object
DeserializationError error = deserializeJson(doc, action /*, len*/);
if(error != DeserializationError::Ok) doc.set(action); // use tag as-is
const size_t size = measureJson(doc) + 1;
if(char* str = (char*)hasp_malloc(size)) {
size_t len = serializeJson(doc, str, size); // tidy-up the json object
obj->user_data.action = str;
LOG_VERBOSE(TAG_ATTR, "new json: %s", str);
}
}
}
// the tag data is stored as SERIALIZED JSON data
const char* my_obj_get_action(lv_obj_t* obj)
{
return obj->user_data.action;
}
lv_label_align_t my_textarea_get_text_align(lv_obj_t* ta)
{
lv_textarea_ext_t* ext = (lv_textarea_ext_t*)lv_obj_get_ext_attr(ta);

View File

@ -4,13 +4,13 @@
#include <time.h>
#include <sys/time.h>
//#include "ArduinoLog.h"
// #include "ArduinoLog.h"
#include "hasplib.h"
#include "dev/device.h"
#include "drv/tft/tft_driver.h"
//#include "hasp_gui.h"
// #include "hasp_gui.h"
#if HASP_USE_DEBUG > 0
#include "../hasp_debug.h"
@ -272,7 +272,7 @@ static void dispatch_output(const char* topic, const char* payload)
}
// objectattribute=value
void dispatch_command(const char* topic, const char* payload, bool update, uint8_t source)
static void dispatch_command(const char* topic, const char* payload, bool update, uint8_t source)
{
/* ================================= Standard payload commands ======================================= */
@ -323,47 +323,14 @@ void dispatch_command(const char* topic, const char* payload, bool update, uint8
#endif // HASP_USE_CONFIG
} else {
if(strlen(payload) == 0) {
// dispatch_text_line(topic); // Could cause an infinite loop!
// dispatch_simple_text_command(topic); // Could cause an infinite loop!
}
LOG_WARNING(TAG_MSGR, F(D_DISPATCH_COMMAND_NOT_FOUND " => %s"), topic, payload);
}
}
// Strip command/config prefix from the topic and process the payload
void dispatch_topic_payload(const char* topic, const char* payload, bool update, uint8_t source)
{
if(!strcmp_P(topic, PSTR(MQTT_TOPIC_COMMAND))) {
dispatch_text_line((char*)payload, source);
return;
}
if(topic == strstr_P(topic, PSTR(MQTT_TOPIC_COMMAND "/"))) { // startsWith command/
topic += 8u;
dispatch_command(topic, (char*)payload, update, source);
return;
}
#if HASP_USE_CONFIG > 0
if(topic == strstr_P(topic, PSTR("config/"))) { // startsWith config/
topic += 7u;
dispatch_config(topic, (char*)payload, source);
return;
}
#endif
#if defined(HASP_USE_CUSTOM)
if(topic == strstr_P(topic, PSTR(MQTT_TOPIC_CUSTOM "/"))) { // startsWith custom
topic += 7u;
custom_topic_payload(topic, (char*)payload, source);
return;
}
#endif
dispatch_command(topic, (char*)payload, update, source); // dispatch as is
}
// Parse one line of text and execute the command
void dispatch_text_line(const char* cmnd, uint8_t source)
static void dispatch_simple_text_command(const char* cmnd, uint8_t source)
{
while(cmnd[0] == ' ' || cmnd[0] == '\t') cmnd++; // skip leading spaces
if(cmnd[0] == '/' && cmnd[1] == '/') return; // comment
@ -381,9 +348,9 @@ void dispatch_text_line(const char* cmnd, uint8_t source)
dispatch_command("json", cmnd, false, source);
break; // comment
case ' ':
dispatch_text_line(cmnd, source);
break;
// case ' ':
// dispatch_simple_text_command(cmnd, source);
// break;
default: {
size_t pos1 = std::string(cmnd).find("=");
@ -425,6 +392,39 @@ void dispatch_text_line(const char* cmnd, uint8_t source)
}
}
// Strip command/config prefix from the topic and process the payload
void dispatch_topic_payload(const char* topic, const char* payload, bool update, uint8_t source)
{
if(!strcmp_P(topic, PSTR(MQTT_TOPIC_COMMAND))) {
dispatch_simple_text_command((char*)payload, source);
return;
}
if(topic == strstr_P(topic, PSTR(MQTT_TOPIC_COMMAND "/"))) { // startsWith command/
topic += 8u;
dispatch_command(topic, (char*)payload, update, source);
return;
}
#if HASP_USE_CONFIG > 0
if(topic == strstr_P(topic, PSTR("config/"))) { // startsWith config/
topic += 7u;
dispatch_config(topic, (char*)payload, source);
return;
}
#endif
#if defined(HASP_USE_CUSTOM)
if(topic == strstr_P(topic, PSTR(MQTT_TOPIC_CUSTOM "/"))) { // startsWith custom
topic += 7u;
custom_topic_payload(topic, (char*)payload, source);
return;
}
#endif
dispatch_command(topic, (char*)payload, update, source); // dispatch as is
}
// void dispatch_output_group_state(uint8_t groupid, uint16_t state)
// {
// char payload[64];
@ -593,54 +593,69 @@ void dispatch_screenshot(const char*, const char* filename, uint8_t source)
#endif
}
void dispatch_parse_json(const char*, const char* payload, uint8_t source)
{ // Parse an incoming JSON array into individual commands
/* if(strPayload.endsWith(",]")) {
// Trailing null array elements are an artifact of older Home Assistant automations
// and need to be removed before parsing by ArduinoJSON 6+
strPayload.remove(strPayload.length() - 2, 2);
strPayload.concat("]");
}*/
// size_t maxsize = (128u * ((strlen(payload) / 128) + 1)) + 512;
// DynamicJsonDocument json(maxsize);
StaticJsonDocument<1024> json;
// Note: Deserialization needs to be (const char *) so the objects WILL be copied
// this uses more memory but otherwise the mqtt receive buffer can get overwritten by the send buffer !!
DeserializationError jsonError = deserializeJson(json, payload);
// json.shrinkToFit();
if(jsonError) { // Couldn't parse incoming JSON command
dispatch_json_error(TAG_MSGR, jsonError);
} else if(json.is<JsonArray>()) { // handle json as an array of commands
bool dispatch_json_variant(JsonVariant& json, uint8_t& savedPage, uint8_t source)
{
if(json.is<JsonArray>()) { // handle json as an array of commands
JsonArray arr = json.as<JsonArray>();
// guiStop();
LOG_WARNING(TAG_MSGR, "TEXT = ARRAY");
for(JsonVariant command : arr) {
dispatch_text_line(command.as<const char*>(), source);
dispatch_json_variant(command, savedPage, source);
}
// guiStart();
} else if(json.is<JsonObject>()) { // handle json as a jsonl
uint8_t savedPage = haspPages.get();
LOG_WARNING(TAG_MSGR, "TEXT = OBJECT");
hasp_new_object(json.as<JsonObject>(), savedPage);
// #ifdef ARDUINO
// } else if(json.is<String>()) { // handle json as a single command
// dispatch_text_line(json.as<String>().c_str());
// #else
} else if(json.is<std::string>()) { // handle json as a single command
dispatch_text_line(json.as<std::string>().c_str(), source);
// #endif
LOG_WARNING(TAG_MSGR, "TEXT = %s", json.as<std::string>().c_str());
dispatch_simple_text_command(json.as<std::string>().c_str(), source);
} else if(json.is<const char*>()) { // handle json as a single command
dispatch_text_line(json.as<const char*>(), source);
// } else if(json.is<char*>()) { // handle json as a single command
// dispatch_text_line(json.as<char*>());
LOG_WARNING(TAG_MSGR, "TEXT = %s", json.as<const char*>());
dispatch_simple_text_command(json.as<const char*>(), source);
} else {
LOG_WARNING(TAG_MSGR, F(D_DISPATCH_COMMAND_NOT_FOUND), payload);
LOG_WARNING(TAG_MSGR, "TEXT = unknown type");
return false;
}
return true;
}
void dispatch_text_line(const char* payload, uint8_t source)
{
{
// size_t maxsize = (128u * ((strlen(payload) / 128) + 1)) + 512;
// DynamicJsonDocument json(maxsize);
StaticJsonDocument<1024> doc;
// Note: Deserialization needs to be (const char *) so the objects WILL be copied
// this uses more memory but otherwise the mqtt receive buffer can get overwritten by the send buffer !!
DeserializationError jsonError = deserializeJson(doc, payload);
// json.shrinkToFit();
if(jsonError) {
// dispatch_json_error(TAG_MSGR, jsonError);
} else {
JsonVariant json = doc.as<JsonVariant>();
uint8_t savedPage = haspPages.get();
if(!dispatch_json_variant(json, savedPage, source)) {
LOG_WARNING(TAG_MSGR, F(D_DISPATCH_COMMAND_NOT_FOUND), payload);
// dispatch_simple_text_command(payload, source);
}
return;
}
}
// Could not parse as json
dispatch_simple_text_command(payload, source);
}
void dispatch_parse_json(const char*, const char* payload, uint8_t source)
{ // Parse an incoming JSON array into individual commands
dispatch_simple_text_command(payload, source);
}
#ifdef ARDUINO
@ -730,7 +745,7 @@ void dispatch_run_script(const char*, const char* payload, uint8_t source)
index++;
}
if(index > 0 && buffer.charAt(0) != '#') { // Check for comments
dispatch_text_line(buffer.c_str(), TAG_FILE);
dispatch_simple_text_command(buffer.c_str(), TAG_FILE);
}
}
@ -752,7 +767,7 @@ void dispatch_run_script(const char*, const char* payload, uint8_t source)
std::string line;
while(std::getline(f, line)) {
LOG_VERBOSE(TAG_HASP, line.c_str());
if(!line.empty() && line[0] != '#') dispatch_text_line(line.c_str(), TAG_FILE); // # for comments
if(!line.empty() && line[0] != '#') dispatch_simple_text_command(line.c_str(), TAG_FILE); // # for comments
}
} else {
LOG_ERROR(TAG_MSGR, F(D_FILE_LOAD_FAILED), payload);
@ -841,17 +856,10 @@ void dispatch_page(const char*, const char* payload, uint8_t source)
dispatch_set_page(pageid, animation, time, delay);
}
// Clears all fonts
void dispatch_clear_font(const char*, const char* payload, uint8_t source)
{
hasp_init();
font_clear_list(payload);
}
// Clears a page id or the current page if empty
void dispatch_clear_page(const char*, const char* page, uint8_t source)
{
if(!strcasecmp_P(page, PSTR("all"))) {
if(!strcasecmp(page, "all")) {
hasp_init();
return;
}
@ -865,6 +873,14 @@ void dispatch_clear_page(const char*, const char* page, uint8_t source)
haspPages.clear(pageid);
}
// Clears all fonts
void dispatch_clear_font(const char*, const char* payload, uint8_t source)
{
dispatch_clear_page(NULL, "all", source);
hasp_init();
font_clear_list(payload);
}
void dispatch_dim(const char*, const char* level)
{
// Set the current state

View File

@ -54,6 +54,7 @@ void dispatch_parse_jsonl(Stream& stream, uint8_t& saved_page_id);
#else
void dispatch_parse_jsonl(std::istream& stream, uint8_t& saved_page_id);
#endif
bool dispatch_json_variant(JsonVariant& json, uint8_t& savedPage, uint8_t source);
void dispatch_clear_page(const char* page);
void dispatch_json_error(uint8_t tag, DeserializationError& jsonError);

View File

@ -86,6 +86,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_CHECKED, NULL);
}
my_obj_set_tag(obj, (char*)NULL);
my_obj_set_action(obj, (char*)NULL);
}
/* ============================== Timer Event ============================ */
@ -491,8 +492,31 @@ void generic_event_handler(lv_obj_t* obj, lv_event_t event)
if(last_value_sent == HASP_EVENT_LOST) return;
/* If an actionid is attached, perform that action on UP event only */
if(obj->user_data.actionid) {
if(obj->user_data.action) {
// if(last_value_sent == HASP_EVENT_UP || last_value_sent == HASP_EVENT_RELEASE) {
// dispatch_text_line(obj->user_data.action, TAG_EVENT);
StaticJsonDocument<256> doc;
StaticJsonDocument<64> filter;
char eventname[8];
Parser::get_event_name(last_value_sent, eventname, sizeof(eventname));
filter[eventname] = true;
DeserializationError jsonError =
deserializeJson(doc, (const char*)obj->user_data.action, DeserializationOption::Filter(filter));
if(!jsonError) {
JsonVariant json = doc[eventname].as<JsonVariant>();
uint8_t savedPage = haspPages.get();
if(!dispatch_json_variant(json, savedPage, TAG_EVENT)) {
LOG_WARNING(TAG_MSGR, F(D_DISPATCH_COMMAND_NOT_FOUND), eventname);
// dispatch_simple_text_command(payload, source);
}
}
// }
} else if(obj->user_data.actionid) {
/* If an actionid is attached, perform that action on UP event only */
if(last_value_sent == HASP_EVENT_UP || last_value_sent == HASP_EVENT_RELEASE) {
lv_scr_load_anim_t transitionid = (lv_scr_load_anim_t)obj->user_data.transitionid;
switch(obj->user_data.actionid) {