first commit using PsychicHttp

This commit is contained in:
Proddy
2023-12-25 13:27:02 +01:00
parent 68cb94547e
commit 73a51ae4ad
169 changed files with 7162 additions and 12208 deletions

View File

@@ -608,13 +608,13 @@ void EMSESPShell::stopped() {
// show welcome banner
void EMSESPShell::display_banner() {
println();
printfln("┌───────────────────────────────────────┐");
printfln("│ %sEMS-ESP version %-12s%s │", COLOR_BOLD_ON, EMSESP_APP_VERSION, COLOR_BOLD_OFF);
printfln("│ %s%shttps://github.com/emsesp/EMS-ESP32%s │", COLOR_BRIGHT_GREEN, COLOR_UNDERLINE, COLOR_RESET);
printfln("│ │");
printfln("│ type %shelp%s to show available commands │", COLOR_UNDERLINE, COLOR_RESET);
printfln("│ use %ssu%s to access Admin commands │", COLOR_UNDERLINE, COLOR_RESET);
printfln("└───────────────────────────────────────┘");
printfln("┌───────────────────────────────────────");
printfln("│ %sEMS-ESP version %-13s%s │", COLOR_BOLD_ON, EMSESP_APP_VERSION, COLOR_BOLD_OFF);
printfln("│ %s%shttps://github.com/emsesp/EMS-ESP32%s ", COLOR_BRIGHT_GREEN, COLOR_UNDERLINE, COLOR_RESET);
printfln(" ");
printfln("│ type %shelp%s to show available commands ", COLOR_UNDERLINE, COLOR_RESET);
printfln("│ use %ssu%s to access Admin commands ", COLOR_UNDERLINE, COLOR_RESET);
printfln("└───────────────────────────────────────");
println();
// set console name

View File

@@ -252,4 +252,16 @@ enum {
#error Target CONFIG_IDF_TARGET is not supported
#endif
#ifndef ARDUINO_VERSION
#ifndef STRINGIZE
#define STRINGIZE(s) #s
#endif
#if TASMOTA_SDK
#define ARDUINO_VERSION_STR(major, minor, patch) "Tasmota Arduino v" STRINGIZE(major) "." STRINGIZE(minor) "." STRINGIZE(patch)
#else
#define ARDUINO_VERSION_STR(major, minor, patch) "ESP32 Arduino v" STRINGIZE(major) "." STRINGIZE(minor) "." STRINGIZE(patch)
#endif
#define ARDUINO_VERSION ARDUINO_VERSION_STR(ESP_ARDUINO_VERSION_MAJOR, ESP_ARDUINO_VERSION_MINOR, ESP_ARDUINO_VERSION_PATCH)
#endif
#endif

View File

@@ -1,7 +1,7 @@
/*
* 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
@@ -20,7 +20,7 @@
/*
* These is the EMS devices that we currently recognize
* The types and flags are stored in emsdevice.h
* The types and flags are stored in emsdevice.h
*/
// Boilers - 0x08
@@ -107,6 +107,7 @@
{ 66, DeviceType::THERMOSTAT, "ES72/RC20", DeviceFlags::EMS_DEVICE_FLAG_RC20_N}, // 0x17 or remote
{ 76, DeviceType::THERMOSTAT, "ES73", DeviceFlags::EMS_DEVICE_FLAG_RC30_N}, // 0x10
{113, DeviceType::THERMOSTAT, "ES72/RC20", DeviceFlags::EMS_DEVICE_FLAG_RC20_N}, // 0x17
{159, DeviceType::THERMOSTAT, "ES79", DeviceFlags::EMS_DEVICE_FLAG_RC35}, // 0x10
// Thermostat - Junkers - 0x10
{105, DeviceType::THERMOSTAT, "FW100", DeviceFlags::EMS_DEVICE_FLAG_JUNKERS},
@@ -181,4 +182,4 @@
// Generic - 0x40 or other with no product-id and no version
{0, DeviceType::GENERIC, "unknown", DeviceFlags::EMS_DEVICE_FLAG_NONE}
// clang-format on
// clang-format on

View File

@@ -2420,7 +2420,7 @@ bool Boiler::set_ww_mode(const char * value, const int8_t id) {
if (is_received(EMS_TYPE_UBAParameterWWPlus)) {
if (Helpers::value2enum(value, set, FL_(enum_comfort1))) {
write_command(EMS_TYPE_UBAParameterWWPlus, 13, comfort[set], EMS_TYPE_UBAParameterWWPlus);
write_command(0x05, 70, set ? 0xAA : 0x55); //
write_command(0x05, 70, set == 0 ? 0xAA : 0x55); //
return true;
}
} else {

View File

@@ -22,9 +22,11 @@ static_assert(uuid::thread_safe, "uuid-common must be thread-safe");
static_assert(uuid::log::thread_safe, "uuid-log must be thread-safe");
static_assert(uuid::console::thread_safe, "uuid-console must be thread-safe");
#include <WWWData.h>
namespace emsesp {
AsyncWebServer webServer(80);
PsychicHttpServer webServer; // web server is static and global
#if defined(EMSESP_STANDALONE)
FS dummyFS;
@@ -61,7 +63,7 @@ uuid::log::Logger EMSESP::logger() {
uuid::syslog::SyslogService System::syslog_;
#endif
// The services
// Core EMS-ESP services
RxService EMSESP::rxservice_; // incoming Telegram Rx handler
TxService EMSESP::txservice_; // outgoing Telegram Tx handler
Mqtt EMSESP::mqtt_; // mqtt handler
@@ -69,7 +71,9 @@ System EMSESP::system_; // core system services
TemperatureSensor EMSESP::temperaturesensor_; // Temperature sensors
AnalogSensor EMSESP::analogsensor_; // Analog sensors
Shower EMSESP::shower_; // Shower logic
Preferences EMSESP::nvs_; // NV Storage
// NV Storage
Preferences EMSESP::nvs_;
// static/common variables
uint16_t EMSESP::watch_id_ = WATCH_ID_NONE; // for when log is TRACE. 0 means no trace set
@@ -1389,8 +1393,6 @@ void EMSESP::scheduled_fetch_values() {
}
}
// EMSESP main class
EMSESP::EMSESP()
#ifndef EMSESP_STANDALONE
: telnet_([this](Stream & stream, const IPAddress & addr, uint16_t port) -> std::shared_ptr<uuid::console::Shell> {
@@ -1400,6 +1402,73 @@ EMSESP::EMSESP()
{
}
// add web server endpoint
void EMSESP::handler(const char * uri, const char * contentType, const uint8_t * content, size_t len) {
// remap to root
if (strcmp(uri, "/index.html") == 0) {
uri = "/";
}
webServer.on(uri, HTTP_GET, [contentType, content, len](PsychicRequest * request) {
PsychicResponse response(request);
response.setCode(200);
response.setContentType(contentType);
response.addHeader("Content-Encoding", "gzip");
// response.addHeader("Content-Encoding", "br"); // Brotli - only works over HTTPS
response.setContent(content, len);
return response.send();
});
};
// configure web server
// this can be only be done after the network has been initialized
void EMSESP::setupWeb() {
// set maximum number of uri handlers (.on() calls). default was 8
// WWWData has 19 (in registerRoutes(handler)
// esp8266React services has 13
// custom projects has around 23
webServer.config.max_uri_handlers = 70;
// TODO add support for HTTPS
webServer.listen(80); // start the web server
DefaultHeaders::Instance().addHeader("Server", "EMS-ESP");
WWWData::registerRoutes(handler); // add webServer.on() endpoints from the generated web code
esp8266React.registerURI(); // load up the core system web endpoints
// init EMS-ESP web endpoints
webDataService.registerURI(); // /rest{deviceData,coreData,sensorData...}
webStatusService.registerURI(); // /rest/status
webSettingsService.registerURI(); // /rest/{settings,boardprofile}
webAPIService.registerURI(); // /api/*, /rest/{getSettings,getSchedule,getCustomizations,getEntities}
webLogService.registerURI(); // /rest/logSettings and EventSource
webCustomizationService.registerURI(); // /rest{customization,customizationEntities,resetCustomizations,devices,deviceEntities}
webSchedulerService.registerURI(); // /rest/schedule
webCustomEntityService.registerURI(); // /rest/customentities
webServer.onNotFound([](PsychicRequest * request) {
if (request->method() == HTTP_GET) {
Serial.printf("redirecting not found %s\n", request->uri().c_str()); // TODO remove debug
String url = "http://" + request->host(); // TODO add support for https
return request->redirect(url.c_str());
} else if (request->method() == HTTP_OPTIONS) {
return request->reply(200);
} else {
return request->reply(404);
}
});
// Add CORS if specified in the network settings
esp8266React.getNetworkSettingsService()->read([&](NetworkSettings & networkSettings) {
if (networkSettings.enableCORS) {
DefaultHeaders::Instance().addHeader("Access-Control-Allow-Origin", networkSettings.CORSOrigin);
DefaultHeaders::Instance().addHeader("Access-Control-Allow-Headers", "Accept, Content-Type, Authorization");
DefaultHeaders::Instance().addHeader("Access-Control-Allow-Credentials", "true");
}
});
}
// start all the core services
// the services must be loaded in the correct order
void EMSESP::start() {
@@ -1441,8 +1510,13 @@ void EMSESP::start() {
bool factory_settings = false;
#endif
esp8266React.begin(); // loads core system services settings (network, mqtt, ap, ntp etc)
esp8266React.begin(); // loads core system services settings (network, mqtt, ap, ntp etc)
setupWeb(); // configure web server, now that the network has been initialized
webLogService.begin(); // start web log service. now we can start capturing logs to the web log
// start Prefences, the internal persistance storage
nvs_.begin("ems-esp", false, "nvs");
LOG_INFO("Starting EMS-ESP version %s", EMSESP_APP_VERSION); // welcome message
@@ -1496,11 +1570,11 @@ void EMSESP::start() {
#if defined(EMSESP_STANDALONE)
Mqtt::on_connect(); // simulate an MQTT connection
#endif
webServer.begin(); // start the web server
}
// main loop calling all services
void EMSESP::loop() {
esp8266React.loop(); // web services
system_.loop(); // does LED and checks system health, and syslog service
@@ -1527,6 +1601,7 @@ void EMSESP::loop() {
if (system_.telnet_enabled()) {
telnet_.loop();
}
#else
if (!shell_->running()) {
::exit(0);

View File

@@ -1,7 +1,7 @@
/*
* 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
@@ -228,8 +228,10 @@ class EMSESP {
static TxService txservice_;
static Preferences nvs_;
// web controllers
static ESP8266React esp8266React;
// esp8266React framework
static ESP8266React esp8266React;
// EMS-ESP web controllers
static WebSettingsService webSettingsService;
static WebStatusService webStatusService;
static WebDataService webDataService;
@@ -239,6 +241,8 @@ class EMSESP {
static WebSchedulerService webSchedulerService;
static WebCustomEntityService webCustomEntityService;
static void handler(const char * uri, const char * contentType, const uint8_t * content, size_t len);
private:
static std::string device_tostring(const uint8_t device_id);
static void process_UBADevices(std::shared_ptr<const Telegram> telegram);
@@ -282,8 +286,9 @@ class EMSESP {
uuid::telnet::TelnetService telnet_;
#endif
void setupWeb();
protected:
// EMSESP();
static uuid::log::Logger logger_;
};

File diff suppressed because it is too large Load Diff

View File

@@ -64,7 +64,8 @@ const char * const languages[] = {EMSESP_LOCALE_EN,
EMSESP_LOCALE_NO,
EMSESP_LOCALE_FR,
EMSESP_LOCALE_TR,
EMSESP_LOCALE_IT};
EMSESP_LOCALE_IT,
EMSESP_LOCALE_SK};
#endif
static constexpr uint8_t NUM_LANGUAGES = sizeof(languages) / sizeof(const char *);
@@ -253,7 +254,9 @@ bool System::command_watch(const char * value, const int8_t id) {
}
void System::store_nvs_values() {
Command::call(EMSdevice::DeviceType::BOILER, "nompower", "-1"); // trigger a write
if (Command::find_command(EMSdevice::DeviceType::BOILER, 0, "nompower") != nullptr) {
Command::call(EMSdevice::DeviceType::BOILER, "nompower", "-1"); // trigger a write
}
EMSESP::analogsensor_.store_counters();
EMSESP::nvs_.end();
}
@@ -729,7 +732,11 @@ void System::network_init(bool refresh) {
// ETH_CLOCK_GPIO17_OUT = 3 RMII clock output from GPIO17, for 50hz inverted clock
auto clock_mode = (eth_clock_mode_t)eth_clock_mode_;
eth_present_ = ETH.begin((eth_phy_type_t)phy_addr, power, mdc, mdio, type, clock_mode);
#if ESP_ARDUINO_VERSION_MAJOR < 3
eth_present_ = ETH.begin(phy_addr, power, mdc, mdio, type, clock_mode);
#else
eth_present_ = ETH.begin(type, phy_addr, mdc, mdio, power, clock_mode);
#endif
#endif
}
@@ -1039,42 +1046,44 @@ bool System::check_restore() {
#ifndef EMSESP_STANDALONE
// see if we have a temp file, if so try and read it
File new_file = LittleFS.open(TEMP_FILENAME_PATH);
if (new_file) {
DynamicJsonDocument jsonDocument = DynamicJsonDocument(FS_BUFFER_SIZE);
DeserializationError error = deserializeJson(jsonDocument, new_file);
if (error == DeserializationError::Ok && jsonDocument.is<JsonObject>()) {
JsonObject input = jsonDocument.as<JsonObject>();
// see what type of file it is, either settings or customization. anything else is ignored
std::string settings_type = input["type"];
if (settings_type == "settings") {
// It's a settings file. Parse each section separately. If it's system related it will require a reboot
reboot_required = saveSettings(NETWORK_SETTINGS_FILE, "Network", input);
reboot_required |= saveSettings(AP_SETTINGS_FILE, "AP", input);
reboot_required |= saveSettings(MQTT_SETTINGS_FILE, "MQTT", input);
reboot_required |= saveSettings(NTP_SETTINGS_FILE, "NTP", input);
reboot_required |= saveSettings(SECURITY_SETTINGS_FILE, "Security", input);
reboot_required |= saveSettings(EMSESP_SETTINGS_FILE, "Settings", input);
reboot_required |= saveSettings(OTA_SETTINGS_FILE, "OTA", input);
} else if (settings_type == "customizations") {
// it's a customization file, just replace it and there's no need to reboot
saveSettings(EMSESP_CUSTOMIZATION_FILE, "Customizations", input);
} else if (settings_type == "schedule") {
// it's a schedule file, just replace it and there's no need to reboot
saveSettings(EMSESP_SCHEDULER_FILE, "Schedule", input);
} else if (settings_type == "entities") {
// it's a entity file, just replace it and there's no need to reboot
saveSettings(EMSESP_CUSTOMENTITY_FILE, "Entities", input);
if (LittleFS.exists(TEMP_FILENAME_PATH)) { // prevents open(): /littlefs/tmp_upload does not exist, no permits for creation
File new_file = LittleFS.open(TEMP_FILENAME_PATH);
if (new_file) {
DynamicJsonDocument jsonDocument = DynamicJsonDocument(FS_BUFFER_SIZE);
DeserializationError error = deserializeJson(jsonDocument, new_file);
if (error == DeserializationError::Ok && jsonDocument.is<JsonObject>()) {
JsonObject input = jsonDocument.as<JsonObject>();
// see what type of file it is, either settings or customization. anything else is ignored
std::string settings_type = input["type"];
if (settings_type == "settings") {
// It's a settings file. Parse each section separately. If it's system related it will require a reboot
reboot_required = saveSettings(NETWORK_SETTINGS_FILE, "Network", input);
reboot_required |= saveSettings(AP_SETTINGS_FILE, "AP", input);
reboot_required |= saveSettings(MQTT_SETTINGS_FILE, "MQTT", input);
reboot_required |= saveSettings(NTP_SETTINGS_FILE, "NTP", input);
reboot_required |= saveSettings(SECURITY_SETTINGS_FILE, "Security", input);
reboot_required |= saveSettings(EMSESP_SETTINGS_FILE, "Settings", input);
reboot_required |= saveSettings(OTA_SETTINGS_FILE, "OTA", input);
} else if (settings_type == "customizations") {
// it's a customization file, just replace it and there's no need to reboot
saveSettings(EMSESP_CUSTOMIZATION_FILE, "Customizations", input);
} else if (settings_type == "schedule") {
// it's a schedule file, just replace it and there's no need to reboot
saveSettings(EMSESP_SCHEDULER_FILE, "Schedule", input);
} else if (settings_type == "entities") {
// it's a entity file, just replace it and there's no need to reboot
saveSettings(EMSESP_CUSTOMENTITY_FILE, "Entities", input);
} else {
LOG_ERROR("Unrecognized file uploaded");
}
} else {
LOG_ERROR("Unrecognized file uploaded");
LOG_ERROR("Unrecognized file uploaded, not json");
}
} else {
LOG_ERROR("Unrecognized file uploaded, not json");
}
// close (just in case) and remove the temp file
new_file.close();
LittleFS.remove(TEMP_FILENAME_PATH);
// close (just in case) and remove the temp file
new_file.close();
LittleFS.remove(TEMP_FILENAME_PATH);
}
}
#endif
@@ -1201,13 +1210,16 @@ bool System::command_info(const char * value, const int8_t id, JsonObject & outp
// System
node = output.createNestedObject("System Info");
node["version"] = EMSESP_APP_VERSION;
node["platform"] = EMSESP_PLATFORM;
node["uptime"] = uuid::log::format_timestamp_ms(uuid::get_uptime_ms(), 3);
node["uptime (seconds)"] = uuid::get_uptime_sec();
#ifndef EMSESP_STANDALONE
node["platform"] = ARDUINO_VERSION;
node["sdk"] = ESP.getSdkVersion();
node["free mem"] = getHeapMem();
node["max alloc"] = getMaxAllocMem();
node["used app"] = EMSESP::system_.appUsed(); // kilobytes
node["free app"] = EMSESP::system_.appFree(); // kilobytes
node["partition"] = esp_ota_get_running_partition()->label;
#endif
node["reset reason"] = EMSESP::system_.reset_reason(0) + " / " + EMSESP::system_.reset_reason(1);
@@ -1581,4 +1593,4 @@ bool System::ntp_connected() {
return ntp_connected_;
}
} // namespace emsesp
} // namespace emsesp

View File

@@ -306,7 +306,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
run_test("general");
#ifdef EMSESP_STANDALONE
AsyncWebServerRequest request;
PsychicRequest request;
request.method(HTTP_GET);
request.url("/api/custom");
request.url("/api/custom/boiler_flowtemp");
@@ -321,7 +321,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
run_test("general");
#ifdef EMSESP_STANDALONE
AsyncWebServerRequest request;
PsychicRequest request;
request.method(HTTP_GET);
request.url("/api/boiler/coldshot");
EMSESP::webAPIService.webAPIService_get(&request);
@@ -846,7 +846,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
run_test("boiler");
run_test("thermostat");
AsyncWebServerRequest request;
PsychicRequest request;
DynamicJsonDocument doc(2000);
JsonVariant json;
request.method(HTTP_GET);
@@ -890,7 +890,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
Mqtt::nested_format(1);
run_test("310");
AsyncWebServerRequest request;
PsychicRequest request;
request.method(HTTP_POST);
DynamicJsonDocument doc(2000);
JsonVariant json;
@@ -915,7 +915,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
run_test("boiler");
run_test("thermostat");
AsyncWebServerRequest requestX;
PsychicRequest requestX;
DynamicJsonDocument docX(2000);
JsonVariant jsonX;
@@ -1084,7 +1084,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
EMSESP::mqtt_.incoming("home/cellar/heating/thermostat/mode"); // empty payload
// Web API TESTS
AsyncWebServerRequest request;
PsychicRequest request;
request.method(HTTP_GET);
@@ -1714,7 +1714,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
// shell.invoke_command("call mixer wwc2 info");
// test API
AsyncWebServerRequest request;
PsychicRequest request;
request.url("/api/mixer");
EMSESP::webAPIService.webAPIService_get(&request);
request.url("/api/mixer/hc1/pumpstatus");

View File

@@ -22,7 +22,7 @@
#define EMSESP_TEST_H
#include "emsesp.h"
#include <ESPAsyncWebServer.h>
#include <PsychicHttp.h>
namespace emsesp {

View File

@@ -1 +1 @@
#define EMSESP_APP_VERSION "3.6.5-dev.4"
#define EMSESP_APP_VERSION "3.6.5-https.0"

View File

@@ -1,7 +1,7 @@
/*
* 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
@@ -25,49 +25,46 @@ namespace emsesp {
uint32_t WebAPIService::api_count_ = 0;
uint16_t WebAPIService::api_fails_ = 0;
WebAPIService::WebAPIService(AsyncWebServer * server, SecurityManager * securityManager)
: _securityManager(securityManager)
, _apiHandler("/api", std::bind(&WebAPIService::webAPIService_post, this, _1, _2), 256) { // for POSTS, must use 'Content-Type: application/json' in header
server->on("/api", HTTP_GET, std::bind(&WebAPIService::webAPIService_get, this, _1)); // for GETS
server->addHandler(&_apiHandler);
WebAPIService::WebAPIService(PsychicHttpServer * server, SecurityManager * securityManager)
: _server(server)
, _securityManager(securityManager) {
}
void WebAPIService::registerURI() {
// POST /{device}[/{hc|id}][/{name}]
// note: must explicity use 'Content-Type: application/json' in header
_server->on(EMSESP_API_SERVICE_PATH, HTTP_POST, [this](PsychicRequest * request, JsonVariant & json) {
// if no body then treat it as a secure GET
if (!json.is<JsonObject>()) {
StaticJsonDocument<EMSESP_JSON_SIZE_SMALL> input_doc;
JsonObject input = input_doc.to<JsonObject>();
return parse(request, input);
}
// extract values from the json. these will be used as default values
auto && input = json.as<JsonObject>();
return parse(request, input);
});
// GET /{device}/{entity}
_server->on(EMSESP_API_SERVICE_PATH, HTTP_GET, [this](PsychicRequest * request) {
StaticJsonDocument<EMSESP_JSON_SIZE_SMALL> input_doc;
JsonObject input = input_doc.to<JsonObject>();
return parse(request, input);
});
// for settings
server->on(GET_SETTINGS_PATH, HTTP_GET, securityManager->wrapRequest(std::bind(&WebAPIService::getSettings, this, _1), AuthenticationPredicates::IS_ADMIN));
server->on(GET_CUSTOMIZATIONS_PATH,
HTTP_GET,
securityManager->wrapRequest(std::bind(&WebAPIService::getCustomizations, this, _1), AuthenticationPredicates::IS_ADMIN));
server->on(GET_SCHEDULE_PATH, HTTP_GET, securityManager->wrapRequest(std::bind(&WebAPIService::getSchedule, this, _1), AuthenticationPredicates::IS_ADMIN));
server->on(GET_ENTITIES_PATH, HTTP_GET, securityManager->wrapRequest(std::bind(&WebAPIService::getEntities, this, _1), AuthenticationPredicates::IS_ADMIN));
}
// HTTP GET
// GET /{device}
// GET /{device}/{entity}
void WebAPIService::webAPIService_get(AsyncWebServerRequest * request) {
// has no body JSON so create dummy as empty input object
StaticJsonDocument<EMSESP_JSON_SIZE_SMALL> input_doc;
JsonObject input = input_doc.to<JsonObject>();
parse(request, input);
}
// For HTTP POSTS with an optional JSON body
// HTTP_POST | HTTP_PUT | HTTP_PATCH
// POST /{device}[/{hc|id}][/{name}]
void WebAPIService::webAPIService_post(AsyncWebServerRequest * request, JsonVariant & json) {
// if no body then treat it as a secure GET
if (!json.is<JsonObject>()) {
webAPIService_get(request);
return;
}
// extract values from the json. these will be used as default values
auto && input = json.as<JsonObject>();
parse(request, input);
_server->on(GET_SETTINGS_PATH, HTTP_GET, _securityManager->wrapRequest(std::bind(&WebAPIService::getSettings, this, _1), AuthenticationPredicates::IS_ADMIN));
_server->on(GET_CUSTOMIZATIONS_PATH,
HTTP_GET,
_securityManager->wrapRequest(std::bind(&WebAPIService::getCustomizations, this, _1), AuthenticationPredicates::IS_ADMIN));
_server->on(GET_SCHEDULE_PATH, HTTP_GET, _securityManager->wrapRequest(std::bind(&WebAPIService::getSchedule, this, _1), AuthenticationPredicates::IS_ADMIN));
_server->on(GET_ENTITIES_PATH, HTTP_GET, _securityManager->wrapRequest(std::bind(&WebAPIService::getEntities, this, _1), AuthenticationPredicates::IS_ADMIN));
}
// parse the URL looking for query or path parameters
// reporting back any errors
void WebAPIService::parse(AsyncWebServerRequest * request, JsonObject & input) {
esp_err_t WebAPIService::parse(PsychicRequest * request, JsonObject & input) {
// check if the user has admin privileges (token is included and authorized)
bool is_admin = false;
EMSESP::webSettingsService.read([&](WebSettings & settings) {
@@ -77,6 +74,7 @@ void WebAPIService::parse(AsyncWebServerRequest * request, JsonObject & input) {
// check for query parameters first, the old style from v2
// api?device={device}&cmd={name}&data={value}&id={hc}
// TODO check if this works, because we're using wildcard now for api/*
if (request->url() == "/api") {
// get the device
if (request->hasParam(F_(device))) {
@@ -106,18 +104,24 @@ void WebAPIService::parse(AsyncWebServerRequest * request, JsonObject & input) {
emsesp::EMSESP::system_.refreshHeapMem();
// output json buffer
size_t buffer = EMSESP_JSON_SIZE_XXXLARGE;
auto * response = new PrettyAsyncJsonResponse(false, buffer);
while (!response->getSize()) {
delete response;
buffer -= 1024;
response = new PrettyAsyncJsonResponse(false, buffer);
}
JsonObject output = response->getRoot();
size_t buffer = EMSESP_JSON_SIZE_XXXLARGE;
PsychicJsonResponse response = PsychicJsonResponse(request, false, buffer);
// TODO add back memory managegement. Be careful we do need to free()/delete() any object we extend with new()
// while (!response->getSize()) {
// delete response;
// buffer -= 1024;
// response = new PrettyAsyncJsonResponse(false, buffer);
// response = PsychicJsonResponse(request, false, buffer);
// }
JsonObject output = response.getRoot();
// call command
uint8_t return_code = Command::process(request->url().c_str(), is_admin, input, output);
// handle failure
if (return_code != CommandRet::OK) {
char error[100];
if (output.size()) {
@@ -127,42 +131,29 @@ void WebAPIService::parse(AsyncWebServerRequest * request, JsonObject & input) {
}
emsesp::EMSESP::logger().err(error);
api_fails_++;
// FAIL, OK, NOT_FOUND, ERROR, NOT_ALLOWED = 400 (bad request), 200 (OK), 400 (not found), 400 (bad request), 401 (unauthorized)
int ret_codes[6] = {400, 200, 400, 400, 401, 400};
request->reply(ret_codes[return_code]); // exit with error code
}
// if we're returning single values, just sent as plain text
api_count_++; // another succesful api call
// if we're returning single values, just sent as plain text and not json
// https://github.com/emsesp/EMS-ESP32/issues/462#issuecomment-1093877210
if (output.containsKey("api_data")) {
JsonVariant data = output["api_data"];
request->send(200, "text/plain; charset=utf-8", data.as<String>());
api_count_++;
delete response;
return;
return request->reply(200, "text/plain; charset=utf-8", data.as<const char *>());
}
// send the json that came back from the command call
// FAIL, OK, NOT_FOUND, ERROR, NOT_ALLOWED = 400 (bad request), 200 (OK), 400 (not found), 400 (bad request), 401 (unauthorized)
int ret_codes[6] = {400, 200, 400, 400, 401, 400};
response->setCode(ret_codes[return_code]);
response->setLength();
response->setContentType("application/json; charset=utf-8");
request->send(response);
api_count_++;
#if defined(EMSESP_STANDALONE)
Serial.print(COLOR_YELLOW);
Serial.print("web response code: ");
Serial.println(ret_codes[return_code]);
if (output.size()) {
serializeJsonPretty(output, Serial);
}
Serial.println();
Serial.print(COLOR_RESET);
#endif
// normal return
// as setContentType("application/json; charset=utf-8")
return response.send();
}
void WebAPIService::getSettings(AsyncWebServerRequest * request) {
auto * response = new AsyncJsonResponse(false, FS_BUFFER_SIZE);
JsonObject root = response->getRoot();
esp_err_t WebAPIService::getSettings(PsychicRequest * request) {
PsychicJsonResponse response = PsychicJsonResponse(request, this, FS_BUFFER_SIZE);
JsonObject root = response.getRoot();
root["type"] = "settings";
@@ -177,44 +168,39 @@ void WebAPIService::getSettings(AsyncWebServerRequest * request) {
System::extractSettings(SECURITY_SETTINGS_FILE, "Security", root);
System::extractSettings(EMSESP_SETTINGS_FILE, "Settings", root);
response->setLength();
request->send(response);
return response.send();
}
void WebAPIService::getCustomizations(AsyncWebServerRequest * request) {
auto * response = new AsyncJsonResponse(false, FS_BUFFER_SIZE);
JsonObject root = response->getRoot();
esp_err_t WebAPIService::getCustomizations(PsychicRequest * request) {
PsychicJsonResponse response = PsychicJsonResponse(request, this, FS_BUFFER_SIZE);
JsonObject root = response.getRoot();
root["type"] = "customizations";
System::extractSettings(EMSESP_CUSTOMIZATION_FILE, "Customizations", root);
response->setLength();
request->send(response);
return response.send();
}
void WebAPIService::getSchedule(AsyncWebServerRequest * request) {
auto * response = new AsyncJsonResponse(false, FS_BUFFER_SIZE);
JsonObject root = response->getRoot();
esp_err_t WebAPIService::getSchedule(PsychicRequest * request) {
PsychicJsonResponse response = PsychicJsonResponse(request, this, FS_BUFFER_SIZE);
JsonObject root = response.getRoot();
root["type"] = "schedule";
System::extractSettings(EMSESP_SCHEDULER_FILE, "Schedule", root);
response->setLength();
request->send(response);
return response.send();
}
void WebAPIService::getEntities(AsyncWebServerRequest * request) {
auto * response = new AsyncJsonResponse(false, FS_BUFFER_SIZE);
JsonObject root = response->getRoot();
esp_err_t WebAPIService::getEntities(PsychicRequest * request) {
PsychicJsonResponse response = PsychicJsonResponse(request, this, FS_BUFFER_SIZE);
JsonObject root = response.getRoot();
root["type"] = "entities";
System::extractSettings(EMSESP_CUSTOMENTITY_FILE, "Entities", root);
response->setLength();
request->send(response);
return response.send();
}
} // namespace emsesp

View File

@@ -19,7 +19,7 @@
#ifndef WebAPIService_h
#define WebAPIService_h
#define EMSESP_API_SERVICE_PATH "/api"
#define EMSESP_API_SERVICE_PATH "/api/*"
#define GET_SETTINGS_PATH "/rest/getSettings"
#define GET_CUSTOMIZATIONS_PATH "/rest/getCustomizations"
#define GET_SCHEDULE_PATH "/rest/getSchedule"
@@ -29,10 +29,9 @@ namespace emsesp {
class WebAPIService {
public:
WebAPIService(AsyncWebServer * server, SecurityManager * securityManager);
WebAPIService(PsychicHttpServer * server, SecurityManager * securityManager);
void webAPIService_post(AsyncWebServerRequest * request, JsonVariant & json); // for POSTs
void webAPIService_get(AsyncWebServerRequest * request); // for GETs
void registerURI();
static uint32_t api_count() {
return api_count_;
@@ -43,18 +42,18 @@ class WebAPIService {
}
private:
SecurityManager * _securityManager;
AsyncCallbackJsonWebHandler _apiHandler; // for POSTs
SecurityManager * _securityManager;
PsychicHttpServer * _server;
static uint32_t api_count_;
static uint16_t api_fails_;
void parse(AsyncWebServerRequest * request, JsonObject & input);
esp_err_t parse(PsychicRequest * request, JsonObject & input);
void getSettings(AsyncWebServerRequest * request);
void getCustomizations(AsyncWebServerRequest * request);
void getSchedule(AsyncWebServerRequest * request);
void getEntities(AsyncWebServerRequest * request);
esp_err_t getSettings(PsychicRequest * request);
esp_err_t getCustomizations(PsychicRequest * request);
esp_err_t getSchedule(PsychicRequest * request);
esp_err_t getEntities(PsychicRequest * request);
};
} // namespace emsesp

View File

@@ -22,7 +22,7 @@ namespace emsesp {
using namespace std::placeholders; // for `_1` etc
WebCustomEntityService::WebCustomEntityService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
WebCustomEntityService::WebCustomEntityService(PsychicHttpServer * server, FS * fs, SecurityManager * securityManager)
: _httpEndpoint(WebCustomEntity::read,
WebCustomEntity::update,
this,
@@ -33,6 +33,10 @@ WebCustomEntityService::WebCustomEntityService(AsyncWebServer * server, FS * fs,
, _fsPersistence(WebCustomEntity::read, WebCustomEntity::update, this, fs, EMSESP_CUSTOMENTITY_FILE, FS_BUFFER_SIZE) {
}
void WebCustomEntityService::registerURI() {
_httpEndpoint.registerURI();
}
// load the settings when the service starts
void WebCustomEntityService::begin() {
_fsPersistence.readFromFS();
@@ -469,7 +473,7 @@ uint8_t WebCustomEntityService::has_commands() {
return count;
}
// send to dashboard, msgpack don't like serialized, use number
// send to dashboard
void WebCustomEntityService::generate_value_web(JsonObject & output) {
EMSESP::webCustomEntityService.read([&](WebCustomEntity & webEntity) { customEntityItems = &webEntity.customEntityItems; });

View File

@@ -50,9 +50,11 @@ class WebCustomEntity {
class WebCustomEntityService : public StatefulService<WebCustomEntity> {
public:
WebCustomEntityService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager);
WebCustomEntityService(PsychicHttpServer * server, FS * fs, SecurityManager * securityManager);
void begin();
void registerURI();
void publish_single(const CustomEntityItem & entity);
void publish(const bool force = false);
bool command_setvalue(const char * value, const std::string name);

View File

@@ -24,35 +24,38 @@ using namespace std::placeholders; // for `_1` etc
bool WebCustomization::_start = true;
WebCustomizationService::WebCustomizationService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
: _httpEndpoint(WebCustomization::read,
WebCustomizationService::WebCustomizationService(PsychicHttpServer * server, FS * fs, SecurityManager * securityManager)
: _server(server)
, _securityManager(securityManager)
, _httpEndpoint(WebCustomization::read,
WebCustomization::update,
this,
server,
EMSESP_CUSTOMIZATION_SERVICE_PATH,
securityManager,
AuthenticationPredicates::IS_AUTHENTICATED)
, _fsPersistence(WebCustomization::read, WebCustomization::update, this, fs, EMSESP_CUSTOMIZATION_FILE)
, _masked_entities_handler(CUSTOMIZATION_ENTITIES_PATH,
securityManager->wrapCallback(std::bind(&WebCustomizationService::customization_entities, this, _1, _2),
AuthenticationPredicates::IS_AUTHENTICATED)) {
server->on(DEVICE_ENTITIES_PATH,
HTTP_GET,
securityManager->wrapRequest(std::bind(&WebCustomizationService::device_entities, this, _1), AuthenticationPredicates::IS_AUTHENTICATED));
, _fsPersistence(WebCustomization::read, WebCustomization::update, this, fs, EMSESP_CUSTOMIZATION_FILE) {
}
void WebCustomizationService::registerURI() {
_httpEndpoint.registerURI();
server->on(DEVICES_SERVICE_PATH,
HTTP_GET,
securityManager->wrapRequest(std::bind(&WebCustomizationService::devices, this, _1), AuthenticationPredicates::IS_AUTHENTICATED));
_server->on(CUSTOMIZATION_ENTITIES_PATH,
HTTP_POST,
_securityManager->wrapCallback(std::bind(&WebCustomizationService::customization_entities, this, _1, _2),
AuthenticationPredicates::IS_AUTHENTICATED));
server->on(RESET_CUSTOMIZATION_SERVICE_PATH,
HTTP_POST,
securityManager->wrapRequest(std::bind(&WebCustomizationService::reset_customization, this, _1), AuthenticationPredicates::IS_ADMIN));
_server->on(DEVICE_ENTITIES_PATH,
HTTP_GET,
_securityManager->wrapRequest(std::bind(&WebCustomizationService::device_entities, this, _1), AuthenticationPredicates::IS_AUTHENTICATED));
_masked_entities_handler.setMethod(HTTP_POST);
_masked_entities_handler.setMaxContentLength(2048);
_masked_entities_handler.setMaxJsonBufferSize(2048);
server->addHandler(&_masked_entities_handler);
_server->on(DEVICES_SERVICE_PATH,
HTTP_GET,
_securityManager->wrapRequest(std::bind(&WebCustomizationService::devices, this, _1), AuthenticationPredicates::IS_AUTHENTICATED));
_server->on(RESET_CUSTOMIZATION_SERVICE_PATH,
HTTP_POST,
_securityManager->wrapRequest(std::bind(&WebCustomizationService::reset_customization, this, _1), AuthenticationPredicates::IS_ADMIN));
}
// this creates the customization file, saving it to the FS
@@ -163,24 +166,22 @@ StateUpdateResult WebCustomization::update(JsonObject & root, WebCustomization &
}
// deletes the customization file
void WebCustomizationService::reset_customization(AsyncWebServerRequest * request) {
esp_err_t WebCustomizationService::reset_customization(PsychicRequest * request) {
#ifndef EMSESP_STANDALONE
if (LittleFS.remove(EMSESP_CUSTOMIZATION_FILE)) {
AsyncWebServerResponse * response = request->beginResponse(205); // restart needed
request->send(response);
EMSESP::system_.restart_requested(true);
return;
return request->reply(205); // restart needed
}
// failed
AsyncWebServerResponse * response = request->beginResponse(400); // bad request
request->send(response);
return request->reply(400); // bad request
#endif
}
// 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_XLARGE);
JsonObject root = response->getRoot();
esp_err_t WebCustomizationService::devices(PsychicRequest * request) {
PsychicJsonResponse response = PsychicJsonResponse(request, false, EMSESP_JSON_SIZE_XLARGE);
JsonObject root = response.getRoot();
// list is already sorted by device type
// controller is ignored since it doesn't have any associated entities
@@ -195,51 +196,47 @@ void WebCustomizationService::devices(AsyncWebServerRequest * request) {
}
}
response->setLength();
request->send(response);
return response.send();
}
// send back list of device entities
void WebCustomizationService::device_entities(AsyncWebServerRequest * request) {
esp_err_t WebCustomizationService::device_entities(PsychicRequest * request) {
uint8_t id;
if (request->hasParam(F_(id))) {
id = Helpers::atoint(request->getParam(F_(id))->value().c_str()); // get id from url
size_t buffer = EMSESP_JSON_SIZE_XXXXLARGE;
auto * response = new MsgpackAsyncJsonResponse(true, buffer);
PsychicJsonResponse response = PsychicJsonResponse(request, true, EMSESP_JSON_SIZE_XXXXLARGE, true); // is array and also msgpack
JsonArray output = response.getRoot();
// TODO add back memory management
// while (!response) {
// delete response;
// buffer -= 1024;
// // response = new MsgpackAsyncJsonResponse(true, buffer);
// }
// TODO add msgpack
while (!response) {
delete response;
buffer -= 1024;
response = new MsgpackAsyncJsonResponse(true, buffer);
}
for (const auto & emsdevice : EMSESP::emsdevices) {
if (emsdevice->unique_id() == id) {
#ifndef EMSESP_STANDALONE
JsonArray output = response->getRoot();
emsdevice->generate_values_web_customization(output);
#endif
#if defined(EMSESP_DEBUG)
size_t length = response->setLength();
EMSESP::logger().debug("Customization buffer used: %d", length);
#else
response->setLength();
#endif
request->send(response);
return;
// request->send(response);
// return;
return response.send();
}
}
}
// invalid, but send OK anyway
AsyncWebServerResponse * response = request->beginResponse(200);
request->send(response);
return request->reply(200); // OK
}
// takes a list of updated entities with new masks from the web UI
// saves it in the customization service
// and updates the entity list real-time
void WebCustomizationService::customization_entities(AsyncWebServerRequest * request, JsonVariant & json) {
esp_err_t WebCustomizationService::customization_entities(PsychicRequest * request, JsonVariant & json) {
bool need_reboot = false;
if (json.is<JsonObject>()) {
// find the device using the unique_id
@@ -324,8 +321,7 @@ void WebCustomizationService::customization_entities(AsyncWebServerRequest * req
}
}
AsyncWebServerResponse * response = request->beginResponse(need_reboot ? 205 : 200); // reboot or just OK
request->send(response);
return request->reply(need_reboot ? 205 : 200); // reboot or just OK
}
// load the settings when the service starts

View File

@@ -80,9 +80,10 @@ class WebCustomization {
class WebCustomizationService : public StatefulService<WebCustomization> {
public:
WebCustomizationService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager);
WebCustomizationService(PsychicHttpServer * server, FS * fs, SecurityManager * securityManager);
void begin();
void registerURI();
// make all functions public so we can test in the debug and standalone mode
#ifndef EMSESP_STANDALONE
@@ -93,14 +94,16 @@ class WebCustomizationService : public StatefulService<WebCustomization> {
FSPersistence<WebCustomization> _fsPersistence;
// GET
void devices(AsyncWebServerRequest * request);
void device_entities(AsyncWebServerRequest * request);
esp_err_t devices(PsychicRequest * request);
esp_err_t device_entities(PsychicRequest * request);
// POST
void customization_entities(AsyncWebServerRequest * request, JsonVariant & json);
void reset_customization(AsyncWebServerRequest * request); // command
esp_err_t customization_entities(PsychicRequest * request, JsonVariant & json);
esp_err_t reset_customization(PsychicRequest * request); // is a command
AsyncCallbackJsonWebHandler _masked_entities_handler;
private:
SecurityManager * _securityManager;
PsychicHttpServer * _server;
};
} // namespace emsesp

View File

@@ -22,57 +22,56 @@ namespace emsesp {
using namespace std::placeholders; // for `_1` etc
WebDataService::WebDataService(AsyncWebServer * server, SecurityManager * securityManager)
: _write_value_handler(WRITE_DEVICE_VALUE_SERVICE_PATH,
securityManager->wrapCallback(std::bind(&WebDataService::write_device_value, this, _1, _2), AuthenticationPredicates::IS_ADMIN))
, _write_temperature_handler(WRITE_TEMPERATURE_SENSOR_SERVICE_PATH,
securityManager->wrapCallback(std::bind(&WebDataService::write_temperature_sensor, this, _1, _2),
AuthenticationPredicates::IS_ADMIN))
, _write_analog_handler(WRITE_ANALOG_SENSOR_SERVICE_PATH,
securityManager->wrapCallback(std::bind(&WebDataService::write_analog_sensor, this, _1, _2), AuthenticationPredicates::IS_ADMIN)) {
// GET's
server->on(DEVICE_DATA_SERVICE_PATH,
HTTP_GET,
securityManager->wrapRequest(std::bind(&WebDataService::device_data, this, _1), AuthenticationPredicates::IS_AUTHENTICATED));
server->on(CORE_DATA_SERVICE_PATH,
HTTP_GET,
securityManager->wrapRequest(std::bind(&WebDataService::core_data, this, _1), AuthenticationPredicates::IS_AUTHENTICATED));
server->on(SENSOR_DATA_SERVICE_PATH,
HTTP_GET,
securityManager->wrapRequest(std::bind(&WebDataService::sensor_data, this, _1), AuthenticationPredicates::IS_AUTHENTICATED));
// POST's
server->on(SCAN_DEVICES_SERVICE_PATH,
HTTP_POST,
securityManager->wrapRequest(std::bind(&WebDataService::scan_devices, this, _1), AuthenticationPredicates::IS_ADMIN));
_write_value_handler.setMethod(HTTP_POST);
_write_value_handler.setMaxContentLength(256);
server->addHandler(&_write_value_handler);
_write_temperature_handler.setMethod(HTTP_POST);
_write_temperature_handler.setMaxContentLength(256);
server->addHandler(&_write_temperature_handler);
_write_analog_handler.setMethod(HTTP_POST);
_write_analog_handler.setMaxContentLength(256);
server->addHandler(&_write_analog_handler);
WebDataService::WebDataService(PsychicHttpServer * server, SecurityManager * securityManager)
: _server(server)
, _securityManager(securityManager) {
}
void WebDataService::registerURI() {
// GET's
_server->on(CORE_DATA_SERVICE_PATH,
HTTP_GET,
_securityManager->wrapRequest(std::bind(&WebDataService::core_data, this, _1), AuthenticationPredicates::IS_AUTHENTICATED));
_server->on(DEVICE_DATA_SERVICE_PATH,
HTTP_GET,
_securityManager->wrapRequest(std::bind(&WebDataService::device_data, this, _1), AuthenticationPredicates::IS_AUTHENTICATED));
_server->on(SENSOR_DATA_SERVICE_PATH,
HTTP_GET,
_securityManager->wrapRequest(std::bind(&WebDataService::sensor_data, this, _1), AuthenticationPredicates::IS_AUTHENTICATED));
// POST's
_server->on(SCAN_DEVICES_SERVICE_PATH,
HTTP_POST,
_securityManager->wrapRequest(std::bind(&WebDataService::scan_devices, this, _1), AuthenticationPredicates::IS_ADMIN));
_server->on(WRITE_DEVICE_VALUE_SERVICE_PATH,
HTTP_POST,
_securityManager->wrapCallback(std::bind(&WebDataService::write_device_value, this, _1, _2), AuthenticationPredicates::IS_AUTHENTICATED));
_server->on(WRITE_TEMPERATURE_SENSOR_SERVICE_PATH,
HTTP_POST,
_securityManager->wrapCallback(std::bind(&WebDataService::write_temperature_sensor, this, _1, _2), AuthenticationPredicates::IS_AUTHENTICATED));
_server->on(WRITE_ANALOG_SENSOR_SERVICE_PATH,
HTTP_POST,
_securityManager->wrapCallback(std::bind(&WebDataService::write_analog_sensor, this, _1, _2), AuthenticationPredicates::IS_AUTHENTICATED));
}
// scan devices service
void WebDataService::scan_devices(AsyncWebServerRequest * request) {
esp_err_t WebDataService::scan_devices(PsychicRequest * request) {
EMSESP::logger().info("Scanning devices...");
EMSESP::scan_devices();
request->send(200);
return request->reply(200);
}
// 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_XXLARGE);
JsonObject root = response->getRoot();
esp_err_t WebDataService::core_data(PsychicRequest * request) {
PsychicJsonResponse response = PsychicJsonResponse(request, false, EMSESP_JSON_SIZE_XXLARGE);
JsonObject root = response.getRoot();
// list is already sorted by device type
JsonArray devices = root.createNestedArray("devices");
@@ -109,15 +108,14 @@ void WebDataService::core_data(AsyncWebServerRequest * request) {
root["connected"] = EMSESP::bus_status() != 2;
response->setLength();
request->send(response);
return response.send();
}
// sensor data - sends back to web
// /sensorData endpoint
void WebDataService::sensor_data(AsyncWebServerRequest * request) {
auto * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_XXLARGE);
JsonObject root = response->getRoot();
esp_err_t WebDataService::sensor_data(PsychicRequest * request) {
PsychicJsonResponse response = PsychicJsonResponse(request, false, EMSESP_JSON_SIZE_XXLARGE);
JsonObject root = response.getRoot();
// temperature sensors
JsonArray sensors = root.createNestedArray("ts");
@@ -167,26 +165,26 @@ void WebDataService::sensor_data(AsyncWebServerRequest * request) {
root["analog_enabled"] = EMSESP::analog_enabled();
root["platform"] = EMSESP_PLATFORM;
response->setLength();
request->send(response);
return response.send();
}
// The unique_id is the unique record ID from the Web table to identify which device to load
// Compresses the JSON using MsgPack https://msgpack.org/index.html
void WebDataService::device_data(AsyncWebServerRequest * request) {
esp_err_t WebDataService::device_data(PsychicRequest * request) {
uint8_t id;
if (request->hasParam(F_(id))) {
id = Helpers::atoint(request->getParam(F_(id))->value().c_str()); // get id from url
size_t buffer = EMSESP_JSON_SIZE_XXXXLARGE;
auto * response = new MsgpackAsyncJsonResponse(false, buffer);
PsychicJsonResponse response = PsychicJsonResponse(request, false, EMSESP_JSON_SIZE_XXXXLARGE, true); // is jsonobject and also msgpack
JsonObject output = response.getRoot();
// TODO add back memory management?
// check size
while (!response) {
delete response;
buffer -= 1024;
response = new MsgpackAsyncJsonResponse(false, buffer);
}
// while (!response) {
// delete response;
// buffer -= 1024;
// response = new MsgpackAsyncJsonResponse(false, buffer);
// }
for (const auto & emsdevice : EMSESP::emsdevices) {
if (emsdevice->unique_id() == id) {
@@ -196,39 +194,26 @@ void WebDataService::device_data(AsyncWebServerRequest * request) {
}
EMSESP::wait_validate(0); // reset in case of timeout
#ifndef EMSESP_STANDALONE
JsonObject output = response->getRoot();
emsdevice->generate_values_web(output);
#endif
#if defined(EMSESP_DEBUG)
size_t length = response->setLength();
EMSESP::logger().debug("Dashboard buffer used: %d", length);
#else
response->setLength();
#endif
request->send(response);
return;
return response.send();
}
}
#ifndef EMSESP_STANDALONE
if (id == 99) {
JsonObject output = response->getRoot();
EMSESP::webCustomEntityService.generate_value_web(output);
response->setLength();
request->send(response);
return;
return response.send();
}
#endif
}
// invalid
AsyncWebServerResponse * response = request->beginResponse(400);
request->send(response);
return request->reply(400); // Invalid/bad request
}
// assumes the service has been checked for admin authentication
void WebDataService::write_device_value(AsyncWebServerRequest * request, JsonVariant & json) {
esp_err_t WebDataService::write_device_value(PsychicRequest * request, JsonVariant & json) {
if (json.is<JsonObject>()) {
uint8_t unique_id = json["id"]; // unique ID
const char * cmd = json["c"]; // the command
@@ -236,9 +221,7 @@ void WebDataService::write_device_value(AsyncWebServerRequest * request, JsonVar
// quit on bad values
if (strlen(cmd) == 0 || data.isNull()) {
AsyncWebServerResponse * response = request->beginResponse(400); // bad request
request->send(response);
return;
return request->reply(400); // Invalid/bad request
}
// using the unique ID from the web find the real device type
@@ -249,8 +232,8 @@ void WebDataService::write_device_value(AsyncWebServerRequest * request, JsonVar
cmd = Command::parse_command_string(cmd, id); // extract hc or wwc
// create JSON for output
auto * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_SMALL);
JsonObject output = response->getRoot();
PsychicJsonResponse response = PsychicJsonResponse(request, false, EMSESP_JSON_SIZE_SMALL);
JsonObject output = response.getRoot();
// the data could be in any format, but we need string
// authenticated is always true
@@ -277,22 +260,22 @@ void WebDataService::write_device_value(AsyncWebServerRequest * request, JsonVar
#endif
}
response->setCode((return_code == CommandRet::OK) ? 200 : 400); // bad request
response->setLength();
request->send(response);
return;
response.setCode((return_code == CommandRet::OK) ? 200 : 400); // bad request
return response.send();
}
}
// special check for custom entities (which have a unique id of 99)
if (unique_id == 99) {
// parse the command as it could have a hc or wwc prefixed, e.g. hc2/seltemp
int8_t id = -1;
cmd = Command::parse_command_string(cmd, id);
auto * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_SMALL);
JsonObject output = response->getRoot();
uint8_t return_code = CommandRet::NOT_FOUND;
uint8_t device_type = EMSdevice::DeviceType::CUSTOM;
int8_t id = -1;
cmd = Command::parse_command_string(cmd, id);
PsychicJsonResponse response = PsychicJsonResponse(request, false, EMSESP_JSON_SIZE_SMALL);
JsonObject output = response.getRoot();
uint8_t return_code = CommandRet::NOT_FOUND;
uint8_t device_type = EMSdevice::DeviceType::CUSTOM;
if (data.is<const char *>()) {
return_code = Command::call(device_type, cmd, data.as<const char *>(), true, id, output);
} else if (data.is<int>()) {
@@ -310,21 +293,18 @@ void WebDataService::write_device_value(AsyncWebServerRequest * request, JsonVar
#endif
}
response->setCode((return_code == CommandRet::OK) ? 200 : 400); // bad request
response->setLength();
request->send(response);
return;
response.setCode((return_code == CommandRet::OK) ? 200 : 400); // bad request
return response.send();
}
}
// if we reach here, fail
AsyncWebServerResponse * response = request->beginResponse(400); // bad request
request->send(response);
return request->reply(400); // Invalid/Bad Request
}
// takes a temperaturesensor name and optional offset from the WebUI and update the customization settings
// via the temperaturesensor service
void WebDataService::write_temperature_sensor(AsyncWebServerRequest * request, JsonVariant & json) {
esp_err_t WebDataService::write_temperature_sensor(PsychicRequest * request, JsonVariant & json) {
bool ok = false;
if (json.is<JsonObject>()) {
JsonObject sensor = json;
@@ -342,12 +322,11 @@ void WebDataService::write_temperature_sensor(AsyncWebServerRequest * request, J
ok = EMSESP::temperaturesensor_.update(id, name, offset10);
}
AsyncWebServerResponse * response = request->beginResponse(ok ? 200 : 400); // bad request
request->send(response);
return request->reply(ok ? 200 : 400); // bad request); // Invalid/Bad Request
}
// update the analog record, or create a new one
void WebDataService::write_analog_sensor(AsyncWebServerRequest * request, JsonVariant & json) {
esp_err_t WebDataService::write_analog_sensor(PsychicRequest * request, JsonVariant & json) {
bool ok = false;
if (json.is<JsonObject>()) {
JsonObject analog = json;
@@ -362,8 +341,7 @@ void WebDataService::write_analog_sensor(AsyncWebServerRequest * request, JsonVa
ok = EMSESP::analogsensor_.update(gpio, name, offset, factor, uom, type, deleted);
}
AsyncWebServerResponse * response = request->beginResponse(ok ? 200 : 400); // bad request
request->send(response);
return request->reply(ok ? 200 : 400); // bad request); // Invalid/Bad Request
}
} // namespace emsesp

View File

@@ -34,25 +34,27 @@ namespace emsesp {
class WebDataService {
public:
WebDataService(AsyncWebServer * server, SecurityManager * securityManager);
WebDataService(PsychicHttpServer * server, SecurityManager * securityManager);
void registerURI();
// make all functions public so we can test in the debug and standalone mode
#ifndef EMSESP_STANDALONE
private:
#endif
SecurityManager * _securityManager;
PsychicHttpServer * _server;
// GET
void core_data(AsyncWebServerRequest * request);
void sensor_data(AsyncWebServerRequest * request);
void device_data(AsyncWebServerRequest * request);
esp_err_t core_data(PsychicRequest * request);
esp_err_t sensor_data(PsychicRequest * request);
esp_err_t device_data(PsychicRequest * request);
// POST
void write_device_value(AsyncWebServerRequest * request, JsonVariant & json);
void write_temperature_sensor(AsyncWebServerRequest * request, JsonVariant & json);
void write_analog_sensor(AsyncWebServerRequest * request, JsonVariant & json);
void scan_devices(AsyncWebServerRequest * request); // command
AsyncCallbackJsonWebHandler _write_value_handler, _write_temperature_handler, _write_analog_handler;
esp_err_t write_device_value(PsychicRequest * request, JsonVariant & json);
esp_err_t write_temperature_sensor(PsychicRequest * request, JsonVariant & json);
esp_err_t write_analog_sensor(PsychicRequest * request, JsonVariant & json);
esp_err_t scan_devices(PsychicRequest * request); // command
};
} // namespace emsesp

View File

@@ -22,18 +22,66 @@ using namespace std::placeholders;
namespace emsesp {
WebLogService::WebLogService(AsyncWebServer * server, SecurityManager * securityManager)
: events_(EVENT_SOURCE_LOG_PATH)
, setValues_(LOG_SETTINGS_PATH, std::bind(&WebLogService::setValues, this, _1, _2), 256) {
events_.setFilter(securityManager->filterRequest(AuthenticationPredicates::IS_ADMIN));
WebLogService::WebLogService(PsychicHttpServer * server, SecurityManager * securityManager)
// TODO fix event source
: // : _events(EVENT_SOURCE_LOG_PATH)
_server(server)
, _securityManager(securityManager) {
}
server->on(LOG_SETTINGS_PATH, HTTP_GET, std::bind(&WebLogService::getValues, this, _1)); // get settings
void WebLogService::registerURI() {
// TODO fix event source
/*
_events_.onOpen([](PsychicEventSourceClient * client) {
Serial.printf("[eventsource] connection #%u connected from %s\n", client->socket(), client->remoteIP().toString());
client->send("Hello user!", NULL, millis(), 1000);
});
_events_.onClose([](PsychicEventSourceClient * client) {
Serial.printf("[eventsource] connection #%u closed from %s\n", client->socket(), client->remoteIP().toString());
});
_server->on(EVENT_SOURCE_LOG_PATH, &events_);
*/
// post
_server->on(LOG_SETTINGS_PATH, HTTP_POST, [this](PsychicRequest * request, JsonVariant & json) {
auto && body = json.as<JsonObject>();
uuid::log::Level level = body["level"];
log_level(level);
uint8_t max_messages = body["max_messages"];
maximum_log_messages(max_messages);
bool comp = body["compact"];
compact(comp);
return request->reply(200); // OK
});
_events.setFilter(_securityManager->filterRequest(AuthenticationPredicates::IS_ADMIN));
// get settings
_server->on(LOG_SETTINGS_PATH, HTTP_GET, [this](PsychicRequest * request) {
PsychicJsonResponse response = PsychicJsonResponse(request, false, EMSESP_JSON_SIZE_SMALL);
JsonObject root = response.getRoot();
root["level"] = log_level();
root["max_messages"] = maximum_log_messages();
root["compact"] = compact();
return response.send();
});
// for bring back the whole log - is a command, hence a POST
server->on(FETCH_LOG_PATH, HTTP_POST, std::bind(&WebLogService::fetchLog, this, _1));
// send the complete log buffer to the API, not filtering on log level
// done by resetting the pointer
_server->on(FETCH_LOG_PATH, HTTP_POST, [this](PsychicRequest * request) {
log_message_id_tail_ = 0;
return request->reply(200);
});
server->addHandler(&setValues_);
server->addHandler(&events_);
// TODO remove?
// server->addHandler(&events_);
}
// start the log service with INFO level
@@ -143,7 +191,7 @@ void WebLogService::operator<<(std::shared_ptr<uuid::log::Message> message) {
}
void WebLogService::loop() {
if (!events_.count() || log_messages_.empty()) {
if (!_events.count() || log_messages_.empty()) {
return;
}
@@ -200,47 +248,43 @@ void WebLogService::transmit(const QueuedLogMessage & message) {
char * buffer = new char[len + 1];
if (buffer) {
serializeJson(jsonDocument, buffer, len + 1);
events_.send(buffer, "message", message.id_);
_events.send(buffer, "message", message.id_);
}
delete[] buffer;
}
// send the complete log buffer to the API, not filtering on log level
// done by resetting the pointer
void WebLogService::fetchLog(AsyncWebServerRequest * request) {
log_message_id_tail_ = 0;
request->send(200);
}
// sets the values like level after a POST
void WebLogService::setValues(AsyncWebServerRequest * request, JsonVariant & json) {
if (!json.is<JsonObject>()) {
return;
}
auto && body = json.as<JsonObject>();
uuid::log::Level level = body["level"];
log_level(level);
uint8_t max_messages = body["max_messages"];
maximum_log_messages(max_messages);
bool comp = body["compact"];
compact(comp);
request->send(200); // OK
}
// esp_err_t WebLogService::fetchLog(PsychicRequest * request) {
// log_message_id_tail_ = 0;
// request->send(200);
// }
// return the current value settings after a GET
void WebLogService::getValues(AsyncWebServerRequest * request) {
auto * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_SMALL);
JsonObject root = response->getRoot();
root["level"] = log_level();
root["max_messages"] = maximum_log_messages();
root["compact"] = compact();
response->setLength();
request->send(response);
}
// esp_err_t WebLogService::getValues(PsychicRequest * request) {
// auto * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_SMALL);
// JsonObject root = response->getRoot();
// root["level"] = log_level();
// root["max_messages"] = maximum_log_messages();
// root["compact"] = compact();
// response->setLength();
// request->send(response);
// }
// sets the values like level after a POST
// esp_err_t WebLogService::setValues(PsychicRequest * request, JsonVariant & json) {
// auto && body = json.as<JsonObject>();
// uuid::log::Level level = body["level"];
// log_level(level);
// uint8_t max_messages = body["max_messages"];
// maximum_log_messages(max_messages);
// bool comp = body["compact"];
// compact(comp);
// return request->reply(200); // OK
// }
} // namespace emsesp

View File

@@ -1,7 +1,7 @@
/*
* 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
@@ -30,10 +30,13 @@ class WebLogService : public uuid::log::Handler {
static constexpr size_t MAX_LOG_MESSAGES = 50;
static constexpr size_t REFRESH_SYNC = 50;
WebLogService(AsyncWebServer * server, SecurityManager * securityManager);
WebLogService(PsychicHttpServer * server, SecurityManager * securityManager);
void begin();
void start();
void loop();
void registerURI();
void begin();
void start();
uuid::log::Level log_level() const;
void log_level(uuid::log::Level level);
size_t maximum_log_messages() const;
@@ -41,12 +44,13 @@ class WebLogService : public uuid::log::Handler {
void maximum_log_messages(size_t count);
bool compact() const;
void compact(bool compact);
void loop();
virtual void operator<<(std::shared_ptr<uuid::log::Message> message);
private:
AsyncEventSource events_;
PsychicEventSource _events;
SecurityManager * _securityManager;
PsychicHttpServer * _server;
class QueuedLogMessage {
public:
@@ -58,15 +62,15 @@ class WebLogService : public uuid::log::Handler {
const std::shared_ptr<const uuid::log::Message> content_; // Log message content
};
void transmit(const QueuedLogMessage & message);
void fetchLog(AsyncWebServerRequest * request);
void getValues(AsyncWebServerRequest * request);
void transmit(const QueuedLogMessage & message);
char * messagetime(char * out, const uint64_t t, const size_t bufsize);
void setValues(AsyncWebServerRequest * request, JsonVariant & json);
// TODO remove this?
// PsychicJsonHandler setValues_; // for POSTs
AsyncCallbackJsonWebHandler setValues_; // for POSTs
esp_err_t fetchLog(PsychicRequest * request);
esp_err_t getValues(PsychicRequest * request);
esp_err_t setValues(PsychicRequest * request, JsonVariant & json);
uint64_t last_transmit_ = 0; // Last transmit time
size_t maximum_log_messages_ = MAX_LOG_MESSAGES; // Maximum number of log messages to buffer before they are output

View File

@@ -22,11 +22,15 @@ namespace emsesp {
using namespace std::placeholders; // for `_1` etc
WebSchedulerService::WebSchedulerService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
WebSchedulerService::WebSchedulerService(PsychicHttpServer * 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) {
}
void WebSchedulerService::registerURI() {
_httpEndpoint.registerURI();
}
// load the settings when the service starts
void WebSchedulerService::begin() {
_fsPersistence.readFromFS();

View File

@@ -1,7 +1,7 @@
/*
* 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
@@ -49,10 +49,12 @@ class WebScheduler {
class WebSchedulerService : public StatefulService<WebScheduler> {
public:
WebSchedulerService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager);
WebSchedulerService(PsychicHttpServer * server, FS * fs, SecurityManager * securityManager);
void begin();
void loop();
void registerURI();
void publish_single(const char * name, const bool state);
void publish(const bool force = false);
bool has_commands();

View File

@@ -1,7 +1,7 @@
/*
* 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
@@ -24,17 +24,21 @@ uint8_t WebSettings::flags_ = 0;
using namespace std::placeholders; // for `_1` etc
WebSettingsService::WebSettingsService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
: _httpEndpoint(WebSettings::read, WebSettings::update, this, server, EMSESP_SETTINGS_SERVICE_PATH, securityManager)
WebSettingsService::WebSettingsService(PsychicHttpServer * server, FS * fs, SecurityManager * securityManager)
: _server(server)
, _securityManager(securityManager)
, _httpEndpoint(WebSettings::read, WebSettings::update, this, server, EMSESP_SETTINGS_SERVICE_PATH, securityManager)
, _fsPersistence(WebSettings::read, WebSettings::update, this, fs, EMSESP_SETTINGS_FILE) {
// GET
server->on(EMSESP_BOARD_PROFILE_SERVICE_PATH,
HTTP_GET,
securityManager->wrapRequest(std::bind(&WebSettingsService::board_profile, this, _1), AuthenticationPredicates::IS_ADMIN));
addUpdateHandler([&](const String & originId) { onUpdate(); }, false);
}
void WebSettingsService::registerURI() {
_httpEndpoint.registerURI();
_server->on(EMSESP_BOARD_PROFILE_SERVICE_PATH,
HTTP_GET,
_securityManager->wrapRequest(std::bind(&WebSettingsService::board_profile, this, _1), AuthenticationPredicates::IS_ADMIN));
}
void WebSettings::read(WebSettings & settings, JsonObject & root) {
root["version"] = settings.version;
root["locale"] = settings.locale;
@@ -91,6 +95,7 @@ StateUpdateResult WebSettings::update(JsonObject & root, WebSettings & settings)
if ((String)EMSESP_DEFAULT_BOARD_PROFILE != "default" && EMSESP::nvs_.getString("boot") == "") {
EMSESP::nvs_.putString("boot", (const char *)EMSESP_DEFAULT_BOARD_PROFILE);
}
/*
#if CONFIG_IDF_TARGET_ESP32C3
settings.board_profile = root["board_profile"] | "C3MINI";
@@ -103,19 +108,28 @@ StateUpdateResult WebSettings::update(JsonObject & root, WebSettings & settings)
settings.board_profile = root["board_profile"] | EMSESP_DEFAULT_BOARD_PROFILE;
#endif
*/
if (!System::load_board_profile(data, settings.board_profile.c_str())) {
// unknown, check for NVS or scan for ethernet, use default E32/E32V2/S32
settings.board_profile = EMSESP::nvs_.getString("boot");
if (!System::load_board_profile(data, settings.board_profile.c_str())) {
#if CONFIG_IDF_TARGET_ESP32 && !defined(EMSESP_STANDALONE)
if (settings.board_profile == "") { // empty: new test
if (ETH.begin((eth_phy_type_t)1, 16, 23, 18, ETH_PHY_LAN8720, ETH_CLOCK_GPIO0_IN)) {
#if ESP_ARDUINO_VERSION_MAJOR < 3
if (ETH.begin(1, 16, 23, 18, ETH_PHY_LAN8720, ETH_CLOCK_GPIO0_IN)) {
#else
if (ETH.begin(ETH_PHY_LAN8720, 1, 23, 18, 16, ETH_CLOCK_GPIO0_IN)) {
#endif
EMSESP::nvs_.putString("boot", "E32");
} else {
EMSESP::nvs_.putString("boot", "Test");
}
} else if (settings.board_profile == "Test") {
if (ETH.begin((eth_phy_type_t)0, 15, 23, 18, ETH_PHY_LAN8720, ETH_CLOCK_GPIO0_OUT)) {
#if ESP_ARDUINO_VERSION_MAJOR < 3
if (ETH.begin(0, 15, 23, 18, ETH_PHY_LAN8720, ETH_CLOCK_GPIO0_OUT)) {
#else
if (ETH.begin(ETH_PHY_LAN8720, 0, 23, 18, 15, ETH_CLOCK_GPIO0_OUT)) {
#endif
EMSESP::nvs_.putString("boot", "E32V2");
} else {
EMSESP::nvs_.putString("boot", "S32");
@@ -352,12 +366,12 @@ void WebSettingsService::save() {
}
// build the json profile to send back
void WebSettingsService::board_profile(AsyncWebServerRequest * request) {
esp_err_t WebSettingsService::board_profile(PsychicRequest * request) {
if (request->hasParam("boardProfile")) {
std::string board_profile = request->getParam("boardProfile")->value().c_str();
auto * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_MEDIUM);
JsonObject root = response->getRoot();
PsychicJsonResponse response = PsychicJsonResponse(request, false, EMSESP_JSON_SIZE_MEDIUM);
JsonObject root = response.getRoot();
std::vector<int8_t> data; // led, dallas, rx, tx, button, phy_type, eth_power, eth_phy_addr, eth_clock_mode
(void)System::load_board_profile(data, board_profile);
@@ -372,13 +386,10 @@ void WebSettingsService::board_profile(AsyncWebServerRequest * request) {
root["eth_phy_addr"] = data[7];
root["eth_clock_mode"] = data[8];
response->setLength();
request->send(response);
return;
return response.send();
}
AsyncWebServerResponse * response = request->beginResponse(200);
request->send(response);
return request->reply(200);
}
} // namespace emsesp

View File

@@ -117,16 +117,20 @@ class WebSettings {
class WebSettingsService : public StatefulService<WebSettings> {
public:
WebSettingsService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager);
WebSettingsService(PsychicHttpServer * server, FS * fs, SecurityManager * securityManager);
void begin();
void save();
void registerURI();
private:
SecurityManager * _securityManager;
PsychicHttpServer * _server;
HttpEndpoint<WebSettings> _httpEndpoint;
FSPersistence<WebSettings> _fsPersistence;
void board_profile(AsyncWebServerRequest * request);
esp_err_t board_profile(PsychicRequest * request);
void onUpdate();
};

View File

@@ -1,7 +1,7 @@
/*
* 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
@@ -22,14 +22,18 @@ using namespace std::placeholders; // for `_1` etc
namespace emsesp {
WebStatusService::WebStatusService(AsyncWebServer * server, SecurityManager * securityManager) {
// rest endpoint for web page
server->on(EMSESP_STATUS_SERVICE_PATH,
HTTP_GET,
securityManager->wrapRequest(std::bind(&WebStatusService::webStatusService, this, _1), AuthenticationPredicates::IS_AUTHENTICATED));
WebStatusService::WebStatusService(PsychicHttpServer * server, SecurityManager * securityManager)
: _server(server)
, _securityManager(securityManager) {
WiFi.onEvent(std::bind(&WebStatusService::WiFiEvent, this, _1, _2));
}
void WebStatusService::registerURI() {
_server->on(EMSESP_STATUS_SERVICE_PATH,
HTTP_GET,
_securityManager->wrapRequest(std::bind(&WebStatusService::webStatusService, this, _1), AuthenticationPredicates::IS_AUTHENTICATED));
}
// handles both WiFI and Ethernet
void WebStatusService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) {
#ifndef EMSESP_STANDALONE
@@ -114,9 +118,9 @@ void WebStatusService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) {
#endif
}
void WebStatusService::webStatusService(AsyncWebServerRequest * request) {
auto * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_LARGE);
JsonObject root = response->getRoot();
esp_err_t WebStatusService::webStatusService(PsychicRequest * request) {
PsychicJsonResponse response = PsychicJsonResponse(request, false, EMSESP_JSON_SIZE_LARGE);
JsonObject root = response.getRoot();
root["status"] = EMSESP::bus_status(); // 0, 1 or 2
root["tx_mode"] = EMSESP::txservice_.tx_mode();
@@ -189,8 +193,7 @@ void WebStatusService::webStatusService(AsyncWebServerRequest * request) {
}
#endif
response->setLength();
request->send(response);
return response.send();
}
// start the multicast UDP service so EMS-ESP is discoverable via .local

View File

@@ -1,7 +1,7 @@
/*
* 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
@@ -27,10 +27,14 @@ namespace emsesp {
class WebStatusService {
public:
WebStatusService(AsyncWebServer * server, SecurityManager * securityManager);
WebStatusService(PsychicHttpServer * server, SecurityManager * securityManager);
void registerURI();
private:
void webStatusService(AsyncWebServerRequest * request);
SecurityManager * _securityManager;
PsychicHttpServer * _server;
esp_err_t webStatusService(PsychicRequest * request);
void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info);
void mDNS_start() const;
const char * disconnectReason(uint8_t code);