Support event data substitution in action commands

This commit is contained in:
Kuba Szczodrzyński 2024-02-10 18:04:18 +01:00
parent 603d38ae3c
commit 3cb5eb2d58
No known key found for this signature in database
GPG Key ID: 43037AC62A600562
9 changed files with 94 additions and 45 deletions

View File

@ -177,6 +177,10 @@
#define HASP_NUM_GPIO_CONFIG 8 #define HASP_NUM_GPIO_CONFIG 8
#endif #endif
#ifndef HASP_USE_EVENT_DATA_SUBST
#define HASP_USE_EVENT_DATA_SUBST 0
#endif
// #ifndef HASP_USE_CUSTOM // #ifndef HASP_USE_CUSTOM
// #define HASP_USE_CUSTOM 0 // #define HASP_USE_CUSTOM 0
// #endif // #endif

View File

@ -610,11 +610,17 @@ void dispatch_screenshot(const char*, const char* filename, uint8_t source)
} }
bool dispatch_json_variant(JsonVariant& json, uint8_t& savedPage, uint8_t source) bool dispatch_json_variant(JsonVariant& json, uint8_t& savedPage, uint8_t source)
{
JsonObject dummy;
return dispatch_json_variant_with_data(json, savedPage, source, dummy);
}
bool dispatch_json_variant_with_data(JsonVariant& json, uint8_t& savedPage, uint8_t source, JsonObject& data)
{ {
if(json.is<JsonArray>()) { // handle json as an array of commands if(json.is<JsonArray>()) { // handle json as an array of commands
LOG_DEBUG(TAG_MSGR, "Json ARRAY"); LOG_DEBUG(TAG_MSGR, "Json ARRAY");
for(JsonVariant command : json.as<JsonArray>()) { for(JsonVariant command : json.as<JsonArray>()) {
dispatch_json_variant(command, savedPage, source); dispatch_json_variant_with_data(command, savedPage, source, data);
} }
} else if(json.is<JsonObject>()) { // handle json as a jsonl } else if(json.is<JsonObject>()) { // handle json as a jsonl
@ -622,13 +628,23 @@ bool dispatch_json_variant(JsonVariant& json, uint8_t& savedPage, uint8_t source
hasp_new_object(json.as<JsonObject>(), savedPage); hasp_new_object(json.as<JsonObject>(), savedPage);
} else if(json.is<std::string>()) { // handle json as a single command } else if(json.is<std::string>()) { // handle json as a single command
LOG_DEBUG(TAG_MSGR, "Json text = %s", json.as<std::string>().c_str()); std::string command = json.as<std::string>();
dispatch_simple_text_command(json.as<std::string>().c_str(), source);
} else if(json.is<const char*>()) { // handle json as a single command #if HASP_USE_EVENT_DATA_SUBST
LOG_DEBUG(TAG_MSGR, "Json text = %s", json.as<const char*>()); if(command.find('%') != std::string::npos) {
dispatch_simple_text_command(json.as<const char*>(), source); // '%' found in command, run variable substitution
for(JsonPair kv : data) {
std::string find = "%" + std::string(kv.key().c_str()) + "%";
std::string replace = kv.value().as<std::string>();
size_t pos = command.find(find);
if(pos == std::string::npos) continue;
command.replace(pos, find.length(), replace);
}
}
#endif
LOG_DEBUG(TAG_MSGR, "Json text = %s", command.c_str());
dispatch_simple_text_command(command.c_str(), source);
} else if(json.isNull()) { // event handler not found } else if(json.isNull()) { // event handler not found
// nothing to do // nothing to do

View File

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

View File

@ -42,23 +42,47 @@ void event_reset_last_value_sent()
last_value_sent = INT16_MIN; last_value_sent = INT16_MIN;
} }
void script_event_handler(const char* eventname, const char* json) static bool script_event_handler(const char* eventname, const char* action, const char* data)
{ {
if(action == NULL) {
LOG_DEBUG(TAG_EVENT, F("Skipping event: name=%s, data=%s"), eventname, data);
return false;
}
StaticJsonDocument<256> doc; StaticJsonDocument<256> doc;
StaticJsonDocument<64> filter; StaticJsonDocument<64> filter;
filter[eventname] = true; filter[eventname] = true;
DeserializationError jsonError = deserializeJson(doc, json, DeserializationOption::Filter(filter)); DeserializationError jsonError = deserializeJson(doc, action, DeserializationOption::Filter(filter));
if(!jsonError) { if(!jsonError) {
JsonVariant json = doc[eventname].as<JsonVariant>(); JsonVariant json = doc[eventname].as<JsonVariant>();
if(json.isNull()) {
LOG_DEBUG(TAG_EVENT, F("Skipping event: name=%s, data=%s"), eventname, data);
return true;
} else {
LOG_DEBUG(TAG_EVENT, F("Handling event: name=%s, data=%s"), eventname, data);
}
JsonObject dataJson;
#if HASP_USE_EVENT_DATA_SUBST
if(data != NULL) {
StaticJsonDocument<256> jsonDoc;
if(deserializeJson(jsonDoc, data) != DeserializationError::Ok) {
LOG_ERROR(TAG_EVENT, F("Deserialization failed"));
} else {
dataJson = jsonDoc.as<JsonObject>();
}
}
#endif
uint8_t savedPage = haspPages.get(); uint8_t savedPage = haspPages.get();
if(!dispatch_json_variant(json, savedPage, TAG_EVENT)) { if(!dispatch_json_variant_with_data(json, savedPage, TAG_EVENT, dataJson)) {
LOG_WARNING(TAG_EVENT, F(D_DISPATCH_COMMAND_NOT_FOUND), eventname); LOG_WARNING(TAG_EVENT, F(D_DISPATCH_COMMAND_NOT_FOUND), eventname);
} }
} else { } else {
dispatch_json_error(TAG_EVENT, jsonError); dispatch_json_error(TAG_EVENT, jsonError);
} }
return true;
} }
/** /**
@ -254,11 +278,16 @@ static bool translate_event(lv_obj_t* obj, lv_event_t event, uint8_t& eventid)
// ##################### Value Senders ######################################################## // ##################### Value Senders ########################################################
static void event_send_object_data(lv_obj_t* obj, const char* data) static void event_send_object_data(lv_obj_t* obj, const char* eventname, const char* data)
{ {
uint8_t pageid; uint8_t pageid;
uint8_t objid; uint8_t objid;
// handle object "action", abort sending if handled
if(script_event_handler(eventname, my_obj_get_action(obj), data)) {
return;
}
if(hasp_find_id_from_obj(obj, &pageid, &objid)) { if(hasp_find_id_from_obj(obj, &pageid, &objid)) {
if(!data) return; if(!data) return;
object_dispatch_state(pageid, objid, data); object_dispatch_state(pageid, objid, data);
@ -271,23 +300,23 @@ static void event_send_object_data(lv_obj_t* obj, const char* data)
static void event_object_val_event(lv_obj_t* obj, uint8_t eventid, int16_t val) static void event_object_val_event(lv_obj_t* obj, uint8_t eventid, int16_t val)
{ {
char data[512]; char data[512];
{
char eventname[8]; char eventname[8];
{
Parser::get_event_name(eventid, eventname, sizeof(eventname)); Parser::get_event_name(eventid, eventname, sizeof(eventname));
if(const char* tag = my_obj_get_tag(obj)) if(const char* tag = my_obj_get_tag(obj))
snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\",\"val\":%d,\"tag\":%s}"), eventname, val, tag); snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\",\"val\":%d,\"tag\":%s}"), eventname, val, tag);
else 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);
} }
event_send_object_data(obj, data); event_send_object_data(obj, eventname, data);
} }
// Send out events with a val and text attribute // Send out events with a val and text attribute
static void event_object_selection_changed(lv_obj_t* obj, uint8_t eventid, int16_t val, const char* text) static void event_object_selection_changed(lv_obj_t* obj, uint8_t eventid, int16_t val, const char* text)
{ {
char data[512]; char data[512];
{
char eventname[8]; char eventname[8];
{
Parser::get_event_name(eventid, eventname, sizeof(eventname)); Parser::get_event_name(eventid, eventname, sizeof(eventname));
if(const char* tag = my_obj_get_tag(obj)) if(const char* tag = my_obj_get_tag(obj))
@ -296,7 +325,7 @@ static void event_object_selection_changed(lv_obj_t* obj, uint8_t eventid, int16
else else
snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\",\"val\":%d,\"text\":\"%s\"}"), eventname, val, text); snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\",\"val\":%d,\"text\":\"%s\"}"), eventname, val, text);
} }
event_send_object_data(obj, data); event_send_object_data(obj, eventname, data);
} }
// ##################### Event Handlers ######################################################## // ##################### Event Handlers ########################################################
@ -402,16 +431,16 @@ void swipe_event_handler(lv_obj_t* obj, lv_event_t event)
lv_gesture_dir_t dir = lv_indev_get_gesture_dir(lv_indev_get_act()); lv_gesture_dir_t dir = lv_indev_get_gesture_dir(lv_indev_get_act());
switch(dir) { switch(dir) {
case LV_GESTURE_DIR_LEFT: case LV_GESTURE_DIR_LEFT:
script_event_handler("left", swipe); script_event_handler("left", swipe, NULL);
break; break;
case LV_GESTURE_DIR_RIGHT: case LV_GESTURE_DIR_RIGHT:
script_event_handler("right", swipe); script_event_handler("right", swipe, NULL);
break; break;
case LV_GESTURE_DIR_BOTTOM: case LV_GESTURE_DIR_BOTTOM:
script_event_handler("down", swipe); script_event_handler("down", swipe, NULL);
break; break;
default: default:
script_event_handler("up", swipe); script_event_handler("up", swipe, NULL);
} }
} }
} }
@ -432,8 +461,8 @@ void textarea_event_handler(lv_obj_t* obj, lv_event_t event)
if(!translate_event(obj, event, hasp_event_id)) return; if(!translate_event(obj, event, hasp_event_id)) return;
char data[1024]; char data[1024];
{
char eventname[8]; char eventname[8];
{
Parser::get_event_name(hasp_event_id, eventname, sizeof(eventname)); Parser::get_event_name(hasp_event_id, eventname, sizeof(eventname));
if(const char* tag = my_obj_get_tag(obj)) if(const char* tag = my_obj_get_tag(obj))
@ -444,7 +473,7 @@ void textarea_event_handler(lv_obj_t* obj, lv_event_t event)
lv_textarea_get_text(obj)); lv_textarea_get_text(obj));
} }
event_send_object_data(obj, data); event_send_object_data(obj, eventname, data);
} else if(event == LV_EVENT_FOCUSED) { } else if(event == LV_EVENT_FOCUSED) {
lv_textarea_set_cursor_hidden(obj, false); lv_textarea_set_cursor_hidden(obj, false);
} else if(event == LV_EVENT_DEFOCUSED) { } else if(event == LV_EVENT_DEFOCUSED) {
@ -518,14 +547,9 @@ void generic_event_handler(lv_obj_t* obj, lv_event_t event)
if(last_value_sent == HASP_EVENT_LOST) return; if(last_value_sent == HASP_EVENT_LOST) return;
if(const char* action = my_obj_get_action(obj)) {
char eventname[8];
Parser::get_event_name(last_value_sent, eventname, sizeof(eventname));
script_event_handler(eventname, action);
} else {
char data[512]; char data[512];
{
char eventname[8]; char eventname[8];
{
Parser::get_event_name(last_value_sent, eventname, sizeof(eventname)); Parser::get_event_name(last_value_sent, eventname, sizeof(eventname));
if(const char* tag = my_obj_get_tag(obj)) if(const char* tag = my_obj_get_tag(obj))
@ -533,8 +557,7 @@ void generic_event_handler(lv_obj_t* obj, lv_event_t event)
else else
snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\"}"), eventname); snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\"}"), eventname);
} }
event_send_object_data(obj, data); event_send_object_data(obj, eventname, data);
}
// Update group objects and gpios on release // Update group objects and gpios on release
if(last_value_sent != LV_EVENT_LONG_PRESSED && last_value_sent != LV_EVENT_LONG_PRESSED_REPEAT) { if(last_value_sent != LV_EVENT_LONG_PRESSED && last_value_sent != LV_EVENT_LONG_PRESSED_REPEAT) {
@ -841,8 +864,8 @@ void cpicker_event_handler(lv_obj_t* obj, lv_event_t event)
if(hasp_event_id == HASP_EVENT_CHANGED && last_color_sent.full == color.full) return; // same value as before if(hasp_event_id == HASP_EVENT_CHANGED && last_color_sent.full == color.full) return; // same value as before
char data[512]; char data[512];
{
char eventname[8]; char eventname[8];
{
Parser::get_event_name(hasp_event_id, eventname, sizeof(eventname)); Parser::get_event_name(hasp_event_id, eventname, sizeof(eventname));
lv_color32_t c32; lv_color32_t c32;
@ -864,7 +887,7 @@ void cpicker_event_handler(lv_obj_t* obj, lv_event_t event)
eventname, c32.ch.red, c32.ch.green, c32.ch.blue, c32.ch.red, c32.ch.green, c32.ch.blue, hsv.h, 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); hsv.s, hsv.v);
} }
event_send_object_data(obj, data); event_send_object_data(obj, eventname, data);
// event_update_group(obj->user_data.groupid, obj, val, min, max); // event_update_group(obj->user_data.groupid, obj, val, min, max);
} }
@ -891,8 +914,8 @@ void calendar_event_handler(lv_obj_t* obj, lv_event_t event)
return; // same object and value as before return; // same object and value as before
char data[512]; char data[512];
{
char eventname[8]; char eventname[8];
{
Parser::get_event_name(hasp_event_id, eventname, sizeof(eventname)); Parser::get_event_name(hasp_event_id, eventname, sizeof(eventname));
last_value_sent = val; last_value_sent = val;
@ -907,7 +930,7 @@ void calendar_event_handler(lv_obj_t* obj, lv_event_t event)
PSTR("{\"event\":\"%s\",\"val\":\"%d\",\"text\":\"%04d-%02d-%02dT00:00:00Z\"}"), eventname, PSTR("{\"event\":\"%s\",\"val\":\"%d\",\"text\":\"%04d-%02d-%02dT00:00:00Z\"}"), eventname,
date->day, date->year, date->month, date->day); date->day, date->year, date->month, date->day);
} }
event_send_object_data(obj, data); event_send_object_data(obj, eventname, data);
// event_update_group(obj->user_data.groupid, obj, val, min, max); // event_update_group(obj->user_data.groupid, obj, val, min, max);
} }

View File

@ -34,7 +34,8 @@ build_flags =
-D HASP_USE_GIFDECODE=0 -D HASP_USE_GIFDECODE=0
-D HASP_USE_JPGDECODE=0 -D HASP_USE_JPGDECODE=0
-D HASP_USE_MQTT=1 -D HASP_USE_MQTT=1
-D MQTT_MAX_PACKET_SIZE=2048 -D HASP_USE_EVENT_DATA_SUBST=1
-D MQTT_MAX_PACKET_SIZE=32768
-D HASP_ATTRIBUTE_FAST_MEM= -D HASP_ATTRIBUTE_FAST_MEM=
-D IRAM_ATTR= ; No IRAM_ATTR available -D IRAM_ATTR= ; No IRAM_ATTR available
-D PROGMEM= ; No PROGMEM available -D PROGMEM= ; No PROGMEM available

View File

@ -31,7 +31,8 @@ build_flags =
-D HASP_USE_JPGDECODE=0 -D HASP_USE_JPGDECODE=0
-D HASP_USE_MQTT=1 -D HASP_USE_MQTT=1
-D HASP_USE_LVGL_TASK=1 -D HASP_USE_LVGL_TASK=1
-D MQTT_MAX_PACKET_SIZE=2048 -D HASP_USE_EVENT_DATA_SUBST=1
-D MQTT_MAX_PACKET_SIZE=32768
-D HASP_ATTRIBUTE_FAST_MEM= -D HASP_ATTRIBUTE_FAST_MEM=
-D IRAM_ATTR= ; No IRAM_ATTR available -D IRAM_ATTR= ; No IRAM_ATTR available
-D PROGMEM= ; No PROGMEM available -D PROGMEM= ; No PROGMEM available

View File

@ -34,7 +34,8 @@ build_flags =
-D HASP_USE_GIFDECODE=0 -D HASP_USE_GIFDECODE=0
-D HASP_USE_JPGDECODE=0 -D HASP_USE_JPGDECODE=0
-D HASP_USE_MQTT=1 -D HASP_USE_MQTT=1
-D MQTT_MAX_PACKET_SIZE=2048 -D HASP_USE_EVENT_DATA_SUBST=1
-D MQTT_MAX_PACKET_SIZE=32768
-D HASP_ATTRIBUTE_FAST_MEM= -D HASP_ATTRIBUTE_FAST_MEM=
-D IRAM_ATTR= ; No IRAM_ATTR available -D IRAM_ATTR= ; No IRAM_ATTR available
-D PROGMEM= ; No PROGMEM available -D PROGMEM= ; No PROGMEM available

View File

@ -30,7 +30,8 @@ build_flags =
-D HASP_USE_MQTT=1 -D HASP_USE_MQTT=1
-D HASP_USE_SYSLOG=0 -D HASP_USE_SYSLOG=0
-D HASP_USE_LVGL_TASK=1 -D HASP_USE_LVGL_TASK=1
-D MQTT_MAX_PACKET_SIZE=2048 -D HASP_USE_EVENT_DATA_SUBST=1
-D MQTT_MAX_PACKET_SIZE=32768
-D HASP_ATTRIBUTE_FAST_MEM= -D HASP_ATTRIBUTE_FAST_MEM=
-D IRAM_ATTR= ; No IRAM_ATTR available -D IRAM_ATTR= ; No IRAM_ATTR available
-D PROGMEM= ; No PROGMEM available -D PROGMEM= ; No PROGMEM available

View File

@ -34,7 +34,8 @@ build_flags =
-D HASP_USE_JPGDECODE=0 -D HASP_USE_JPGDECODE=0
-D HASP_USE_MQTT=1 -D HASP_USE_MQTT=1
-D HASP_USE_SYSLOG=0 -D HASP_USE_SYSLOG=0
-D MQTT_MAX_PACKET_SIZE=2048 -D HASP_USE_EVENT_DATA_SUBST=1
-D MQTT_MAX_PACKET_SIZE=32768
-D HASP_ATTRIBUTE_FAST_MEM= -D HASP_ATTRIBUTE_FAST_MEM=
-D IRAM_ATTR= ; No IRAM_ATTR available -D IRAM_ATTR= ; No IRAM_ATTR available
-D PROGMEM= ; No PROGMEM available -D PROGMEM= ; No PROGMEM available