mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-06 07:49:52 +03:00
scheduler, small fixes, allow commands in json get url
This commit is contained in:
@@ -51,9 +51,9 @@ void WebScheduler::read(WebScheduler & webScheduler, JsonObject root) {
|
|||||||
for (const ScheduleItem & scheduleItem : webScheduler.scheduleItems) {
|
for (const ScheduleItem & scheduleItem : webScheduler.scheduleItems) {
|
||||||
JsonObject si = schedule.add<JsonObject>();
|
JsonObject si = schedule.add<JsonObject>();
|
||||||
si["id"] = counter++; // id is only used to render the table and must be unique
|
si["id"] = counter++; // id is only used to render the table and must be unique
|
||||||
si["active"] = scheduleItem.flags ? scheduleItem.active : false;
|
|
||||||
si["flags"] = scheduleItem.flags;
|
si["flags"] = scheduleItem.flags;
|
||||||
si["time"] = scheduleItem.time;
|
si["active"] = scheduleItem.flags != SCHEDULEFLAG_SCHEDULE_IMMEDIATE ? scheduleItem.active : false;
|
||||||
|
si["time"] = scheduleItem.flags != SCHEDULEFLAG_SCHEDULE_IMMEDIATE ? scheduleItem.time : "";
|
||||||
si["cmd"] = scheduleItem.cmd;
|
si["cmd"] = scheduleItem.cmd;
|
||||||
si["value"] = scheduleItem.value;
|
si["value"] = scheduleItem.value;
|
||||||
si["name"] = scheduleItem.name;
|
si["name"] = scheduleItem.name;
|
||||||
@@ -76,7 +76,7 @@ StateUpdateResult WebScheduler::update(JsonObject root, WebScheduler & webSchedu
|
|||||||
auto si = ScheduleItem();
|
auto si = ScheduleItem();
|
||||||
si.active = schedule["active"];
|
si.active = schedule["active"];
|
||||||
si.flags = schedule["flags"];
|
si.flags = schedule["flags"];
|
||||||
si.time = schedule["time"].as<std::string>();
|
si.time = si.flags == SCHEDULEFLAG_SCHEDULE_IMMEDIATE ? "" : schedule["time"].as<std::string>();
|
||||||
si.cmd = schedule["cmd"].as<std::string>();
|
si.cmd = schedule["cmd"].as<std::string>();
|
||||||
si.value = schedule["value"].as<std::string>();
|
si.value = schedule["value"].as<std::string>();
|
||||||
si.name = schedule["name"].as<std::string>();
|
si.name = schedule["name"].as<std::string>();
|
||||||
@@ -322,6 +322,8 @@ bool WebSchedulerService::has_commands() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include "shuntingYard.hpp"
|
||||||
|
|
||||||
// execute scheduled command
|
// execute scheduled command
|
||||||
bool WebSchedulerService::command(const char * name, const std::string & command, const std::string & data) {
|
bool WebSchedulerService::command(const char * name, const std::string & command, const std::string & data) {
|
||||||
std::string cmd = Helpers::toLower(command);
|
std::string cmd = Helpers::toLower(command);
|
||||||
@@ -331,13 +333,19 @@ bool WebSchedulerService::command(const char * name, const std::string & command
|
|||||||
// shelly(get): http://<shellyIP>/relais/0?turn=on
|
// shelly(get): http://<shellyIP>/relais/0?turn=on
|
||||||
// parse json
|
// parse json
|
||||||
JsonDocument doc;
|
JsonDocument doc;
|
||||||
if (DeserializationError::Ok == deserializeJson(doc, cmd)) {
|
if (deserializeJson(doc, cmd) == DeserializationError::Ok) {
|
||||||
HTTPClient http;
|
HTTPClient http;
|
||||||
int httpResult = 0;
|
int httpResult = 0;
|
||||||
String url = doc["url"];
|
String url = doc["url"] | "";
|
||||||
if (http.begin(url)) {
|
// for a GET with parameters replace commands with values
|
||||||
// It's an HTTP call
|
auto q = url.indexOf('?');
|
||||||
|
if (q != -1) {
|
||||||
|
auto s = url.substring(q + 1);
|
||||||
|
std::string v = s.c_str();
|
||||||
|
commands(v, false);
|
||||||
|
url.replace(s, v.c_str());
|
||||||
|
}
|
||||||
|
if (url.startsWith("http") && http.begin(url)) {
|
||||||
// add any given headers
|
// add any given headers
|
||||||
for (JsonPair p : doc["header"].as<JsonObject>()) {
|
for (JsonPair p : doc["header"].as<JsonObject>()) {
|
||||||
http.addHeader(p.key().c_str(), p.value().as<String>().c_str());
|
http.addHeader(p.key().c_str(), p.value().as<String>().c_str());
|
||||||
@@ -424,8 +432,6 @@ bool WebSchedulerService::onChange(const char * cmd) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "shuntingYard.hpp"
|
|
||||||
|
|
||||||
// handle condition schedules, parse string stored in schedule.time field
|
// handle condition schedules, parse string stored in schedule.time field
|
||||||
void WebSchedulerService::condition() {
|
void WebSchedulerService::condition() {
|
||||||
for (ScheduleItem & scheduleItem : *scheduleItems_) {
|
for (ScheduleItem & scheduleItem : *scheduleItems_) {
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
|
|
||||||
class Token {
|
class Token {
|
||||||
public:
|
public:
|
||||||
enum class Type {
|
enum class Type : uint8_t {
|
||||||
Unknown,
|
Unknown,
|
||||||
Number,
|
Number,
|
||||||
String,
|
String,
|
||||||
@@ -332,12 +332,13 @@ bool isnum(const std::string & s) {
|
|||||||
|
|
||||||
|
|
||||||
// replace commands like "<device>/<hc>/<cmd>" with its value"
|
// replace commands like "<device>/<hc>/<cmd>" with its value"
|
||||||
std::string commands(std::string & expr) {
|
std::string commands(std::string & expr, bool quotes = true) {
|
||||||
for (uint8_t device = 0; device < emsesp::EMSdevice::DeviceType::UNKNOWN; device++) {
|
for (uint8_t device = 0; device < emsesp::EMSdevice::DeviceType::UNKNOWN; device++) {
|
||||||
const char * d = emsesp::EMSdevice::device_type_2_device_name(device);
|
const char * d = emsesp::EMSdevice::device_type_2_device_name(device);
|
||||||
auto f = expr.find(d);
|
auto f = expr.find(d);
|
||||||
while (f != std::string::npos) {
|
while (f != std::string::npos) {
|
||||||
auto e = expr.find_first_of(")=<>|&+-*!", f);
|
// entity names are alphanumeric or _
|
||||||
|
auto e = expr.find_first_not_of("/._abcdefghijklmnopqrstuvwxyz0123456789", f);
|
||||||
if (e == std::string::npos) {
|
if (e == std::string::npos) {
|
||||||
e = expr.length();
|
e = expr.length();
|
||||||
}
|
}
|
||||||
@@ -361,7 +362,7 @@ std::string commands(std::string & expr) {
|
|||||||
emsesp::Command::process(cmd_s.c_str(), true, input, output);
|
emsesp::Command::process(cmd_s.c_str(), true, input, output);
|
||||||
if (output.containsKey("api_data")) {
|
if (output.containsKey("api_data")) {
|
||||||
std::string data = output["api_data"].as<std::string>();
|
std::string data = output["api_data"].as<std::string>();
|
||||||
if (!isnum(data)) {
|
if (!isnum(data) && quotes) {
|
||||||
data.insert(data.begin(), '"');
|
data.insert(data.begin(), '"');
|
||||||
data.insert(data.end(), '"');
|
data.insert(data.end(), '"');
|
||||||
}
|
}
|
||||||
@@ -596,7 +597,7 @@ std::string compute(const std::string & expr) {
|
|||||||
auto expr_new = emsesp::Helpers::toLower(expr);
|
auto expr_new = emsesp::Helpers::toLower(expr);
|
||||||
|
|
||||||
// search json with url:
|
// search json with url:
|
||||||
auto f = expr_new.find_first_of("{");
|
auto f = expr_new.find_first_of('{');
|
||||||
while (f != std::string::npos) {
|
while (f != std::string::npos) {
|
||||||
auto e = f + 1;
|
auto e = f + 1;
|
||||||
for (uint8_t i = 1; i > 0; e++) {
|
for (uint8_t i = 1; i > 0; e++) {
|
||||||
@@ -612,8 +613,8 @@ std::string compute(const std::string & expr) {
|
|||||||
JsonDocument doc;
|
JsonDocument doc;
|
||||||
if (DeserializationError::Ok == deserializeJson(doc, cmd)) {
|
if (DeserializationError::Ok == deserializeJson(doc, cmd)) {
|
||||||
HTTPClient http;
|
HTTPClient http;
|
||||||
String url = doc["url"];
|
String url = doc["url"] | "";
|
||||||
if (http.begin(url)) {
|
if (url.startsWith("http") && http.begin(url)) {
|
||||||
int httpResult = 0;
|
int httpResult = 0;
|
||||||
for (JsonPair p : doc["header"].as<JsonObject>()) {
|
for (JsonPair p : doc["header"].as<JsonObject>()) {
|
||||||
http.addHeader(p.key().c_str(), p.value().as<std::string>().c_str());
|
http.addHeader(p.key().c_str(), p.value().as<std::string>().c_str());
|
||||||
@@ -647,20 +648,22 @@ std::string compute(const std::string & expr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// positions: q-questionmark, c-colon
|
// positions: q-questionmark, c-colon
|
||||||
auto q = expr_new.find_first_of("?");
|
auto q = expr_new.find_first_of('?');
|
||||||
while (q != std::string::npos) {
|
while (q != std::string::npos) {
|
||||||
// find corresponding colon
|
// find corresponding colon
|
||||||
auto c1 = expr_new.find_first_of(":", q + 1);
|
auto c1 = expr_new.find_first_of(':', q + 1);
|
||||||
auto q1 = expr_new.find_first_of("?", q + 1);
|
auto q1 = expr_new.find_first_of('?', q + 1);
|
||||||
while (q1 < c1 && q1 != std::string::npos && c1 != std::string::npos) {
|
while (q1 < c1 && q1 != std::string::npos && c1 != std::string::npos) {
|
||||||
q1 = expr_new.find_first_of("?", q1 + 1);
|
q1 = expr_new.find_first_of('?', q1 + 1);
|
||||||
c1 = expr_new.find_first_of(":", c1 + 1);
|
c1 = expr_new.find_first_of(':', c1 + 1);
|
||||||
}
|
}
|
||||||
if (c1 == std::string::npos) {
|
if (c1 == std::string::npos) {
|
||||||
return ""; // error: missing colon
|
return ""; // error: missing colon
|
||||||
}
|
}
|
||||||
std::string cond = calculate(expr_new.substr(0, q));
|
std::string cond = calculate(expr_new.substr(0, q));
|
||||||
if (cond[0] == '1') {
|
if (cond.length() == 0) {
|
||||||
|
return "";
|
||||||
|
} else if (cond[0] == '1') {
|
||||||
expr_new.erase(c1); // remove second expression after colon
|
expr_new.erase(c1); // remove second expression after colon
|
||||||
expr_new.erase(0, q + 1); // remove condition before questionmark
|
expr_new.erase(0, q + 1); // remove condition before questionmark
|
||||||
} else if (cond[0] == '0') {
|
} else if (cond[0] == '0') {
|
||||||
@@ -668,7 +671,7 @@ std::string compute(const std::string & expr) {
|
|||||||
} else {
|
} else {
|
||||||
return ""; // error
|
return ""; // error
|
||||||
}
|
}
|
||||||
q = expr_new.find_first_of("?"); // search next instance
|
q = expr_new.find_first_of('?'); // search next instance
|
||||||
}
|
}
|
||||||
|
|
||||||
return calculate(expr_new);
|
return calculate(expr_new);
|
||||||
|
|||||||
Reference in New Issue
Block a user