Scheduler with type "Immediate", click Execute does not run the command

Fixes #3092
This commit is contained in:
proddy
2026-05-25 12:28:42 +02:00
parent a406d6d911
commit ace071e974
8 changed files with 78 additions and 155 deletions

View File

@@ -137,6 +137,7 @@ bool WebSchedulerService::command_setvalue(const char * value, const int8_t id,
if (EMSESP::mqtt_.get_publish_onchange(0)) {
publish();
}
// save new state to nvs #2946
if (scheduleItem.flags != SCHEDULEFLAG_SCHEDULE_IMMEDIATE) {
char key[sizeof(scheduleItem.name) + 2];
@@ -343,6 +344,7 @@ uint8_t WebSchedulerService::count_entities(bool cmd_only) {
}
// execute scheduled command
// return true if successful, false if not
bool WebSchedulerService::command(const char * name, const std::string & command, const std::string & data) {
std::string cmd = Helpers::toLower(command);
@@ -365,130 +367,10 @@ bool WebSchedulerService::command(const char * name, const std::string & command
std::string value = doc["value"] | data; // extract value if its in the command, or take the data
std::string method = doc["method"] | "GET"; // default GET
commands(value, false);
if (value.length()) {
method = "POST";
}
std::string result;
int httpResult = 0;
#ifndef NO_TLS_SUPPORT
if (Helpers::toLower(url.c_str()).starts_with("https://")) {
WiFiClient * basic_client = new WiFiClient;
ESP_SSLClient * ssl_client = new ESP_SSLClient;
ssl_client->setInsecure(); // with root CA we should set here: ssl_client->setCACert(rootCACert);
ssl_client->setBufferSizes(1024, 1024);
ssl_client->setSessionTimeout(120); // Set the timeout in seconds (>=120 seconds)
url.replace(0, 8, "");
std::string host = url;
auto index = url.find_first_of('/');
if (index != std::string::npos) {
host = url.substr(0, index);
url.replace(0, index, "");
}
// EMSESP::logger().debug("Host: %s, URL: %s", host.c_str(), url.c_str());
ssl_client->setClient(basic_client);
if (ssl_client->connect(host.c_str(), 443)) {
if (value.length() || Helpers::toLower(method) == "post") {
// EMSESP::logger().debug("POST %s HTTP/1.1", url.c_str());
ssl_client->print("POST ");
ssl_client->print(url.c_str());
ssl_client->println(" HTTP/1.1");
ssl_client->print("Host: ");
ssl_client->println(host.c_str());
bool content_set = false;
for (JsonPair p : doc["header"].as<JsonObject>()) {
content_set |= (emsesp::Helpers::toLower(p.key().c_str()) == "content-type");
ssl_client->print(p.key().c_str());
ssl_client->print(": ");
ssl_client->println(p.value().as<std::string>().c_str());
}
if (!content_set) {
ssl_client->print("Content-Type: ");
if (value.starts_with('{')) {
ssl_client->println(asyncsrv::T_application_json);
} else {
ssl_client->println(asyncsrv::T_text_plain);
}
}
ssl_client->print("Content-Length: ");
ssl_client->println(value.length());
ssl_client->println("Connection: close");
ssl_client->print("\r\n");
ssl_client->print(value.c_str());
} else {
// EMSESP::logger().debug("GET %s HTTP/1.1", url.c_str());
ssl_client->print("GET ");
ssl_client->print(url.c_str());
ssl_client->println(" HTTP/1.1");
ssl_client->print("Host: ");
ssl_client->println(host.c_str());
for (JsonPair p : doc["header"].as<JsonObject>()) {
ssl_client->print(p.key().c_str());
ssl_client->print(": ");
ssl_client->println(p.value().as<std::string>().c_str());
}
ssl_client->println("Connection: close");
}
auto ms = millis();
while (ssl_client->connected() && !ssl_client->available() && millis() - ms < 3000) {
delay(0);
}
while (ssl_client->available()) {
result += (char)ssl_client->read();
}
ssl_client->stop();
// EMSESP::logger().debug("HTTPS response: %s", result.c_str());
index = result.find_first_of(' ');
if (index != std::string::npos) {
httpResult = stoi(result.substr(index + 1, 3));
// EMSESP::logger().debug("HTTPS code: %i", httpResult);
}
index = result.find("\r\n\r\n");
if (index != std::string::npos) {
result.replace(0, index + 4, "");
// EMSESP::logger().debug("HTTPS response: %s", result.c_str());
}
} else {
EMSESP::logger().warning("HTTPS connection failed");
}
delete ssl_client;
delete basic_client;
// check HTTP return code
if (httpResult != 200) {
EMSESP::logger().warning("Schedule '%s': URL command failed with http code %d", name, httpResult);
return false;
}
return true;
} else
#endif
if (Helpers::toLower(url.c_str()).starts_with("http://")) {
HTTPClient * http = new HTTPClient;
if (http->begin(url.c_str())) {
bool content_set = false;
for (JsonPair p : doc["header"].as<JsonObject>()) {
http->addHeader(p.key().c_str(), p.value().as<std::string>().c_str());
content_set |= p.key() == "content-type";
}
// if there is data, force a POST
if (Helpers::toLower(method) == "post") { // we have all lowercase
if (!content_set) {
// http->addHeader("Content-Type", value.find_first_of('{') != std::string::npos ? "application/json" : "text/plain");
if (value.starts_with('{')) {
http->addHeader(asyncsrv::T_Content_Type, asyncsrv::T_application_json, false); // auto-set to JSON
} else {
http->addHeader(asyncsrv::T_Content_Type, asyncsrv::T_text_plain, false); // auto-set to JSON
}
}
httpResult = http->POST(value.c_str());
} else {
httpResult = http->GET(); // normal GET
if (httpResult > 0) {
result = http->getString().c_str();
}
}
}
http->end();
delete http;
// check HTTP return code
auto lower_url = Helpers::toLower(url.c_str());
if (lower_url.starts_with("http://") || lower_url.starts_with("https://")) {
std::string result;
int httpResult = http_request(url, method, value, doc["header"].as<JsonObjectConst>(), result);
if (httpResult != 200) {
EMSESP::logger().warning("Schedule '%s': URL command failed with http code %d", name, httpResult);
return false;
@@ -598,7 +480,7 @@ void WebSchedulerService::loop() {
for (ScheduleItem & scheduleItem : *scheduleItems_) {
if (scheduleItem.active && scheduleItem.flags == SCHEDULEFLAG_SCHEDULE_IMMEDIATE) {
command(scheduleItem.name, scheduleItem.cmd.c_str(), compute(scheduleItem.value.c_str()));
scheduleItem.active = false;
// scheduleItem.active = false;
publish_single(scheduleItem.name, false);
if (EMSESP::mqtt_.get_publish_onchange(0)) {
publish();
@@ -659,6 +541,18 @@ void WebSchedulerService::loop() {
}
}
// execute a schedule item immediately
bool WebSchedulerService::executeSchedule(const char * name) {
for (ScheduleItem & scheduleItem : *scheduleItems_) {
if (scheduleItem.flags == SCHEDULEFLAG_SCHEDULE_IMMEDIATE && strcmp(scheduleItem.name, name) == 0) {
EMSESP::logger().info("Executing schedule '%s'", name);
return command(scheduleItem.name, scheduleItem.cmd.c_str(), compute(scheduleItem.value.c_str()));
}
}
EMSESP::logger().warning("Schedule '%s' not found", name);
return false; // not found
}
// process schedules async
void WebSchedulerService::scheduler_task(void * pvParameters) {
while (1) {

View File

@@ -88,6 +88,8 @@ class WebSchedulerService : public StatefulService<WebScheduler> {
uint8_t count_entities(bool cmd_only = false);
bool onChange(const char * cmd);
bool executeSchedule(const char * name);
std::string get_metrics_prometheus();
std::string raw_value;

View File

@@ -227,6 +227,8 @@ void WebStatusService::action(AsyncWebServerRequest * request, JsonVariant json)
EMSESP::mqtt_.reset_mqtt();
} else if (action == "upgradeImportantMessages") {
root["upgradeImportantMessageType"] = upgradeImportantMessages(param);
} else if (action == "executeSchedule") {
ok = EMSESP::webSchedulerService.executeSchedule(param.c_str());
}
#if defined(EMSESP_STANDALONE) && !defined(EMSESP_UNITY)