mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-08 08:49:52 +03:00
Merge remote-tracking branch 'origin/tech-upgrade' into dev
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* EMS-ESP - https://github.com/emsesp/EMS-ESP
|
||||
* Copyright 2020 Paul Derbyshire
|
||||
* Copyright 2020-2023 Paul Derbyshire
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -100,8 +100,11 @@ void WebAPIService::parse(AsyncWebServerRequest * request, JsonObject & input) {
|
||||
}
|
||||
}
|
||||
|
||||
// capture current heap memory before allocating the large return buffer
|
||||
emsesp::EMSESP::system_.refreshHeapMem();
|
||||
|
||||
// output json buffer
|
||||
size_t buffer = EMSESP_JSON_SIZE_XXLARGE_DYN;
|
||||
size_t buffer = EMSESP_JSON_SIZE_XXXLARGE;
|
||||
auto * response = new PrettyAsyncJsonResponse(false, buffer);
|
||||
while (!response->getSize()) {
|
||||
delete response;
|
||||
@@ -123,7 +126,6 @@ void WebAPIService::parse(AsyncWebServerRequest * request, JsonObject & input) {
|
||||
emsesp::EMSESP::logger().err(error);
|
||||
api_fails_++;
|
||||
} else {
|
||||
// emsesp::EMSESP::logger().debug("API command called successfully");
|
||||
// if there was no json output from the call, default to the output message 'OK'.
|
||||
if (!output.size()) {
|
||||
output["message"] = "OK";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* EMS-ESP - https://github.com/emsesp/EMS-ESP
|
||||
* Copyright 2020 Paul Derbyshire
|
||||
* Copyright 2020-2023 Paul Derbyshire
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* EMS-ESP - https://github.com/emsesp/EMS-ESP
|
||||
* Copyright 2020 Paul Derbyshire
|
||||
* Copyright 2020-2023 Paul Derbyshire
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -178,7 +178,7 @@ void WebCustomizationService::reset_customization(AsyncWebServerRequest * reques
|
||||
|
||||
// send back a list of devices used in the customization web page
|
||||
void WebCustomizationService::devices(AsyncWebServerRequest * request) {
|
||||
auto * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_LARGE_DYN);
|
||||
auto * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_XLARGE);
|
||||
JsonObject root = response->getRoot();
|
||||
|
||||
// list is already sorted by device type
|
||||
@@ -201,7 +201,7 @@ void WebCustomizationService::devices(AsyncWebServerRequest * request) {
|
||||
// send back list of device entities
|
||||
void WebCustomizationService::device_entities(AsyncWebServerRequest * request, JsonVariant & json) {
|
||||
if (json.is<JsonObject>()) {
|
||||
size_t buffer = EMSESP_JSON_SIZE_XXXLARGE_DYN;
|
||||
size_t buffer = EMSESP_JSON_SIZE_XXXXLARGE;
|
||||
auto * response = new MsgpackAsyncJsonResponse(true, buffer);
|
||||
while (!response->getSize()) {
|
||||
delete response;
|
||||
@@ -328,4 +328,4 @@ void WebCustomizationService::begin() {
|
||||
_fsPersistence.readFromFS();
|
||||
}
|
||||
|
||||
} // namespace emsesp
|
||||
} // namespace emsesp
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* EMS-ESP - https://github.com/emsesp/EMS-ESP
|
||||
* Copyright 2020 Paul Derbyshire
|
||||
* Copyright 2020-2023 Paul Derbyshire
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* EMS-ESP - https://github.com/emsesp/EMS-ESP
|
||||
* Copyright 2020 Paul Derbyshire
|
||||
* Copyright 2020-2023 Paul Derbyshire
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -70,7 +70,7 @@ void WebDataService::scan_devices(AsyncWebServerRequest * request) {
|
||||
// this is used in the dashboard and contains all ems device information
|
||||
// /coreData endpoint
|
||||
void WebDataService::core_data(AsyncWebServerRequest * request) {
|
||||
auto * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_XLARGE_DYN);
|
||||
auto * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_XXLARGE);
|
||||
JsonObject root = response->getRoot();
|
||||
|
||||
// list is already sorted by device type
|
||||
@@ -83,7 +83,7 @@ void WebDataService::core_data(AsyncWebServerRequest * request) {
|
||||
obj["id"] = Helpers::smallitoa(buffer, emsdevice->unique_id()); // a unique id as a string
|
||||
obj["tn"] = emsdevice->device_type_2_device_name_translated(); // translated device type name
|
||||
obj["t"] = emsdevice->device_type(); // device type number
|
||||
obj["b"] = emsdevice->brand_to_string(); // brand
|
||||
obj["b"] = emsdevice->brand_to_char(); // brand
|
||||
obj["n"] = emsdevice->name(); // name
|
||||
obj["d"] = emsdevice->device_id(); // deviceid
|
||||
obj["p"] = emsdevice->product_id(); // productid
|
||||
@@ -106,7 +106,7 @@ void WebDataService::core_data(AsyncWebServerRequest * request) {
|
||||
// /sensorData endpoint
|
||||
// the "sensors" and "analogs" are arrays and must exist
|
||||
void WebDataService::sensor_data(AsyncWebServerRequest * request) {
|
||||
auto * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_XLARGE_DYN);
|
||||
auto * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_XXLARGE);
|
||||
JsonObject root = response->getRoot();
|
||||
|
||||
// dallas sensors
|
||||
@@ -167,7 +167,7 @@ void WebDataService::sensor_data(AsyncWebServerRequest * request) {
|
||||
// Compresses the JSON using MsgPack https://msgpack.org/index.html
|
||||
void WebDataService::device_data(AsyncWebServerRequest * request, JsonVariant & json) {
|
||||
if (json.is<JsonObject>()) {
|
||||
size_t buffer = EMSESP_JSON_SIZE_XXXLARGE_DYN;
|
||||
size_t buffer = EMSESP_JSON_SIZE_XXXXLARGE;
|
||||
auto * response = new MsgpackAsyncJsonResponse(false, buffer);
|
||||
while (!response->getSize()) {
|
||||
delete response;
|
||||
@@ -186,12 +186,6 @@ void WebDataService::device_data(AsyncWebServerRequest * request, JsonVariant &
|
||||
emsdevice->generate_values_web(output);
|
||||
#endif
|
||||
|
||||
// #ifdef EMSESP_USE_SERIAL
|
||||
// #ifdef EMSESP_DEBUG
|
||||
// serializeJson(output, Serial);
|
||||
// #endif
|
||||
// #endif
|
||||
|
||||
#if defined(EMSESP_DEBUG)
|
||||
size_t length = response->setLength();
|
||||
EMSESP::logger().debug("Dashboard buffer used: %d", length);
|
||||
@@ -251,7 +245,9 @@ void WebDataService::write_value(AsyncWebServerRequest * request, JsonVariant &
|
||||
if (return_code != CommandRet::OK) {
|
||||
EMSESP::logger().err("Write command failed %s (%s)", (const char *)output["message"], Command::return_code_string(return_code).c_str());
|
||||
} else {
|
||||
#if defined(EMSESP_DEBUG)
|
||||
EMSESP::logger().debug("Write command successful");
|
||||
#endif
|
||||
}
|
||||
|
||||
response->setCode((return_code == CommandRet::OK) ? 200 : 204);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* EMS-ESP - https://github.com/emsesp/EMS-ESP
|
||||
* Copyright 2020 Paul Derbyshire
|
||||
* Copyright 2020-2023 Paul Derbyshire
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* EMS-ESP - https://github.com/emsesp/EMS-ESP
|
||||
* Copyright 2020 Paul Derbyshire
|
||||
* Copyright 2020-2023 Paul Derbyshire
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -136,7 +136,7 @@ void WebLogService::operator<<(std::shared_ptr<uuid::log::Message> message) {
|
||||
log_messages_.pop_front();
|
||||
}
|
||||
|
||||
log_messages_.emplace_back(log_message_id_++, std::move(message));
|
||||
log_messages_.emplace_back(++log_message_id_, std::move(message));
|
||||
|
||||
EMSESP::esp8266React.getNTPSettingsService()->read([&](NTPSettings & settings) {
|
||||
if (!settings.enabled || (time(nullptr) < 1500000000L)) {
|
||||
@@ -191,9 +191,9 @@ char * WebLogService::messagetime(char * out, const uint64_t t, const size_t buf
|
||||
|
||||
// send to web eventsource
|
||||
void WebLogService::transmit(const QueuedLogMessage & message) {
|
||||
auto jsonDocument = DynamicJsonDocument(EMSESP_JSON_SIZE_MEDIUM);
|
||||
JsonObject logEvent = jsonDocument.to<JsonObject>();
|
||||
char time_string[25];
|
||||
StaticJsonDocument<EMSESP_JSON_SIZE_MEDIUM> jsonDocument;
|
||||
JsonObject logEvent = jsonDocument.to<JsonObject>();
|
||||
char time_string[25];
|
||||
|
||||
logEvent["t"] = messagetime(time_string, message.content_->uptime_ms, sizeof(time_string));
|
||||
logEvent["l"] = message.content_->level;
|
||||
@@ -212,32 +212,8 @@ void WebLogService::transmit(const QueuedLogMessage & message) {
|
||||
|
||||
// send the complete log buffer to the API, not filtering on log level
|
||||
void WebLogService::fetchLog(AsyncWebServerRequest * request) {
|
||||
// auto * response = new MsgpackAsyncJsonResponse(false, EMSESP_JSON_SIZE_LARGE_DYN + 192 * log_messages_.size());
|
||||
size_t buffer = EMSESP_JSON_SIZE_XLARGE_DYN + 192 * log_messages_.size();
|
||||
auto * response = new MsgpackAsyncJsonResponse(false, buffer);
|
||||
while (!response->getSize()) {
|
||||
delete response;
|
||||
buffer -= 1024;
|
||||
response = new MsgpackAsyncJsonResponse(false, buffer);
|
||||
}
|
||||
JsonObject root = response->getRoot();
|
||||
JsonArray log = root.createNestedArray("events");
|
||||
|
||||
log_message_id_tail_ = log_messages_.back().id_;
|
||||
last_transmit_ = uuid::get_uptime_ms();
|
||||
for (const auto & message : log_messages_) {
|
||||
JsonObject logEvent = log.createNestedObject();
|
||||
char time_string[25];
|
||||
|
||||
logEvent["t"] = messagetime(time_string, message.content_->uptime_ms, sizeof(time_string));
|
||||
logEvent["l"] = message.content_->level;
|
||||
logEvent["i"] = message.id_;
|
||||
logEvent["n"] = message.content_->name;
|
||||
logEvent["m"] = message.content_->text;
|
||||
}
|
||||
log_message_id_tail_ = log_messages_.back().id_;
|
||||
response->setLength();
|
||||
request->send(response);
|
||||
log_message_id_tail_ = 0;
|
||||
request->send(200);
|
||||
}
|
||||
|
||||
// sets the values like level after a POST
|
||||
@@ -271,4 +247,4 @@ void WebLogService::getValues(AsyncWebServerRequest * request) {
|
||||
request->send(response);
|
||||
}
|
||||
|
||||
} // namespace emsesp
|
||||
} // namespace emsesp
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* EMS-ESP - https://github.com/emsesp/EMS-ESP
|
||||
* Copyright 2020 Paul Derbyshire
|
||||
* Copyright 2020-2023 Paul Derbyshire
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
191
src/web/WebSchedulerService.cpp
Normal file
191
src/web/WebSchedulerService.cpp
Normal file
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* EMS-ESP - https://github.com/emsesp/EMS-ESP
|
||||
* Copyright 2020-2023 Paul Derbyshire
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "emsesp.h"
|
||||
|
||||
namespace emsesp {
|
||||
|
||||
using namespace std::placeholders; // for `_1` etc
|
||||
|
||||
WebSchedulerService::WebSchedulerService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
|
||||
: _httpEndpoint(WebScheduler::read, WebScheduler::update, this, server, EMSESP_SCHEDULER_SERVICE_PATH, securityManager, AuthenticationPredicates::IS_AUTHENTICATED)
|
||||
, _fsPersistence(WebScheduler::read, WebScheduler::update, this, fs, EMSESP_SCHEDULER_FILE) {
|
||||
}
|
||||
|
||||
// load the settings when the service starts
|
||||
void WebSchedulerService::begin() {
|
||||
_fsPersistence.readFromFS();
|
||||
EMSESP::logger().info("Starting Scheduler service");
|
||||
}
|
||||
|
||||
// this creates the scheduler file, saving it to the FS
|
||||
void WebScheduler::read(WebScheduler & webScheduler, JsonObject & root) {
|
||||
JsonArray schedule = root.createNestedArray("schedule");
|
||||
uint8_t count = 0;
|
||||
char s[3];
|
||||
for (const ScheduleItem & scheduleItem : webScheduler.scheduleItems) {
|
||||
JsonObject si = schedule.createNestedObject();
|
||||
si["id"] = Helpers::smallitoa(s, count++); // create unique ID as a string
|
||||
si["active"] = scheduleItem.active;
|
||||
si["flags"] = scheduleItem.flags;
|
||||
si["time"] = scheduleItem.time;
|
||||
si["cmd"] = scheduleItem.cmd;
|
||||
si["value"] = scheduleItem.value;
|
||||
si["description"] = scheduleItem.description;
|
||||
}
|
||||
}
|
||||
|
||||
// call on initialization and also when the page is saved via web UI
|
||||
// this loads the data into the internal class
|
||||
StateUpdateResult WebScheduler::update(JsonObject & root, WebScheduler & webScheduler) {
|
||||
#ifdef EMSESP_STANDALONE
|
||||
// invoke some fake data for testing
|
||||
const char * json =
|
||||
"{[{\"active\":true,\"flags\":31,\"time\": \"07:30\",\"cmd\": \"hc1/mode\",\"value\": \"day\",\"description\": \"turn on central heating\"}]}";
|
||||
StaticJsonDocument<500> doc;
|
||||
deserializeJson(doc, json);
|
||||
root = doc.as<JsonObject>();
|
||||
Serial.println(COLOR_BRIGHT_MAGENTA);
|
||||
Serial.print("Using custom file: ");
|
||||
serializeJson(root, Serial);
|
||||
Serial.println(COLOR_RESET);
|
||||
#endif
|
||||
|
||||
webScheduler.scheduleItems.clear();
|
||||
|
||||
if (root["schedule"].is<JsonArray>()) {
|
||||
for (const JsonObject schedule : root["schedule"].as<JsonArray>()) {
|
||||
// create each schedule item, overwriting any previous settings
|
||||
// ignore the id (as this is only used in the web for table rendering)
|
||||
auto si = ScheduleItem();
|
||||
si.id = schedule["id"].as<std::string>();
|
||||
si.active = schedule["active"];
|
||||
si.flags = schedule["flags"];
|
||||
si.time = schedule["time"].as<std::string>();
|
||||
si.cmd = schedule["cmd"].as<std::string>();
|
||||
si.value = schedule["value"].as<std::string>();
|
||||
si.description = schedule["description"].as<std::string>();
|
||||
|
||||
// calculated elapsed minutes
|
||||
si.elapsed_min = Helpers::string2minutes(si.time);
|
||||
si.retry_cnt = 0xFF; // no starup retries
|
||||
|
||||
webScheduler.scheduleItems.push_back(si); // add to list
|
||||
}
|
||||
}
|
||||
return StateUpdateResult::CHANGED;
|
||||
}
|
||||
|
||||
// execute scheduled command
|
||||
bool WebSchedulerService::command(const char * cmd, const char * data) {
|
||||
StaticJsonDocument<EMSESP_JSON_SIZE_SMALL> doc_input;
|
||||
JsonObject input = doc_input.to<JsonObject>();
|
||||
if (strlen(data)) { // empty data queries a value
|
||||
input["data"] = data;
|
||||
}
|
||||
|
||||
StaticJsonDocument<EMSESP_JSON_SIZE_SMALL> doc_output; // only for commands without output
|
||||
JsonObject output = doc_output.to<JsonObject>();
|
||||
|
||||
// prefix "api/" to command string
|
||||
char command_str[100];
|
||||
snprintf(command_str, sizeof(command_str), "/api/%s", cmd);
|
||||
uint8_t return_code = Command::process(command_str, true, input, output); // admin set
|
||||
|
||||
if (return_code == CommandRet::OK) {
|
||||
EMSESP::logger().debug("Scheduled command %s with data %s successfully", cmd, data);
|
||||
if (strlen(data) == 0 && Mqtt::enabled() && Mqtt::send_response() && output.size()) {
|
||||
Mqtt::queue_publish("response", output);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
char error[100];
|
||||
if (output.size()) {
|
||||
snprintf(error,
|
||||
sizeof(error),
|
||||
"Scheduled command %s failed with error: %s (%s)",
|
||||
cmd,
|
||||
(const char *)output["message"],
|
||||
Command::return_code_string(return_code).c_str());
|
||||
} else {
|
||||
snprintf(error, sizeof(error), "Scheduled command %s failed with error code (%s)", cmd, Command::return_code_string(return_code).c_str());
|
||||
}
|
||||
emsesp::EMSESP::logger().err(error);
|
||||
return false;
|
||||
}
|
||||
|
||||
// process any scheduled jobs
|
||||
// checks on the minute
|
||||
void WebSchedulerService::loop() {
|
||||
// initialize static value on startup
|
||||
static int8_t last_tm_min = -1; // invalid value also used for startup commands
|
||||
static uint32_t last_uptime_min = 0;
|
||||
|
||||
// get list of scheduler events and exit if it's empty
|
||||
EMSESP::webSchedulerService.read([&](WebScheduler & webScheduler) { scheduleItems = &webScheduler.scheduleItems; });
|
||||
if (scheduleItems->size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// check startup commands
|
||||
if (last_tm_min == -1) {
|
||||
for (ScheduleItem & scheduleItem : *scheduleItems) {
|
||||
if (scheduleItem.active && scheduleItem.flags == SCHEDULEFLAG_SCHEDULE_TIMER && scheduleItem.elapsed_min == 0) {
|
||||
scheduleItem.retry_cnt = command(scheduleItem.cmd.c_str(), scheduleItem.value.c_str()) ? 0xFF : 0;
|
||||
}
|
||||
}
|
||||
last_tm_min = 0; // startup done, now use for RTC
|
||||
}
|
||||
|
||||
// check timer every minute, sync to EMS-ESP clock
|
||||
uint32_t uptime_min = uuid::get_uptime_sec() / 60;
|
||||
if (last_uptime_min != uptime_min) {
|
||||
for (ScheduleItem & scheduleItem : *scheduleItems) {
|
||||
// retry startup commands not yet executed
|
||||
if (scheduleItem.active && scheduleItem.flags == SCHEDULEFLAG_SCHEDULE_TIMER && scheduleItem.elapsed_min == 0
|
||||
&& scheduleItem.retry_cnt < MAX_STARTUP_RETRIES) {
|
||||
scheduleItem.retry_cnt = command(scheduleItem.cmd.c_str(), scheduleItem.value.c_str()) ? 0xFF : scheduleItem.retry_cnt + 1;
|
||||
}
|
||||
// scheduled timer commands
|
||||
if (scheduleItem.active && scheduleItem.flags == SCHEDULEFLAG_SCHEDULE_TIMER && scheduleItem.elapsed_min > 0
|
||||
&& (uptime_min % scheduleItem.elapsed_min == 0)) {
|
||||
command(scheduleItem.cmd.c_str(), scheduleItem.value.c_str());
|
||||
}
|
||||
}
|
||||
last_uptime_min = uptime_min;
|
||||
}
|
||||
|
||||
// check calender, sync to RTC, only execute if year is valid
|
||||
time_t now = time(nullptr);
|
||||
tm * tm = localtime(&now);
|
||||
if (tm->tm_min != last_tm_min && tm->tm_year > 120) {
|
||||
// find the real dow and minute from RTC
|
||||
uint8_t real_dow = 1 << tm->tm_wday; // 1 is Sunday
|
||||
uint16_t real_min = tm->tm_hour * 60 + tm->tm_min;
|
||||
|
||||
for (const ScheduleItem & scheduleItem : *scheduleItems) {
|
||||
if (scheduleItem.active && (real_dow & scheduleItem.flags) && real_min == scheduleItem.elapsed_min) {
|
||||
command(scheduleItem.cmd.c_str(), scheduleItem.value.c_str());
|
||||
}
|
||||
}
|
||||
last_tm_min = tm->tm_min;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace emsesp
|
||||
74
src/web/WebSchedulerService.h
Normal file
74
src/web/WebSchedulerService.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* EMS-ESP - https://github.com/emsesp/EMS-ESP
|
||||
* Copyright 2020-2023 Paul Derbyshire
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef WebSchedulerService_h
|
||||
#define WebSchedulerService_h
|
||||
|
||||
#define EMSESP_SCHEDULER_FILE "/config/emsespScheduler.json"
|
||||
#define EMSESP_SCHEDULER_SERVICE_PATH "/rest/schedule" // GET and POST
|
||||
|
||||
#define SCHEDULEFLAG_SCHEDULE_TIMER 0x80 // 7th bit for Timer
|
||||
#define MAX_STARTUP_RETRIES 3 // retry the statup commands x times
|
||||
|
||||
namespace emsesp {
|
||||
|
||||
class ScheduleItem {
|
||||
public:
|
||||
std::string id; // unqiue id
|
||||
boolean active;
|
||||
uint8_t flags;
|
||||
uint16_t elapsed_min; // total mins from 00:00
|
||||
std::string time; // HH:MM
|
||||
std::string cmd;
|
||||
std::string value;
|
||||
std::string description;
|
||||
uint8_t retry_cnt;
|
||||
};
|
||||
|
||||
class WebScheduler {
|
||||
public:
|
||||
std::list<ScheduleItem> scheduleItems;
|
||||
|
||||
static void read(WebScheduler & webScheduler, JsonObject & root);
|
||||
static StateUpdateResult update(JsonObject & root, WebScheduler & webScheduler);
|
||||
};
|
||||
|
||||
class WebSchedulerService : public StatefulService<WebScheduler> {
|
||||
public:
|
||||
WebSchedulerService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager);
|
||||
|
||||
void begin();
|
||||
void loop();
|
||||
|
||||
private:
|
||||
bool command(const char * cmd, const char * data);
|
||||
|
||||
// make all functions public so we can test in the debug and standalone mode
|
||||
#ifndef EMSESP_STANDALONE
|
||||
private:
|
||||
#endif
|
||||
|
||||
HttpEndpoint<WebScheduler> _httpEndpoint;
|
||||
FSPersistence<WebScheduler> _fsPersistence;
|
||||
|
||||
std::list<ScheduleItem> * scheduleItems; // pointer to the list of schedule events
|
||||
};
|
||||
|
||||
} // namespace emsesp
|
||||
|
||||
#endif
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* EMS-ESP - https://github.com/emsesp/EMS-ESP
|
||||
* Copyright 2020 Paul Derbyshire
|
||||
* Copyright 2020-2023 Paul Derbyshire
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -240,14 +240,22 @@ StateUpdateResult WebSettings::update(JsonObject & root, WebSettings & settings)
|
||||
settings.low_clock = root["low_clock"] | false;
|
||||
check_flag(prev, settings.low_clock, ChangeFlags::RESTART);
|
||||
|
||||
String old_local = settings.locale;
|
||||
settings.locale = root["locale"] | EMSESP_DEFAULT_LOCALE;
|
||||
EMSESP::system_.locale(settings.locale);
|
||||
#ifndef EMSESP_STANDALONE
|
||||
if (!old_local.equals(settings.locale)) {
|
||||
add_flags(ChangeFlags::RESTART); // force restart
|
||||
//
|
||||
// these may need mqtt restart to rebuild HA discovery topics
|
||||
//
|
||||
prev = settings.bool_format;
|
||||
settings.bool_format = root["bool_format"] | EMSESP_DEFAULT_BOOL_FORMAT;
|
||||
EMSESP::system_.bool_format(settings.bool_format);
|
||||
if (Mqtt::ha_enabled()) {
|
||||
check_flag(prev, settings.bool_format, ChangeFlags::MQTT);
|
||||
}
|
||||
|
||||
prev = settings.enum_format;
|
||||
settings.enum_format = root["enum_format"] | EMSESP_DEFAULT_ENUM_FORMAT;
|
||||
EMSESP::system_.enum_format(settings.enum_format);
|
||||
if (Mqtt::ha_enabled()) {
|
||||
check_flag(prev, settings.enum_format, ChangeFlags::MQTT);
|
||||
}
|
||||
#endif
|
||||
|
||||
//
|
||||
// these may need mqtt restart to rebuild HA discovery topics
|
||||
@@ -267,6 +275,9 @@ StateUpdateResult WebSettings::update(JsonObject & root, WebSettings & settings)
|
||||
//
|
||||
// without checks or necessary restarts...
|
||||
//
|
||||
settings.locale = root["locale"] | EMSESP_DEFAULT_LOCALE;
|
||||
EMSESP::system_.locale(settings.locale);
|
||||
|
||||
settings.trace_raw = root["trace_raw"] | EMSESP_DEFAULT_TRACELOG_RAW;
|
||||
EMSESP::trace_raw(settings.trace_raw);
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* EMS-ESP - https://github.com/emsesp/EMS-ESP
|
||||
* Copyright 2020 Paul Derbyshire
|
||||
* Copyright 2020-2023 Paul Derbyshire
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* EMS-ESP - https://github.com/emsesp/EMS-ESP
|
||||
* Copyright 2020 Paul Derbyshire
|
||||
* Copyright 2020-2023 Paul Derbyshire
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -32,6 +32,8 @@ WebStatusService::WebStatusService(AsyncWebServer * server, SecurityManager * se
|
||||
|
||||
// handles both WiFI and Ethernet
|
||||
void WebStatusService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) {
|
||||
#ifndef EMSESP_STANDALONE
|
||||
|
||||
switch (event) {
|
||||
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
|
||||
EMSESP::logger().warning("WiFi disconnected. Reason code=%s", disconnectReason(info.wifi_sta_disconnected.reason)); // IDF 4.0
|
||||
@@ -39,10 +41,8 @@ void WebStatusService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) {
|
||||
break;
|
||||
|
||||
case ARDUINO_EVENT_WIFI_STA_GOT_IP:
|
||||
#ifndef EMSESP_STANDALONE
|
||||
EMSESP::logger().info("WiFi connected with IP=%s, hostname=%s", WiFi.localIP().toString().c_str(), WiFi.getHostname());
|
||||
#endif
|
||||
EMSESP::system_.syslog_init();
|
||||
// EMSESP::system_.syslog_init();
|
||||
mDNS_start();
|
||||
EMSESP::system_.send_info_mqtt("connected");
|
||||
break;
|
||||
@@ -63,11 +63,9 @@ void WebStatusService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) {
|
||||
case ARDUINO_EVENT_ETH_GOT_IP:
|
||||
// prevent double calls
|
||||
if (!EMSESP::system_.ethernet_connected()) {
|
||||
#ifndef EMSESP_STANDALONE
|
||||
EMSESP::logger().info("Ethernet connected with IP=%s, speed %d Mbps", ETH.localIP().toString().c_str(), ETH.linkSpeed());
|
||||
#endif
|
||||
// EMSESP::system_.send_heartbeat();
|
||||
EMSESP::system_.syslog_init();
|
||||
// EMSESP::system_.syslog_init();
|
||||
EMSESP::system_.ethernet_connected(true);
|
||||
mDNS_start();
|
||||
EMSESP::system_.send_info_mqtt("connected");
|
||||
@@ -84,7 +82,6 @@ void WebStatusService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) {
|
||||
EMSESP::system_.ethernet_connected(false);
|
||||
break;
|
||||
|
||||
#ifndef EMSESP_STANDALONE
|
||||
case ARDUINO_EVENT_WIFI_STA_CONNECTED:
|
||||
EMSESP::esp8266React.getNetworkSettingsService()->read([&](NetworkSettings & networkSettings) {
|
||||
if (networkSettings.enableIPv6) {
|
||||
@@ -108,19 +105,19 @@ void WebStatusService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) {
|
||||
} else {
|
||||
EMSESP::logger().info("WiFi connected with IPv6=%s, hostname=%s", WiFi.localIPv6().toString().c_str(), WiFi.getHostname());
|
||||
}
|
||||
EMSESP::system_.syslog_init();
|
||||
// EMSESP::system_.syslog_init();
|
||||
mDNS_start();
|
||||
EMSESP::system_.send_info_mqtt("connected");
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void WebStatusService::webStatusService(AsyncWebServerRequest * request) {
|
||||
auto * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_MEDIUM_DYN);
|
||||
auto * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_LARGE);
|
||||
JsonObject root = response->getRoot();
|
||||
|
||||
root["status"] = EMSESP::bus_status(); // 0, 1 or 2
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* EMS-ESP - https://github.com/emsesp/EMS-ESP
|
||||
* Copyright 2020 Paul Derbyshire
|
||||
* Copyright 2020-2023 Paul Derbyshire
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
Reference in New Issue
Block a user