From 559caeb30f63d652001a18e0101cc64e0110f33f Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Fri, 19 Jul 2024 12:45:27 +0200 Subject: [PATCH] schedulder enhancement url json #1806 --- src/web/WebSchedulerService.cpp | 38 +++++++++++++++++--- src/web/shuntingYard.hpp | 63 ++++++++++++++++++++++++++++++++- 2 files changed, 95 insertions(+), 6 deletions(-) diff --git a/src/web/WebSchedulerService.cpp b/src/web/WebSchedulerService.cpp index 88abddcb1..41f3f0d99 100644 --- a/src/web/WebSchedulerService.cpp +++ b/src/web/WebSchedulerService.cpp @@ -18,6 +18,7 @@ #include "emsesp.h" #include "WebSchedulerService.h" +#include namespace emsesp { @@ -330,6 +331,33 @@ bool WebSchedulerService::has_commands() { // execute scheduled command bool WebSchedulerService::command(const char * name, const char * cmd, const char * data) { + // check http commands. e.g. + // tasmota(get): http:///cm?cmnd=power%20ON + // shelly(get): http:///relais/0?turn=on + const char * c = strchr(cmd, '{'); + if (c) { // parse json + JsonDocument doc; + int httpResult = 0; + if (DeserializationError::Ok == deserializeJson(doc, c)) { + HTTPClient http; + String url = doc["url"]; + if (http.begin(url)) { + for (JsonPair p : doc["header"].as()) { + http.addHeader(p.key().c_str(), p.value().as().c_str()); + } + String value = doc["value"] | ""; + if (value.length()) { + httpResult = http.POST(value); + } else if (data && data[0] != '\0') { // post + httpResult = http.POST(String(data)); + } else { + httpResult = http.GET(); + } + http.end(); + } + } + return httpResult > 0; + } JsonDocument doc_input; JsonObject input = doc_input.to(); if (strlen(data)) { // empty data queries a value @@ -390,12 +418,12 @@ void WebSchedulerService::condition() { #ifdef EMESESP_DEBUG // emsesp::EMSESP::logger().debug("condition match: %s", match.c_str()); #endif - if (!match.empty() && match[0] == '1') { - if (scheduleItem.retry_cnt == 0xFF) { // default unswitched - scheduleItem.retry_cnt = command(scheduleItem.name.c_str(), scheduleItem.cmd.c_str(), compute(scheduleItem.value).c_str()) ? 1 : 0xFF; - } - } else if (scheduleItem.retry_cnt == 1) { + if (match.length() == 1 && match[0] == '1' && scheduleItem.retry_cnt == 0xFF) { + scheduleItem.retry_cnt = command(scheduleItem.name.c_str(), scheduleItem.cmd.c_str(), compute(scheduleItem.value).c_str()) ? 1 : 0xFF; + } else if (match.length() == 1 && match[0] == '0' && scheduleItem.retry_cnt == 1) { scheduleItem.retry_cnt = 0xFF; + } else if (match.length() != 1) { // the match is not boolean + emsesp::EMSESP::logger().debug("condition result: %s", match.c_str()); } } } diff --git a/src/web/shuntingYard.hpp b/src/web/shuntingYard.hpp index d4f3a7e25..7fcd1be93 100644 --- a/src/web/shuntingYard.hpp +++ b/src/web/shuntingYard.hpp @@ -63,6 +63,22 @@ std::deque exprToTokens(const std::string & expr) { for (const auto * p = expr.c_str(); *p; ++p) { if (isblank(*p)) { // do nothing + } else if (*p == '{') { // json is stored as string including {} + const auto * b = p; + ++p; + uint8_t i = 1; + while (*p && i > 0) { + i += (*p == '{') ? 1 : (*p == '}') ? -1 : 0; + ++p; + } + if (*p) { + ++p; + } + const auto s = std::string(b, p); + tokens.push_back(Token{Token::Type::String, s, -3}); + if (*p == '\0') { + --p; + } } else if (*p >= 'a' && *p <= 'z') { const auto * b = p; while ((*p >= 'a' && *p <= 'z') || (*p == '_')) { @@ -579,7 +595,52 @@ std::string calculate(const std::string & expr) { // check for multiple instances of ? : std::string compute(const std::string & expr) { - auto expr_new = expr; + auto expr_new = emsesp::Helpers::toLower(expr); + + // search json with url: + auto f = expr_new.find_first_of("{"); + while (f != std::string::npos) { + auto e = f + 1; + for (uint8_t i = 1; i > 0; e++) { + if (e >= expr_new.length()) { + return ""; + } else if (expr_new[e] == '}') { + i--; + } else if (expr_new[e] == '{') { + i++; + } + } + std::string cmd = expr_new.substr(f, e - f).c_str(); + JsonDocument doc; + if (DeserializationError::Ok == deserializeJson(doc, cmd)) { + HTTPClient http; + String url = doc["url"]; + if (http.begin(url)) { + int httpResult = 0; + for (JsonPair p : doc["header"].as()) { + http.addHeader(p.key().c_str(), p.value().as().c_str()); + } + String data = doc["value"] | ""; + if (data.length()) { + httpResult = http.POST(data); + } else { + httpResult = http.GET(); + } + if (httpResult > 0) { + std::string result = emsesp::Helpers::toLower(http.getString().c_str()); + String key = doc["key"] | ""; + doc.clear(); + if (key.length() && DeserializationError::Ok == deserializeJson(doc, result)) { + result = doc[key.c_str()].as(); + } + expr_new.replace(f, e - f, result.c_str()); + } + http.end(); + } + } + f = expr_new.find_first_of("{", e); + } + // positions: q-questionmark, c-colon auto q = expr_new.find_first_of("?"); while (q != std::string::npos) {