mirror of
https://github.com/HASwitchPlate/openHASP.git
synced 2025-07-28 05:36:37 +00:00
Redesign action property
This commit is contained in:
parent
b0ba6a7f2b
commit
8209625f1e
@ -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*/
|
||||
|
@ -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) :
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user