mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-06 07:49:52 +03:00
refactoring
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
#include <APSettingsService.h>
|
||||
#include "APSettingsService.h"
|
||||
|
||||
#include "../../src/emsesp_stub.hpp"
|
||||
|
||||
@@ -9,8 +9,8 @@ APSettingsService::APSettingsService(AsyncWebServer * server, FS * fs, SecurityM
|
||||
, _lastManaged(0)
|
||||
, _reconfigureAp(false)
|
||||
, _connected(0) {
|
||||
addUpdateHandler([&](const String & originId) { reconfigureAP(); }, false);
|
||||
WiFi.onEvent(std::bind(&APSettingsService::WiFiEvent, this, _1));
|
||||
addUpdateHandler([this] { reconfigureAP(); }, false);
|
||||
WiFi.onEvent([this](WiFiEvent_t event, WiFiEventInfo_t info) { WiFiEvent(event); });
|
||||
}
|
||||
|
||||
void APSettingsService::begin() {
|
||||
@@ -53,7 +53,7 @@ void APSettingsService::reconfigureAP() {
|
||||
|
||||
void APSettingsService::loop() {
|
||||
unsigned long currentMillis = uuid::get_uptime();
|
||||
unsigned long manageElapsed = (uint32_t)(currentMillis - _lastManaged);
|
||||
unsigned long manageElapsed = static_cast<uint32_t>(currentMillis - _lastManaged);
|
||||
if (manageElapsed >= MANAGE_NETWORK_DELAY) {
|
||||
_lastManaged = currentMillis;
|
||||
manageAP();
|
||||
@@ -76,7 +76,7 @@ void APSettingsService::manageAP() {
|
||||
|
||||
void APSettingsService::startAP() {
|
||||
WiFi.softAPConfig(_state.localIP, _state.gatewayIP, _state.subnetMask);
|
||||
esp_wifi_set_bandwidth((wifi_interface_t)ESP_IF_WIFI_AP, WIFI_BW_HT20);
|
||||
esp_wifi_set_bandwidth(static_cast<wifi_interface_t>(ESP_IF_WIFI_AP), WIFI_BW_HT20);
|
||||
WiFi.softAP(_state.ssid.c_str(), _state.password.c_str(), _state.channel, _state.ssidHidden, _state.maxClients);
|
||||
#if CONFIG_IDF_TARGET_ESP32C3
|
||||
WiFi.setTxPower(WIFI_POWER_8_5dBm); // https://www.wemos.cc/en/latest/c3/c3_mini_1_0_0.html#about-wifi
|
||||
@@ -108,14 +108,16 @@ void APSettingsService::handleDNS() {
|
||||
APNetworkStatus APSettingsService::getAPNetworkStatus() {
|
||||
WiFiMode_t currentWiFiMode = WiFi.getMode();
|
||||
bool apActive = currentWiFiMode == WIFI_AP || currentWiFiMode == WIFI_AP_STA;
|
||||
|
||||
if (apActive && _state.provisionMode != AP_MODE_ALWAYS && WiFi.status() == WL_CONNECTED) {
|
||||
return APNetworkStatus::LINGERING;
|
||||
}
|
||||
|
||||
return apActive ? APNetworkStatus::ACTIVE : APNetworkStatus::INACTIVE;
|
||||
}
|
||||
|
||||
|
||||
void APSettings::read(APSettings & settings, JsonObject root) {
|
||||
void APSettings::read(const APSettings & settings, JsonObject root) {
|
||||
root["provision_mode"] = settings.provisionMode;
|
||||
root["ssid"] = settings.ssid;
|
||||
root["password"] = settings.password;
|
||||
@@ -129,7 +131,8 @@ void APSettings::read(APSettings & settings, JsonObject root) {
|
||||
|
||||
StateUpdateResult APSettings::update(JsonObject root, APSettings & settings) {
|
||||
APSettings newSettings = {};
|
||||
newSettings.provisionMode = root["provision_mode"] | FACTORY_AP_PROVISION_MODE;
|
||||
newSettings.provisionMode = static_cast<uint8_t>(root["provision_mode"] | FACTORY_AP_PROVISION_MODE);
|
||||
|
||||
switch (settings.provisionMode) {
|
||||
case AP_MODE_ALWAYS:
|
||||
case AP_MODE_DISCONNECTED:
|
||||
@@ -138,11 +141,12 @@ StateUpdateResult APSettings::update(JsonObject root, APSettings & settings) {
|
||||
default:
|
||||
newSettings.provisionMode = AP_MODE_ALWAYS;
|
||||
}
|
||||
|
||||
newSettings.ssid = root["ssid"] | FACTORY_AP_SSID;
|
||||
newSettings.password = root["password"] | FACTORY_AP_PASSWORD;
|
||||
newSettings.channel = root["channel"] | FACTORY_AP_CHANNEL;
|
||||
newSettings.channel = static_cast<uint8_t>(root["channel"] | FACTORY_AP_CHANNEL);
|
||||
newSettings.ssidHidden = root["ssid_hidden"] | FACTORY_AP_SSID_HIDDEN;
|
||||
newSettings.maxClients = root["max_clients"] | FACTORY_AP_MAX_CLIENTS;
|
||||
newSettings.maxClients = static_cast<uint8_t>(root["max_clients"] | FACTORY_AP_MAX_CLIENTS);
|
||||
|
||||
JsonUtils::readIP(root, "local_ip", newSettings.localIP, FACTORY_AP_LOCAL_IP);
|
||||
JsonUtils::readIP(root, "gateway_ip", newSettings.gatewayIP, FACTORY_AP_GATEWAY_IP);
|
||||
@@ -151,6 +155,7 @@ StateUpdateResult APSettings::update(JsonObject root, APSettings & settings) {
|
||||
if (newSettings == settings) {
|
||||
return StateUpdateResult::UNCHANGED;
|
||||
}
|
||||
|
||||
settings = newSettings;
|
||||
return StateUpdateResult::CHANGED;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#ifndef APSettingsConfig_h
|
||||
#define APSettingsConfig_h
|
||||
|
||||
#include <HttpEndpoint.h>
|
||||
#include <FSPersistence.h>
|
||||
#include <JsonUtils.h>
|
||||
#include "HttpEndpoint.h"
|
||||
#include "FSPersistence.h"
|
||||
#include "JsonUtils.h"
|
||||
|
||||
#include <DNSServer.h>
|
||||
#include <IPAddress.h>
|
||||
@@ -75,7 +75,7 @@ class APSettings {
|
||||
&& subnetMask == settings.subnetMask;
|
||||
}
|
||||
|
||||
static void read(APSettings & settings, JsonObject root);
|
||||
static void read(const APSettings & settings, JsonObject root);
|
||||
static StateUpdateResult update(JsonObject root, APSettings & settings);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
#include <APStatus.h>
|
||||
|
||||
using namespace std::placeholders; // for `_1` etc
|
||||
#include "APStatus.h"
|
||||
|
||||
APStatus::APStatus(AsyncWebServer * server, SecurityManager * securityManager, APSettingsService * apSettingsService)
|
||||
: _apSettingsService(apSettingsService) {
|
||||
server->on(AP_STATUS_SERVICE_PATH,
|
||||
HTTP_GET,
|
||||
securityManager->wrapRequest(std::bind(&APStatus::apStatus, this, _1), AuthenticationPredicates::IS_AUTHENTICATED));
|
||||
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { apStatus(request); }, AuthenticationPredicates::IS_AUTHENTICATED));
|
||||
}
|
||||
|
||||
void APStatus::apStatus(AsyncWebServerRequest * request) {
|
||||
AsyncJsonResponse * response = new AsyncJsonResponse(false);
|
||||
auto * response = new AsyncJsonResponse(false);
|
||||
JsonObject root = response->getRoot();
|
||||
|
||||
root["status"] = _apSettingsService->getAPNetworkStatus();
|
||||
|
||||
@@ -7,8 +7,9 @@
|
||||
#include <ArduinoJson.h>
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <IPAddress.h>
|
||||
#include <SecurityManager.h>
|
||||
#include <APSettingsService.h>
|
||||
|
||||
#include "SecurityManager.h"
|
||||
#include "APSettingsService.h"
|
||||
|
||||
#define AP_STATUS_SERVICE_PATH "/rest/apStatus"
|
||||
|
||||
|
||||
@@ -1,47 +1,27 @@
|
||||
#include "ArduinoJsonJWT.h"
|
||||
|
||||
#include <array>
|
||||
|
||||
ArduinoJsonJWT::ArduinoJsonJWT(String secret)
|
||||
: _secret(secret) {
|
||||
: _secret(std::move(secret)) {
|
||||
}
|
||||
|
||||
void ArduinoJsonJWT::setSecret(String secret) {
|
||||
_secret = secret;
|
||||
_secret = std::move(secret);
|
||||
}
|
||||
|
||||
String ArduinoJsonJWT::getSecret() {
|
||||
return _secret;
|
||||
}
|
||||
|
||||
/*
|
||||
* ESP32 uses mbedtls, ESP2866 uses bearssl.
|
||||
*
|
||||
* Both come with decent HMAC implementations supporting sha256, as well as others.
|
||||
*
|
||||
* No need to pull in additional crypto libraries - lets use what we already have.
|
||||
*/
|
||||
String ArduinoJsonJWT::sign(String & payload) {
|
||||
unsigned char hmacResult[32];
|
||||
{
|
||||
mbedtls_md_context_t ctx;
|
||||
mbedtls_md_type_t md_type = MBEDTLS_MD_SHA256;
|
||||
mbedtls_md_init(&ctx);
|
||||
mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(md_type), 1);
|
||||
mbedtls_md_hmac_starts(&ctx, (unsigned char *)_secret.c_str(), _secret.length());
|
||||
mbedtls_md_hmac_update(&ctx, (unsigned char *)payload.c_str(), payload.length());
|
||||
mbedtls_md_hmac_finish(&ctx, hmacResult);
|
||||
mbedtls_md_free(&ctx);
|
||||
}
|
||||
return encode((char *)hmacResult, 32);
|
||||
}
|
||||
|
||||
String ArduinoJsonJWT::buildJWT(JsonObject payload) {
|
||||
// serialize, then encode payload
|
||||
String jwt;
|
||||
serializeJson(payload, jwt);
|
||||
jwt = encode(jwt.c_str(), jwt.length());
|
||||
jwt = encode(jwt.c_str(), static_cast<int>(jwt.length()));
|
||||
|
||||
// add the header to payload
|
||||
jwt = JWT_HEADER + '.' + jwt;
|
||||
jwt = getJWTHeader() + '.' + jwt;
|
||||
|
||||
// add signature
|
||||
jwt += '.' + sign(jwt);
|
||||
@@ -53,65 +33,88 @@ void ArduinoJsonJWT::parseJWT(String jwt, JsonDocument & jsonDocument) {
|
||||
// clear json document before we begin, jsonDocument wil be null on failure
|
||||
jsonDocument.clear();
|
||||
|
||||
const String & jwt_header = getJWTHeader();
|
||||
const unsigned int jwt_header_size = jwt_header.length();
|
||||
|
||||
// must have the correct header and delimiter
|
||||
if (!jwt.startsWith(JWT_HEADER) || jwt.indexOf('.') != JWT_HEADER_SIZE) {
|
||||
if (!jwt.startsWith(jwt_header) || jwt.indexOf('.') != static_cast<int>(jwt_header_size)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// check there is a signature delimieter
|
||||
int signatureDelimiterIndex = jwt.lastIndexOf('.');
|
||||
if (signatureDelimiterIndex == JWT_HEADER_SIZE) {
|
||||
const int signatureDelimiterIndex = jwt.lastIndexOf('.');
|
||||
if (signatureDelimiterIndex == static_cast<int>(jwt_header_size)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// check the signature is valid
|
||||
String signature = jwt.substring(signatureDelimiterIndex + 1);
|
||||
jwt = jwt.substring(0, signatureDelimiterIndex);
|
||||
const String signature = jwt.substring(static_cast<unsigned int>(signatureDelimiterIndex) + 1);
|
||||
jwt = jwt.substring(0, static_cast<unsigned int>(signatureDelimiterIndex));
|
||||
if (sign(jwt) != signature) {
|
||||
return;
|
||||
}
|
||||
|
||||
// decode payload
|
||||
jwt = jwt.substring(JWT_HEADER_SIZE + 1);
|
||||
jwt = jwt.substring(jwt_header_size + 1);
|
||||
jwt = decode(jwt);
|
||||
|
||||
// parse payload, clearing json document after failure
|
||||
DeserializationError error = deserializeJson(jsonDocument, jwt);
|
||||
const DeserializationError error = deserializeJson(jsonDocument, jwt);
|
||||
if (error != DeserializationError::Ok || !jsonDocument.is<JsonObject>()) {
|
||||
jsonDocument.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ESP32 uses mbedtls, ESP2866 uses bearssl.
|
||||
*
|
||||
* Both come with decent HMAC implementations supporting sha256, as well as others.
|
||||
*
|
||||
* No need to pull in additional crypto libraries - lets use what we already have.
|
||||
*/
|
||||
String ArduinoJsonJWT::sign(String & payload) {
|
||||
std::array<unsigned char, 32> hmacResult{};
|
||||
{
|
||||
mbedtls_md_context_t ctx;
|
||||
mbedtls_md_type_t md_type = MBEDTLS_MD_SHA256;
|
||||
mbedtls_md_init(&ctx);
|
||||
mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(md_type), 1);
|
||||
mbedtls_md_hmac_starts(&ctx, reinterpret_cast<const unsigned char *>(_secret.c_str()), _secret.length());
|
||||
mbedtls_md_hmac_update(&ctx, reinterpret_cast<const unsigned char *>(payload.c_str()), payload.length());
|
||||
mbedtls_md_hmac_finish(&ctx, hmacResult.data());
|
||||
mbedtls_md_free(&ctx);
|
||||
}
|
||||
return encode(reinterpret_cast<const char *>(hmacResult.data()), hmacResult.size());
|
||||
}
|
||||
|
||||
String ArduinoJsonJWT::encode(const char * cstr, int inputLen) {
|
||||
// prepare encoder
|
||||
base64_encodestate _state;
|
||||
base64_init_encodestate(&_state);
|
||||
size_t encodedLength = base64_encode_expected_len(inputLen) + 1;
|
||||
// prepare buffer of correct length, returning an empty string on failure
|
||||
char * buffer = (char *)malloc(encodedLength * sizeof(char));
|
||||
if (buffer == nullptr) {
|
||||
return "";
|
||||
}
|
||||
|
||||
// prepare buffer of correct length
|
||||
const auto bufferLength = static_cast<std::size_t>(base64_encode_expected_len(inputLen)) + 1;
|
||||
auto * buffer = new char[bufferLength];
|
||||
|
||||
// encode to buffer
|
||||
int len = base64_encode_block(cstr, inputLen, &buffer[0], &_state);
|
||||
len += base64_encode_blockend(&buffer[len], &_state);
|
||||
buffer[len] = 0;
|
||||
buffer[len] = '\0';
|
||||
|
||||
// convert to arduino string, freeing buffer
|
||||
String value = String(buffer);
|
||||
free(buffer);
|
||||
auto result = String(buffer);
|
||||
delete[] buffer;
|
||||
buffer = nullptr;
|
||||
|
||||
// remove padding and convert to URL safe form
|
||||
while (value.length() > 0 && value.charAt(value.length() - 1) == '=') {
|
||||
value.remove(value.length() - 1);
|
||||
while (result.length() > 0 && result.charAt(result.length() - 1) == '=') {
|
||||
result.remove(result.length() - 1);
|
||||
}
|
||||
value.replace('+', '-');
|
||||
value.replace('/', '_');
|
||||
result.replace('+', '-');
|
||||
result.replace('/', '_');
|
||||
|
||||
// return as string
|
||||
return value;
|
||||
return result;
|
||||
}
|
||||
|
||||
String ArduinoJsonJWT::decode(String value) {
|
||||
@@ -120,12 +123,18 @@ String ArduinoJsonJWT::decode(String value) {
|
||||
value.replace('_', '/');
|
||||
|
||||
// prepare buffer of correct length
|
||||
char buffer[base64_decode_expected_len(value.length()) + 1];
|
||||
const auto bufferLength = static_cast<std::size_t>(base64_decode_expected_len(value.length()) + 1);
|
||||
auto * buffer = new char[bufferLength];
|
||||
|
||||
// decode
|
||||
int len = base64_decode_chars(value.c_str(), value.length(), &buffer[0]);
|
||||
buffer[len] = 0;
|
||||
const int len = base64_decode_chars(value.c_str(), static_cast<int>(value.length()), &buffer[0]);
|
||||
buffer[len] = '\0';
|
||||
|
||||
// convert to arduino string, freeing buffer
|
||||
auto result = String(buffer);
|
||||
delete[] buffer;
|
||||
buffer = nullptr;
|
||||
|
||||
// return as string
|
||||
return String(buffer);
|
||||
return result;
|
||||
}
|
||||
@@ -3,30 +3,33 @@
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
#include <libb64/cdecode.h>
|
||||
#include <libb64/cencode.h>
|
||||
#include <mbedtls/md.h>
|
||||
|
||||
class ArduinoJsonJWT {
|
||||
private:
|
||||
String _secret;
|
||||
|
||||
const String JWT_HEADER = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9";
|
||||
const int JWT_HEADER_SIZE = JWT_HEADER.length();
|
||||
|
||||
String sign(String & value);
|
||||
|
||||
static String encode(const char * cstr, int len);
|
||||
static String decode(String value);
|
||||
|
||||
public:
|
||||
ArduinoJsonJWT(String secret);
|
||||
explicit ArduinoJsonJWT(String secret);
|
||||
|
||||
void setSecret(String secret);
|
||||
String getSecret();
|
||||
|
||||
String buildJWT(JsonObject payload);
|
||||
void parseJWT(String jwt, JsonDocument & jsonDocument);
|
||||
|
||||
private:
|
||||
String _secret;
|
||||
|
||||
String sign(String & value);
|
||||
|
||||
static String encode(const char * cstr, int len);
|
||||
static String decode(String value);
|
||||
|
||||
static const String & getJWTHeader() {
|
||||
static const String JWT_HEADER = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9";
|
||||
return JWT_HEADER;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,11 +1,9 @@
|
||||
#include <AuthenticationService.h>
|
||||
|
||||
using namespace std::placeholders; // for `_1` etc
|
||||
#include "AuthenticationService.h"
|
||||
|
||||
AuthenticationService::AuthenticationService(AsyncWebServer * server, SecurityManager * securityManager)
|
||||
: _securityManager(securityManager)
|
||||
, _signInHandler(SIGN_IN_PATH, std::bind(&AuthenticationService::signIn, this, _1, _2)) {
|
||||
server->on(VERIFY_AUTHORIZATION_PATH, HTTP_GET, std::bind(&AuthenticationService::verifyAuthorization, this, _1));
|
||||
, _signInHandler(SIGN_IN_PATH, [this](AsyncWebServerRequest * request, JsonVariant json) { signIn(request, json); }) {
|
||||
server->on(VERIFY_AUTHORIZATION_PATH, HTTP_GET, [this](AsyncWebServerRequest * request) { verifyAuthorization(request); });
|
||||
_signInHandler.setMethod(HTTP_POST);
|
||||
_signInHandler.setMaxContentLength(MAX_AUTHENTICATION_SIZE);
|
||||
server->addHandler(&_signInHandler);
|
||||
@@ -30,7 +28,7 @@ void AuthenticationService::signIn(AsyncWebServerRequest * request, JsonVariant
|
||||
Authentication authentication = _securityManager->authenticate(username, password);
|
||||
if (authentication.authenticated) {
|
||||
User * user = authentication.user;
|
||||
AsyncJsonResponse * response = new AsyncJsonResponse(false);
|
||||
auto * response = new AsyncJsonResponse(false);
|
||||
JsonObject jsonObject = response->getRoot();
|
||||
jsonObject["access_token"] = _securityManager->generateJWT(user);
|
||||
response->setLength();
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
#ifndef AuthenticationService_H_
|
||||
#define AuthenticationService_H_
|
||||
|
||||
#include <Features.h>
|
||||
#include "Features.h"
|
||||
#include "SecurityManager.h"
|
||||
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <SecurityManager.h>
|
||||
|
||||
#define VERIFY_AUTHORIZATION_PATH "/rest/verifyAuthorization"
|
||||
#define SIGN_IN_PATH "/rest/signIn"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include <ESP8266React.h>
|
||||
#include "ESP8266React.h"
|
||||
|
||||
#include <WWWData.h>
|
||||
#include "WWWData.h"
|
||||
|
||||
ESP8266React::ESP8266React(AsyncWebServer * server, FS * fs)
|
||||
: _securitySettingsService(server, fs)
|
||||
@@ -27,7 +27,7 @@ ESP8266React::ESP8266React(AsyncWebServer * server, FS * fs)
|
||||
static char last_modified[50];
|
||||
sprintf(last_modified, "%s %s CET", __DATE__, __TIME__);
|
||||
|
||||
WWWData::registerRoutes([server, this](const String & uri, const String & contentType, const uint8_t * content, size_t len, const String & hash) {
|
||||
WWWData::registerRoutes([server](const String & uri, const String & contentType, const uint8_t * content, size_t len, const String & hash) {
|
||||
ArRequestHandlerFunction requestHandler = [contentType, content, len, hash](AsyncWebServerRequest * request) {
|
||||
// Check if the client already has the same version and respond with a 304 (Not modified)
|
||||
if (request->header("If-Modified-Since").indexOf(last_modified) > 0) {
|
||||
@@ -66,12 +66,13 @@ ESP8266React::ESP8266React(AsyncWebServer * server, FS * fs)
|
||||
void ESP8266React::begin() {
|
||||
_networkSettingsService.begin();
|
||||
_networkSettingsService.read([&](NetworkSettings & networkSettings) {
|
||||
DefaultHeaders & defaultHeaders = DefaultHeaders::Instance();
|
||||
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");
|
||||
defaultHeaders.addHeader("Access-Control-Allow-Origin", networkSettings.CORSOrigin);
|
||||
defaultHeaders.addHeader("Access-Control-Allow-Headers", "Accept, Content-Type, Authorization");
|
||||
defaultHeaders.addHeader("Access-Control-Allow-Credentials", "true");
|
||||
}
|
||||
DefaultHeaders::Instance().addHeader("Server", networkSettings.hostname);
|
||||
defaultHeaders.addHeader("Server", networkSettings.hostname);
|
||||
});
|
||||
_apSettingsService.begin();
|
||||
_ntpSettingsService.begin();
|
||||
|
||||
@@ -1,28 +1,27 @@
|
||||
#ifndef ESP8266React_h
|
||||
#define ESP8266React_h
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "APSettingsService.h"
|
||||
#include "APStatus.h"
|
||||
#include "AuthenticationService.h"
|
||||
#include "FactoryResetService.h"
|
||||
#include "MqttSettingsService.h"
|
||||
#include "MqttStatus.h"
|
||||
#include "NTPSettingsService.h"
|
||||
#include "NTPStatus.h"
|
||||
#include "OTASettingsService.h"
|
||||
#include "UploadFileService.h"
|
||||
#include "RestartService.h"
|
||||
#include "SecuritySettingsService.h"
|
||||
#include "SystemStatus.h"
|
||||
#include "WiFiScanner.h"
|
||||
#include "NetworkSettingsService.h"
|
||||
#include "NetworkStatus.h"
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <AsyncTCP.h>
|
||||
#include <WiFi.h>
|
||||
|
||||
#include <APSettingsService.h>
|
||||
#include <APStatus.h>
|
||||
#include <AuthenticationService.h>
|
||||
#include <FactoryResetService.h>
|
||||
#include <MqttSettingsService.h>
|
||||
#include <MqttStatus.h>
|
||||
#include <NTPSettingsService.h>
|
||||
#include <NTPStatus.h>
|
||||
#include <OTASettingsService.h>
|
||||
#include <UploadFileService.h>
|
||||
#include <RestartService.h>
|
||||
#include <SecuritySettingsService.h>
|
||||
#include <SystemStatus.h>
|
||||
#include <WiFiScanner.h>
|
||||
#include <NetworkSettingsService.h>
|
||||
#include <NetworkStatus.h>
|
||||
|
||||
class ESP8266React {
|
||||
public:
|
||||
ESP8266React(AsyncWebServer * server, FS * fs);
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
|
||||
class ESPUtils {
|
||||
public:
|
||||
static String defaultDeviceValue(String prefix = "") {
|
||||
return prefix + String((uint32_t)ESP.getEfuseMac(), HEX);
|
||||
static String defaultDeviceValue(const String & prefix = "") {
|
||||
return prefix + String(static_cast<uint32_t>(ESP.getEfuseMac()), HEX);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#ifndef FSPersistence_h
|
||||
#define FSPersistence_h
|
||||
|
||||
#include <StatefulService.h>
|
||||
#include <FS.h>
|
||||
#include "StatefulService.h"
|
||||
#include "FS.h"
|
||||
|
||||
template <class T>
|
||||
class FSPersistence {
|
||||
@@ -47,8 +47,8 @@ class FSPersistence {
|
||||
// make directories if required, for new IDF4.2 & LittleFS
|
||||
String path(_filePath);
|
||||
int index = 0;
|
||||
while ((index = path.indexOf('/', index + 1)) != -1) {
|
||||
String segment = path.substring(0, index);
|
||||
while ((index = path.indexOf('/', static_cast<unsigned int>(index) + 1)) != -1) {
|
||||
String segment = path.substring(0, static_cast<unsigned int>(index));
|
||||
if (!_fs->exists(segment)) {
|
||||
_fs->mkdir(segment);
|
||||
}
|
||||
@@ -80,7 +80,7 @@ class FSPersistence {
|
||||
|
||||
void enableUpdateHandler() {
|
||||
if (!_updateHandlerId) {
|
||||
_updateHandlerId = _statefulService->addUpdateHandler([&] { writeToFS(); });
|
||||
_updateHandlerId = _statefulService->addUpdateHandler([this] { writeToFS(); });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
#include <FactoryResetService.h>
|
||||
|
||||
using namespace std::placeholders;
|
||||
#include "FactoryResetService.h"
|
||||
|
||||
FactoryResetService::FactoryResetService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
|
||||
: fs(fs) {
|
||||
server->on(FACTORY_RESET_SERVICE_PATH,
|
||||
HTTP_POST,
|
||||
securityManager->wrapRequest(std::bind(&FactoryResetService::handleRequest, this, _1), AuthenticationPredicates::IS_ADMIN));
|
||||
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { handleRequest(request); }, AuthenticationPredicates::IS_ADMIN));
|
||||
}
|
||||
|
||||
void FactoryResetService::handleRequest(AsyncWebServerRequest * request) {
|
||||
request->onDisconnect(std::bind(&FactoryResetService::factoryReset, this));
|
||||
request->onDisconnect([this]() { factoryReset(); });
|
||||
request->send(200);
|
||||
}
|
||||
|
||||
@@ -21,7 +19,7 @@ void FactoryResetService::factoryReset() {
|
||||
// TODO To replaced with fs.rmdir(FS_CONFIG_DIRECTORY) now we're using IDF 4.2
|
||||
File root = fs->open(FS_CONFIG_DIRECTORY);
|
||||
File file;
|
||||
while (file = root.openNextFile()) {
|
||||
while ((file = root.openNextFile())) {
|
||||
String path = file.path();
|
||||
file.close();
|
||||
fs->remove(path);
|
||||
|
||||
@@ -3,22 +3,22 @@
|
||||
|
||||
#include <WiFi.h>
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <SecurityManager.h>
|
||||
#include <RestartService.h>
|
||||
#include <FS.h>
|
||||
|
||||
#include "SecurityManager.h"
|
||||
#include "RestartService.h"
|
||||
|
||||
#define FS_CONFIG_DIRECTORY "/config"
|
||||
#define FACTORY_RESET_SERVICE_PATH "/rest/factoryReset"
|
||||
|
||||
class FactoryResetService {
|
||||
FS * fs;
|
||||
|
||||
public:
|
||||
FactoryResetService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager);
|
||||
|
||||
void factoryReset();
|
||||
|
||||
private:
|
||||
FS * fs;
|
||||
void handleRequest(AsyncWebServerRequest * request);
|
||||
};
|
||||
|
||||
|
||||
@@ -2,15 +2,13 @@
|
||||
#define HttpEndpoint_h
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include <ESPAsyncWebServer.h>
|
||||
|
||||
#include <SecurityManager.h>
|
||||
#include <StatefulService.h>
|
||||
#include "SecurityManager.h"
|
||||
#include "StatefulService.h"
|
||||
|
||||
#define HTTP_ENDPOINT_ORIGIN_ID "http"
|
||||
|
||||
using namespace std::placeholders; // for `_1` etc
|
||||
#define HTTPS_ENDPOINT_ORIGIN_ID "https"
|
||||
|
||||
template <class T>
|
||||
class HttpEndpoint {
|
||||
@@ -19,8 +17,7 @@ class HttpEndpoint {
|
||||
JsonStateUpdater<T> _stateUpdater;
|
||||
StatefulService<T> * _statefulService;
|
||||
|
||||
AsyncCallbackWebHandler * GEThandler;
|
||||
AsyncCallbackJsonWebHandler * POSThandler;
|
||||
AsyncCallbackJsonWebHandler * handler;
|
||||
|
||||
public:
|
||||
HttpEndpoint(JsonStateReader<T> stateReader,
|
||||
@@ -33,12 +30,12 @@ class HttpEndpoint {
|
||||
: _stateReader(stateReader)
|
||||
, _stateUpdater(stateUpdater)
|
||||
, _statefulService(statefulService) {
|
||||
// Create the GET and POST endpoints
|
||||
POSThandler = new AsyncCallbackJsonWebHandler(servicePath,
|
||||
// Create hander for both GET and POST endpoints
|
||||
handler = new AsyncCallbackJsonWebHandler(servicePath,
|
||||
securityManager->wrapCallback([this](AsyncWebServerRequest * request,
|
||||
JsonVariant json) { handleRequest(request, json); },
|
||||
authenticationPredicate));
|
||||
server->addHandler(POSThandler);
|
||||
server->addHandler(handler);
|
||||
}
|
||||
|
||||
protected:
|
||||
@@ -66,7 +63,7 @@ class HttpEndpoint {
|
||||
}
|
||||
}
|
||||
|
||||
AsyncJsonResponse * response = new AsyncJsonResponse(false);
|
||||
auto * response = new AsyncJsonResponse(false);
|
||||
JsonObject jsonObject = response->getRoot().to<JsonObject>();
|
||||
_statefulService->read(jsonObject, _stateReader);
|
||||
response->setLength();
|
||||
|
||||
@@ -3,15 +3,19 @@
|
||||
|
||||
#include <IPAddress.h>
|
||||
|
||||
const IPAddress IP_NOT_SET = IPAddress(INADDR_NONE);
|
||||
|
||||
class IPUtils {
|
||||
public:
|
||||
static bool isSet(const IPAddress & ip) {
|
||||
return ip != IP_NOT_SET;
|
||||
return ip != getNotSetIP();
|
||||
}
|
||||
static bool isNotSet(const IPAddress & ip) {
|
||||
return ip == IP_NOT_SET;
|
||||
return ip == getNotSetIP();
|
||||
}
|
||||
|
||||
private:
|
||||
static const IPAddress & getNotSetIP() {
|
||||
static const IPAddress IP_NOT_SET = IPAddress(INADDR_NONE);
|
||||
return IP_NOT_SET;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
#define JsonUtils_h
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <IPAddress.h>
|
||||
#include <IPUtils.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <IPAddress.h>
|
||||
|
||||
#include "IPUtils.h"
|
||||
|
||||
class JsonUtils {
|
||||
public:
|
||||
|
||||
@@ -1,22 +1,23 @@
|
||||
#include <MqttSettingsService.h>
|
||||
|
||||
#include "MqttSettingsService.h"
|
||||
#include "../../src/emsesp_stub.hpp"
|
||||
|
||||
using namespace std::placeholders; // for `_1` etc
|
||||
|
||||
/**
|
||||
* Retains a copy of the cstr provided in the pointer provided using dynamic allocation.
|
||||
*
|
||||
* Frees the pointer before allocation and leaves it as nullptr if cstr == nullptr.
|
||||
*/
|
||||
static char * retainCstr(const char * cstr, char ** ptr) {
|
||||
if (ptr == nullptr || *ptr == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// free up previously retained value if exists
|
||||
free(*ptr);
|
||||
delete[] *ptr;
|
||||
*ptr = nullptr;
|
||||
|
||||
// dynamically allocate and copy cstr (if non null)
|
||||
if (cstr != nullptr) {
|
||||
*ptr = (char *)malloc(strlen(cstr) + 1);
|
||||
*ptr = new char[strlen(cstr) + 1];
|
||||
strcpy(*ptr, cstr);
|
||||
}
|
||||
|
||||
@@ -31,15 +32,22 @@ MqttSettingsService::MqttSettingsService(AsyncWebServer * server, FS * fs, Secur
|
||||
, _retainedClientId(nullptr)
|
||||
, _retainedUsername(nullptr)
|
||||
, _retainedPassword(nullptr)
|
||||
, _retainedRootCA(nullptr)
|
||||
, _reconfigureMqtt(false)
|
||||
, _disconnectedAt(0)
|
||||
, _disconnectReason(espMqttClientTypes::DisconnectReason::TCP_DISCONNECTED)
|
||||
, _mqttClient(nullptr) {
|
||||
WiFi.onEvent(std::bind(&MqttSettingsService::WiFiEvent, this, _1, _2));
|
||||
addUpdateHandler([&] { onConfigUpdated(); }, false);
|
||||
WiFi.onEvent([this](WiFiEvent_t event, WiFiEventInfo_t info) { WiFiEvent(event); });
|
||||
addUpdateHandler([this]() { onConfigUpdated(); }, false);
|
||||
}
|
||||
|
||||
MqttSettingsService::~MqttSettingsService() {
|
||||
delete _mqttClient;
|
||||
retainCstr(nullptr, &_retainedHost);
|
||||
retainCstr(nullptr, &_retainedClientId);
|
||||
retainCstr(nullptr, &_retainedUsername);
|
||||
retainCstr(nullptr, &_retainedPassword);
|
||||
retainCstr(nullptr, &_retainedRootCA);
|
||||
}
|
||||
|
||||
void MqttSettingsService::begin() {
|
||||
@@ -55,32 +63,41 @@ void MqttSettingsService::startClient() {
|
||||
return;
|
||||
}
|
||||
delete _mqttClient;
|
||||
_mqttClient = nullptr;
|
||||
}
|
||||
#if CONFIG_IDF_TARGET_ESP32S3
|
||||
if (_state.enableTLS) {
|
||||
isSecure = true;
|
||||
_mqttClient = static_cast<MqttClient *>(new espMqttClientSecure(espMqttClientTypes::UseInternalTask::NO));
|
||||
_mqttClient = new espMqttClientSecure(espMqttClientTypes::UseInternalTask::NO);
|
||||
if (_state.rootCA == "insecure") {
|
||||
static_cast<espMqttClientSecure *>(_mqttClient)->setInsecure();
|
||||
} else {
|
||||
String certificate = "-----BEGIN CERTIFICATE-----\n" + _state.rootCA + "\n-----END CERTIFICATE-----\n";
|
||||
static_cast<espMqttClientSecure *>(_mqttClient)->setCACert(retainCstr(certificate.c_str(), &_retainedRootCA));
|
||||
}
|
||||
static_cast<espMqttClientSecure *>(_mqttClient)->onConnect(std::bind(&MqttSettingsService::onMqttConnect, this, _1));
|
||||
static_cast<espMqttClientSecure *>(_mqttClient)->onDisconnect(std::bind(&MqttSettingsService::onMqttDisconnect, this, _1));
|
||||
static_cast<espMqttClientSecure *>(_mqttClient)->onMessage(std::bind(&MqttSettingsService::onMqttMessage, this, _1, _2, _3, _4, _5, _6));
|
||||
static_cast<espMqttClientSecure *>(_mqttClient)->onConnect([this](bool sessionPresent) { onMqttConnect(sessionPresent); });
|
||||
static_cast<espMqttClientSecure *>(_mqttClient)->onDisconnect([this](espMqttClientTypes::DisconnectReason reason) { onMqttDisconnect(reason); });
|
||||
static_cast<espMqttClientSecure *>(_mqttClient)
|
||||
->onMessage(
|
||||
[this](const espMqttClientTypes::MessageProperties & properties, const char * topic, const uint8_t * payload, size_t len, size_t index, size_t total) {
|
||||
onMqttMessage(properties, topic, payload, len, index, total);
|
||||
});
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
isSecure = false;
|
||||
_mqttClient = static_cast<MqttClient *>(new espMqttClient(espMqttClientTypes::UseInternalTask::NO));
|
||||
static_cast<espMqttClient *>(_mqttClient)->onConnect(std::bind(&MqttSettingsService::onMqttConnect, this, _1));
|
||||
static_cast<espMqttClient *>(_mqttClient)->onDisconnect(std::bind(&MqttSettingsService::onMqttDisconnect, this, _1));
|
||||
static_cast<espMqttClient *>(_mqttClient)->onMessage(std::bind(&MqttSettingsService::onMqttMessage, this, _1, _2, _3, _4, _5, _6));
|
||||
_mqttClient = new espMqttClient(espMqttClientTypes::UseInternalTask::NO);
|
||||
static_cast<espMqttClient *>(_mqttClient)->onConnect([this](bool sessionPresent) { onMqttConnect(sessionPresent); });
|
||||
static_cast<espMqttClient *>(_mqttClient)->onDisconnect([this](espMqttClientTypes::DisconnectReason reason) { onMqttDisconnect(reason); });
|
||||
static_cast<espMqttClient *>(_mqttClient)
|
||||
->onMessage(
|
||||
[this](const espMqttClientTypes::MessageProperties & properties, const char * topic, const uint8_t * payload, size_t len, size_t index, size_t total) {
|
||||
onMqttMessage(properties, topic, payload, len, index, total);
|
||||
});
|
||||
}
|
||||
|
||||
void MqttSettingsService::loop() {
|
||||
if (_reconfigureMqtt || (_disconnectedAt && (uint32_t)(uuid::get_uptime() - _disconnectedAt) >= MQTT_RECONNECTION_DELAY)) {
|
||||
if (_reconfigureMqtt || (_disconnectedAt && static_cast<uint32_t>(uuid::get_uptime() - _disconnectedAt) >= MQTT_RECONNECTION_DELAY)) {
|
||||
// reconfigure MQTT client
|
||||
_disconnectedAt = configureMqtt() ? 0 : uuid::get_uptime();
|
||||
_reconfigureMqtt = false;
|
||||
@@ -116,6 +133,9 @@ void MqttSettingsService::onMqttMessage(const espMqttClientTypes::MessagePropert
|
||||
size_t len,
|
||||
size_t index,
|
||||
size_t total) {
|
||||
(void)properties;
|
||||
(void)index;
|
||||
(void)total;
|
||||
emsesp::EMSESP::mqtt_.on_message(topic, payload, len);
|
||||
}
|
||||
|
||||
@@ -128,6 +148,7 @@ MqttClient * MqttSettingsService::getMqttClient() {
|
||||
}
|
||||
|
||||
void MqttSettingsService::onMqttConnect(bool sessionPresent) {
|
||||
(void)sessionPresent;
|
||||
// _disconnectedAt = 0;
|
||||
emsesp::EMSESP::mqtt_.on_connect();
|
||||
// emsesp::EMSESP::logger().info("Connected to MQTT, %s", (sessionPresent) ? ("with persistent session") : ("without persistent session"));
|
||||
@@ -149,7 +170,7 @@ void MqttSettingsService::onConfigUpdated() {
|
||||
emsesp::EMSESP::mqtt_.start(); // reload EMS-ESP MQTT settings
|
||||
}
|
||||
|
||||
void MqttSettingsService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) {
|
||||
void MqttSettingsService::WiFiEvent(WiFiEvent_t event) {
|
||||
switch (event) {
|
||||
case ARDUINO_EVENT_WIFI_STA_GOT_IP:
|
||||
case ARDUINO_EVENT_ETH_GOT_IP:
|
||||
@@ -264,32 +285,32 @@ StateUpdateResult MqttSettings::update(JsonObject root, MqttSettings & settings)
|
||||
#endif
|
||||
newSettings.enabled = root["enabled"] | FACTORY_MQTT_ENABLED;
|
||||
newSettings.host = root["host"] | FACTORY_MQTT_HOST;
|
||||
newSettings.port = root["port"] | FACTORY_MQTT_PORT;
|
||||
newSettings.port = static_cast<uint16_t>(root["port"] | FACTORY_MQTT_PORT);
|
||||
newSettings.base = root["base"] | FACTORY_MQTT_BASE;
|
||||
newSettings.username = root["username"] | FACTORY_MQTT_USERNAME;
|
||||
newSettings.password = root["password"] | FACTORY_MQTT_PASSWORD;
|
||||
newSettings.clientId = root["client_id"] | FACTORY_MQTT_CLIENT_ID;
|
||||
newSettings.keepAlive = root["keep_alive"] | FACTORY_MQTT_KEEP_ALIVE;
|
||||
newSettings.keepAlive = static_cast<uint16_t>(root["keep_alive"] | FACTORY_MQTT_KEEP_ALIVE);
|
||||
newSettings.cleanSession = root["clean_session"] | FACTORY_MQTT_CLEAN_SESSION;
|
||||
newSettings.mqtt_qos = root["mqtt_qos"] | EMSESP_DEFAULT_MQTT_QOS;
|
||||
newSettings.mqtt_qos = static_cast<uint8_t>(root["mqtt_qos"] | EMSESP_DEFAULT_MQTT_QOS);
|
||||
newSettings.mqtt_retain = root["mqtt_retain"] | EMSESP_DEFAULT_MQTT_RETAIN;
|
||||
|
||||
newSettings.publish_time_boiler = root["publish_time_boiler"] | EMSESP_DEFAULT_PUBLISH_TIME;
|
||||
newSettings.publish_time_thermostat = root["publish_time_thermostat"] | EMSESP_DEFAULT_PUBLISH_TIME;
|
||||
newSettings.publish_time_solar = root["publish_time_solar"] | EMSESP_DEFAULT_PUBLISH_TIME;
|
||||
newSettings.publish_time_mixer = root["publish_time_mixer"] | EMSESP_DEFAULT_PUBLISH_TIME;
|
||||
newSettings.publish_time_other = root["publish_time_other"] | EMSESP_DEFAULT_PUBLISH_TIME;
|
||||
newSettings.publish_time_sensor = root["publish_time_sensor"] | EMSESP_DEFAULT_PUBLISH_TIME;
|
||||
newSettings.publish_time_heartbeat = root["publish_time_heartbeat"] | EMSESP_DEFAULT_PUBLISH_HEARTBEAT;
|
||||
newSettings.publish_time_boiler = static_cast<uint16_t>(root["publish_time_boiler"] | EMSESP_DEFAULT_PUBLISH_TIME);
|
||||
newSettings.publish_time_thermostat = static_cast<uint16_t>(root["publish_time_thermostat"] | EMSESP_DEFAULT_PUBLISH_TIME);
|
||||
newSettings.publish_time_solar = static_cast<uint16_t>(root["publish_time_solar"] | EMSESP_DEFAULT_PUBLISH_TIME);
|
||||
newSettings.publish_time_mixer = static_cast<uint16_t>(root["publish_time_mixer"] | EMSESP_DEFAULT_PUBLISH_TIME);
|
||||
newSettings.publish_time_other = static_cast<uint16_t>(root["publish_time_other"] | EMSESP_DEFAULT_PUBLISH_TIME);
|
||||
newSettings.publish_time_sensor = static_cast<uint16_t>(root["publish_time_sensor"] | EMSESP_DEFAULT_PUBLISH_TIME);
|
||||
newSettings.publish_time_heartbeat = static_cast<uint16_t>(root["publish_time_heartbeat"] | EMSESP_DEFAULT_PUBLISH_HEARTBEAT);
|
||||
|
||||
newSettings.ha_enabled = root["ha_enabled"] | EMSESP_DEFAULT_HA_ENABLED;
|
||||
newSettings.nested_format = root["nested_format"] | EMSESP_DEFAULT_NESTED_FORMAT;
|
||||
newSettings.nested_format = static_cast<uint8_t>(root["nested_format"] | EMSESP_DEFAULT_NESTED_FORMAT);
|
||||
newSettings.discovery_prefix = root["discovery_prefix"] | EMSESP_DEFAULT_DISCOVERY_PREFIX;
|
||||
newSettings.discovery_type = root["discovery_type"] | EMSESP_DEFAULT_DISCOVERY_TYPE;
|
||||
newSettings.discovery_type = static_cast<uint8_t>(root["discovery_type"] | EMSESP_DEFAULT_DISCOVERY_TYPE);
|
||||
newSettings.publish_single = root["publish_single"] | EMSESP_DEFAULT_PUBLISH_SINGLE;
|
||||
newSettings.publish_single2cmd = root["publish_single2cmd"] | EMSESP_DEFAULT_PUBLISH_SINGLE2CMD;
|
||||
newSettings.send_response = root["send_response"] | EMSESP_DEFAULT_SEND_RESPONSE;
|
||||
newSettings.entity_format = root["entity_format"] | EMSESP_DEFAULT_ENTITY_FORMAT;
|
||||
newSettings.entity_format = static_cast<uint8_t>(root["entity_format"] | EMSESP_DEFAULT_ENTITY_FORMAT);
|
||||
|
||||
if (newSettings.enabled != settings.enabled) {
|
||||
changed = true;
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
#ifndef MqttSettingsService_h
|
||||
#define MqttSettingsService_h
|
||||
|
||||
#include <StatefulService.h>
|
||||
#include <HttpEndpoint.h>
|
||||
#include <FSPersistence.h>
|
||||
#include "StatefulService.h"
|
||||
#include "HttpEndpoint.h"
|
||||
#include "FSPersistence.h"
|
||||
#include "ESPUtils.h"
|
||||
|
||||
#include <espMqttClient.h>
|
||||
#include <ESPUtils.h>
|
||||
|
||||
#include <uuid/common.h>
|
||||
|
||||
@@ -141,11 +142,12 @@ class MqttSettingsService : public StatefulService<MqttSettings> {
|
||||
// the MQTT client instance
|
||||
MqttClient * _mqttClient;
|
||||
|
||||
void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info);
|
||||
void WiFiEvent(WiFiEvent_t event);
|
||||
void onMqttConnect(bool sessionPresent);
|
||||
void onMqttDisconnect(espMqttClientTypes::DisconnectReason reason);
|
||||
void
|
||||
onMqttMessage(const espMqttClientTypes::MessageProperties & properties, const char * topic, const uint8_t * payload, size_t len, size_t index, size_t total);
|
||||
|
||||
bool configureMqtt();
|
||||
};
|
||||
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
#include <MqttStatus.h>
|
||||
#include "MqttStatus.h"
|
||||
|
||||
#include "../../src/emsesp_stub.hpp"
|
||||
|
||||
using namespace std::placeholders; // for `_1` etc
|
||||
|
||||
MqttStatus::MqttStatus(AsyncWebServer * server, MqttSettingsService * mqttSettingsService, SecurityManager * securityManager)
|
||||
: _mqttSettingsService(mqttSettingsService) {
|
||||
server->on(MQTT_STATUS_SERVICE_PATH,
|
||||
HTTP_GET,
|
||||
securityManager->wrapRequest(std::bind(&MqttStatus::mqttStatus, this, _1), AuthenticationPredicates::IS_AUTHENTICATED));
|
||||
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { mqttStatus(request); }, AuthenticationPredicates::IS_AUTHENTICATED));
|
||||
}
|
||||
|
||||
void MqttStatus::mqttStatus(AsyncWebServerRequest * request) {
|
||||
AsyncJsonResponse * response = new AsyncJsonResponse(false);
|
||||
auto * response = new AsyncJsonResponse(false);
|
||||
JsonObject root = response->getRoot();
|
||||
|
||||
root["enabled"] = _mqttSettingsService->isEnabled();
|
||||
|
||||
@@ -2,10 +2,11 @@
|
||||
#define MqttStatus_h
|
||||
|
||||
#include <WiFi.h>
|
||||
#include <MqttSettingsService.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <SecurityManager.h>
|
||||
|
||||
#include "MqttSettingsService.h"
|
||||
#include "SecurityManager.h"
|
||||
|
||||
#define MQTT_STATUS_SERVICE_PATH "/rest/mqttStatus"
|
||||
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
#include <NTPSettingsService.h>
|
||||
#include "NTPSettingsService.h"
|
||||
|
||||
#include "../../src/emsesp_stub.hpp"
|
||||
|
||||
using namespace std::placeholders; // for `_1` etc
|
||||
|
||||
NTPSettingsService::NTPSettingsService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
|
||||
: _httpEndpoint(NTPSettings::read, NTPSettings::update, this, server, NTP_SETTINGS_SERVICE_PATH, securityManager)
|
||||
, _fsPersistence(NTPSettings::read, NTPSettings::update, this, fs, NTP_SETTINGS_FILE)
|
||||
, _timeHandler(TIME_PATH, securityManager->wrapCallback(std::bind(&NTPSettingsService::configureTime, this, _1, _2), AuthenticationPredicates::IS_ADMIN)) {
|
||||
, _timeHandler(TIME_PATH,
|
||||
securityManager->wrapCallback([this](AsyncWebServerRequest * request, JsonVariant json) { configureTime(request, json); },
|
||||
AuthenticationPredicates::IS_ADMIN))
|
||||
, _connected(false) {
|
||||
_timeHandler.setMethod(HTTP_POST);
|
||||
_timeHandler.setMaxContentLength(MAX_TIME_SIZE);
|
||||
server->addHandler(&_timeHandler);
|
||||
|
||||
WiFi.onEvent(std::bind(&NTPSettingsService::WiFiEvent, this, _1));
|
||||
|
||||
addUpdateHandler([&] { configureNTP(); }, false);
|
||||
WiFi.onEvent([this](WiFiEvent_t event, WiFiEventInfo_t info) { WiFiEvent(event); });
|
||||
addUpdateHandler([this] { configureNTP(); }, false);
|
||||
}
|
||||
|
||||
void NTPSettingsService::begin() {
|
||||
@@ -27,9 +27,9 @@ void NTPSettingsService::WiFiEvent(WiFiEvent_t event) {
|
||||
switch (event) {
|
||||
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
|
||||
case ARDUINO_EVENT_ETH_DISCONNECTED:
|
||||
if (connected_) {
|
||||
if (_connected) {
|
||||
emsesp::EMSESP::logger().info("WiFi connection dropped, stopping NTP");
|
||||
connected_ = false;
|
||||
_connected = false;
|
||||
configureNTP();
|
||||
}
|
||||
break;
|
||||
@@ -37,7 +37,7 @@ void NTPSettingsService::WiFiEvent(WiFiEvent_t event) {
|
||||
case ARDUINO_EVENT_WIFI_STA_GOT_IP:
|
||||
case ARDUINO_EVENT_ETH_GOT_IP:
|
||||
// emsesp::EMSESP::logger().info("Got IP address, starting NTP synchronization");
|
||||
connected_ = true;
|
||||
_connected = true;
|
||||
configureNTP();
|
||||
break;
|
||||
|
||||
@@ -49,7 +49,7 @@ void NTPSettingsService::WiFiEvent(WiFiEvent_t event) {
|
||||
// https://werner.rothschopf.net/microcontroller/202103_arduino_esp32_ntp_en.htm
|
||||
void NTPSettingsService::configureNTP() {
|
||||
emsesp::EMSESP::system_.ntp_connected(false);
|
||||
if (connected_ && _state.enabled) {
|
||||
if (_connected && _state.enabled) {
|
||||
emsesp::EMSESP::logger().info("Starting NTP service");
|
||||
esp_sntp_set_sync_interval(3600000); // one hour
|
||||
esp_sntp_set_time_sync_notification_cb(ntp_received);
|
||||
@@ -63,13 +63,13 @@ void NTPSettingsService::configureNTP() {
|
||||
|
||||
void NTPSettingsService::configureTime(AsyncWebServerRequest * request, JsonVariant json) {
|
||||
if (json.is<JsonObject>()) {
|
||||
struct tm tm = {0};
|
||||
struct tm tm = {};
|
||||
String timeLocal = json["local_time"];
|
||||
char * s = strptime(timeLocal.c_str(), "%Y-%m-%dT%H:%M:%S", &tm);
|
||||
if (s != nullptr) {
|
||||
tm.tm_isdst = -1; // not set by strptime, tells mktime to determine daylightsaving
|
||||
time_t time = mktime(&tm);
|
||||
struct timeval now = {.tv_sec = time};
|
||||
struct timeval now = {.tv_sec = time, .tv_usec = {}};
|
||||
settimeofday(&now, nullptr);
|
||||
AsyncWebServerResponse * response = request->beginResponse(200);
|
||||
request->send(response);
|
||||
@@ -82,6 +82,7 @@ void NTPSettingsService::configureTime(AsyncWebServerRequest * request, JsonVari
|
||||
}
|
||||
|
||||
void NTPSettingsService::ntp_received(struct timeval * tv) {
|
||||
(void)tv;
|
||||
// emsesp::EMSESP::logger().info("NTP sync to %d sec", tv->tv_sec);
|
||||
emsesp::EMSESP::system_.ntp_connected(true);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#ifndef NTPSettingsService_h
|
||||
#define NTPSettingsService_h
|
||||
|
||||
#include <HttpEndpoint.h>
|
||||
#include <FSPersistence.h>
|
||||
#include "HttpEndpoint.h"
|
||||
#include "FSPersistence.h"
|
||||
|
||||
#include <time.h>
|
||||
#include <ctime>
|
||||
#include <esp_sntp.h>
|
||||
|
||||
#ifndef FACTORY_NTP_ENABLED
|
||||
@@ -51,8 +51,8 @@ class NTPSettingsService : public StatefulService<NTPSettings> {
|
||||
HttpEndpoint<NTPSettings> _httpEndpoint;
|
||||
FSPersistence<NTPSettings> _fsPersistence;
|
||||
AsyncCallbackJsonWebHandler _timeHandler;
|
||||
bool _connected;
|
||||
|
||||
bool connected_ = false;
|
||||
void WiFiEvent(WiFiEvent_t event);
|
||||
void configureNTP();
|
||||
void configureTime(AsyncWebServerRequest * request, JsonVariant json);
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
#include <NTPStatus.h>
|
||||
#include "NTPStatus.h"
|
||||
|
||||
#include "../../src/emsesp_stub.hpp"
|
||||
|
||||
using namespace std::placeholders; // for `_1` etc
|
||||
#include <array>
|
||||
|
||||
NTPStatus::NTPStatus(AsyncWebServer * server, SecurityManager * securityManager) {
|
||||
server->on(NTP_STATUS_SERVICE_PATH,
|
||||
HTTP_GET,
|
||||
securityManager->wrapRequest(std::bind(&NTPStatus::ntpStatus, this, _1), AuthenticationPredicates::IS_AUTHENTICATED));
|
||||
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { ntpStatus(request); }, AuthenticationPredicates::IS_AUTHENTICATED));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -15,9 +16,9 @@ NTPStatus::NTPStatus(AsyncWebServer * server, SecurityManager * securityManager)
|
||||
* Uses a 25 byte buffer, large enough to fit an ISO time string with offset.
|
||||
*/
|
||||
String formatTime(tm * time, const char * format) {
|
||||
char time_string[25];
|
||||
strftime(time_string, 25, format, time);
|
||||
return String(time_string);
|
||||
std::array<char, 25> time_string{};
|
||||
strftime(time_string.data(), time_string.size(), format, time);
|
||||
return {time_string.data()};
|
||||
}
|
||||
|
||||
String toUTCTimeString(tm * time) {
|
||||
@@ -29,14 +30,23 @@ String toLocalTimeString(tm * time) {
|
||||
}
|
||||
|
||||
void NTPStatus::ntpStatus(AsyncWebServerRequest * request) {
|
||||
AsyncJsonResponse * response = new AsyncJsonResponse(false);
|
||||
auto * response = new AsyncJsonResponse(false);
|
||||
JsonObject root = response->getRoot();
|
||||
|
||||
// grab the current instant in unix seconds
|
||||
time_t now = time(nullptr);
|
||||
|
||||
// only provide enabled/disabled status for now
|
||||
root["status"] = esp_sntp_enabled() ? emsesp::EMSESP::system_.ntp_connected() ? 2 : 1 : 0;
|
||||
root["status"] = []() {
|
||||
if (esp_sntp_enabled()) {
|
||||
if (emsesp::EMSESP::system_.ntp_connected()) {
|
||||
return 2;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}();
|
||||
|
||||
// the current time in UTC
|
||||
root["utc_time"] = toUTCTimeString(gmtime(&now));
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
#ifndef NTPStatus_h
|
||||
#define NTPStatus_h
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include <ctime>
|
||||
#include <WiFi.h>
|
||||
#include <esp_sntp.h>
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <SecurityManager.h>
|
||||
|
||||
#include "SecurityManager.h"
|
||||
|
||||
#include <uuid/common.h>
|
||||
|
||||
#define NTP_STATUS_SERVICE_PATH "/rest/ntpStatus"
|
||||
|
||||
@@ -1,16 +1,25 @@
|
||||
#include <NetworkSettingsService.h>
|
||||
#include "NetworkSettingsService.h"
|
||||
|
||||
#include "../../src/emsesp_stub.hpp"
|
||||
|
||||
using namespace std::placeholders; // for `_1` etc
|
||||
|
||||
NetworkSettingsService::NetworkSettingsService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
|
||||
: _httpEndpoint(NetworkSettings::read, NetworkSettings::update, this, server, NETWORK_SETTINGS_SERVICE_PATH, securityManager)
|
||||
, _fsPersistence(NetworkSettings::read, NetworkSettings::update, this, fs, NETWORK_SETTINGS_FILE)
|
||||
, _lastConnectionAttempt(0) {
|
||||
addUpdateHandler([&] { reconfigureWiFiConnection(); }, false);
|
||||
// wifi event callbacks
|
||||
WiFi.onEvent(std::bind(&NetworkSettingsService::WiFiEvent, this, _1, _2));
|
||||
, _lastConnectionAttempt(0)
|
||||
, _stopping(false) {
|
||||
addUpdateHandler([this]() { reconfigureWiFiConnection(); }, false);
|
||||
WiFi.onEvent([this](WiFiEvent_t event, WiFiEventInfo_t info) { WiFiEvent(event, info); });
|
||||
}
|
||||
|
||||
static bool formatBssid(const String & bssid, uint8_t (&mac)[6]) {
|
||||
uint tmp[6];
|
||||
if (bssid.isEmpty() || sscanf(bssid.c_str(), "%X:%X:%X:%X:%X:%X", &tmp[0], &tmp[1], &tmp[2], &tmp[3], &tmp[4], &tmp[5]) != 6) {
|
||||
return false;
|
||||
}
|
||||
for (uint8_t i = 0; i < 6; i++) {
|
||||
mac[i] = static_cast<uint8_t>(tmp[i]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void NetworkSettingsService::begin() {
|
||||
@@ -47,7 +56,7 @@ void NetworkSettingsService::reconfigureWiFiConnection() {
|
||||
|
||||
void NetworkSettingsService::loop() {
|
||||
unsigned long currentMillis = millis();
|
||||
if (!_lastConnectionAttempt || (uint32_t)(currentMillis - _lastConnectionAttempt) >= WIFI_RECONNECTION_DELAY) {
|
||||
if (!_lastConnectionAttempt || static_cast<uint32_t>(currentMillis - _lastConnectionAttempt) >= WIFI_RECONNECTION_DELAY) {
|
||||
_lastConnectionAttempt = currentMillis;
|
||||
manageSTA();
|
||||
}
|
||||
@@ -68,22 +77,18 @@ void NetworkSettingsService::manageSTA() {
|
||||
|
||||
// www.esp32.com/viewtopic.php?t=12055
|
||||
if (_state.bandwidth20) {
|
||||
esp_wifi_set_bandwidth((wifi_interface_t)ESP_IF_WIFI_STA, WIFI_BW_HT20);
|
||||
esp_wifi_set_bandwidth(static_cast<wifi_interface_t>(ESP_IF_WIFI_STA), WIFI_BW_HT20);
|
||||
} else {
|
||||
esp_wifi_set_bandwidth((wifi_interface_t)ESP_IF_WIFI_STA, WIFI_BW_HT40);
|
||||
esp_wifi_set_bandwidth(static_cast<wifi_interface_t>(ESP_IF_WIFI_STA), WIFI_BW_HT40);
|
||||
}
|
||||
if (_state.nosleep) {
|
||||
WiFi.setSleep(false); // turn off sleep - WIFI_PS_NONE
|
||||
}
|
||||
|
||||
// attempt to connect to the network
|
||||
uint mac[6];
|
||||
if (!_state.bssid.isEmpty() && sscanf(_state.bssid.c_str(), "%X:%X:%X:%X:%X:%X", &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]) == 6) {
|
||||
uint8_t mac1[6];
|
||||
for (uint8_t i = 0; i < 6; i++) {
|
||||
mac1[i] = (uint8_t)mac[i];
|
||||
}
|
||||
WiFi.begin(_state.ssid.c_str(), _state.password.c_str(), 0, mac1);
|
||||
uint8_t bssid[6];
|
||||
if (formatBssid(_state.bssid, bssid)) {
|
||||
WiFi.begin(_state.ssid.c_str(), _state.password.c_str(), 0, bssid);
|
||||
} else {
|
||||
WiFi.begin(_state.ssid.c_str(), _state.password.c_str());
|
||||
}
|
||||
@@ -96,7 +101,7 @@ void NetworkSettingsService::manageSTA() {
|
||||
#else
|
||||
if (_state.tx_power != 0) {
|
||||
// if not set to Auto (0) set the Tx power now
|
||||
if (!WiFi.setTxPower((wifi_power_t)_state.tx_power)) {
|
||||
if (!WiFi.setTxPower(static_cast<wifi_power_t>(_state.tx_power))) {
|
||||
emsesp::EMSESP::logger().warning("Failed to set WiFi Tx Power");
|
||||
}
|
||||
}
|
||||
@@ -173,7 +178,7 @@ void NetworkSettingsService::setWiFiPowerOnRSSI() {
|
||||
emsesp::EMSESP::logger().debug("Recommended set WiFi Tx Power (set_power %d, new power %d, rssi %d, threshold %d", set_power, p, rssi, threshold);
|
||||
#else
|
||||
char result[10];
|
||||
emsesp::EMSESP::logger().info("Setting WiFi Tx Power to %s dBm", emsesp::Helpers::render_value(result, (double)(p / 4), 1));
|
||||
emsesp::EMSESP::logger().info("Setting WiFi Tx Power to %s dBm", emsesp::Helpers::render_value(result, ((double)(p) / 4), 1));
|
||||
#endif
|
||||
|
||||
if (!WiFi.setTxPower(p)) {
|
||||
@@ -310,7 +315,7 @@ void NetworkSettingsService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info)
|
||||
emsesp::EMSESP::logger().info("WiFi connected with IP=%s, hostname=%s, TxPower=%s dBm",
|
||||
WiFi.localIP().toString().c_str(),
|
||||
WiFi.getHostname(),
|
||||
emsesp::Helpers::render_value(result, (double)(WiFi.getTxPower() / 4), 1));
|
||||
emsesp::Helpers::render_value(result, ((double)(WiFi.getTxPower()) / 4), 1));
|
||||
|
||||
mDNS_start();
|
||||
break;
|
||||
@@ -389,7 +394,6 @@ void NetworkSettings::read(NetworkSettings & settings, JsonObject root) {
|
||||
root["static_ip_config"] = settings.staticIPConfig;
|
||||
root["enableIPv6"] = settings.enableIPv6;
|
||||
root["bandwidth20"] = settings.bandwidth20;
|
||||
root["tx_power"] = settings.tx_power;
|
||||
root["nosleep"] = settings.nosleep;
|
||||
root["enableMDNS"] = settings.enableMDNS;
|
||||
root["enableCORS"] = settings.enableCORS;
|
||||
@@ -417,7 +421,7 @@ StateUpdateResult NetworkSettings::update(JsonObject root, NetworkSettings & set
|
||||
settings.staticIPConfig = root["static_ip_config"] | false;
|
||||
settings.enableIPv6 = root["enableIPv6"] | false;
|
||||
settings.bandwidth20 = root["bandwidth20"] | false;
|
||||
settings.tx_power = root["tx_power"] | 0;
|
||||
settings.tx_power = static_cast<uint8_t>(root["tx_power"] | 0);
|
||||
settings.nosleep = root["nosleep"] | false;
|
||||
settings.enableMDNS = root["enableMDNS"] | true;
|
||||
settings.enableCORS = root["enableCORS"] | false;
|
||||
@@ -445,7 +449,7 @@ StateUpdateResult NetworkSettings::update(JsonObject root, NetworkSettings & set
|
||||
|
||||
// see if we need to inform the user of a restart
|
||||
if (tx_power != settings.tx_power || enableCORS != settings.enableCORS || CORSOrigin != settings.CORSOrigin
|
||||
|| (ssid != settings.ssid && settings.ssid == "")) {
|
||||
|| (ssid != settings.ssid && settings.ssid.isEmpty())) {
|
||||
return StateUpdateResult::CHANGED_RESTART; // tell WebUI that a restart is needed
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#ifndef NetworkSettingsService_h
|
||||
#define NetworkSettingsService_h
|
||||
|
||||
#include <StatefulService.h>
|
||||
#include <FSPersistence.h>
|
||||
#include <HttpEndpoint.h>
|
||||
#include <JsonUtils.h>
|
||||
#include "StatefulService.h"
|
||||
#include "FSPersistence.h"
|
||||
#include "HttpEndpoint.h"
|
||||
#include "JsonUtils.h"
|
||||
|
||||
#ifndef EMSESP_STANDALONE
|
||||
#include <esp_wifi.h>
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
#define NETWORK_SETTINGS_FILE "/config/networkSettings.json"
|
||||
#define NETWORK_SETTINGS_SERVICE_PATH "/rest/networkSettings"
|
||||
#define WIFI_RECONNECTION_DELAY 1000 * 3
|
||||
#define WIFI_RECONNECTION_DELAY (1000 * 3)
|
||||
|
||||
#ifndef FACTORY_WIFI_SSID
|
||||
#define FACTORY_WIFI_SSID ""
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
#include <NetworkStatus.h>
|
||||
#include "NetworkStatus.h"
|
||||
|
||||
#include "../../src/emsesp_stub.hpp"
|
||||
|
||||
using namespace std::placeholders; // for `_1` etc
|
||||
|
||||
NetworkStatus::NetworkStatus(AsyncWebServer * server, SecurityManager * securityManager) {
|
||||
server->on(NETWORK_STATUS_SERVICE_PATH,
|
||||
HTTP_GET,
|
||||
securityManager->wrapRequest(std::bind(&NetworkStatus::networkStatus, this, _1), AuthenticationPredicates::IS_AUTHENTICATED));
|
||||
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { networkStatus(request); }, AuthenticationPredicates::IS_AUTHENTICATED));
|
||||
}
|
||||
|
||||
void NetworkStatus::networkStatus(AsyncWebServerRequest * request) {
|
||||
AsyncJsonResponse * response = new AsyncJsonResponse(false);
|
||||
auto * response = new AsyncJsonResponse(false);
|
||||
JsonObject root = response->getRoot();
|
||||
|
||||
bool ethernet_connected = emsesp::EMSESP::system_.ethernet_connected();
|
||||
@@ -22,7 +20,7 @@ void NetworkStatus::networkStatus(AsyncWebServerRequest * request) {
|
||||
root["status"] = 10; // custom code #10 - ETHERNET_STATUS_CONNECTED
|
||||
root["hostname"] = ETH.getHostname();
|
||||
} else {
|
||||
root["status"] = (uint8_t)wifi_status;
|
||||
root["status"] = static_cast<uint8_t>(wifi_status);
|
||||
root["hostname"] = WiFi.getHostname();
|
||||
}
|
||||
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
#include <ArduinoJson.h>
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <IPAddress.h>
|
||||
#include <IPUtils.h>
|
||||
|
||||
#include <SecurityManager.h>
|
||||
#include "IPUtils.h"
|
||||
#include "SecurityManager.h"
|
||||
|
||||
#define MAX_NETWORK_STATUS_SIZE 1024
|
||||
#define NETWORK_STATUS_SERVICE_PATH "/rest/networkStatus"
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
#include <OTASettingsService.h>
|
||||
#include "OTASettingsService.h"
|
||||
|
||||
#include "../../src/emsesp_stub.hpp"
|
||||
|
||||
using namespace std::placeholders; // for `_1` etc
|
||||
|
||||
OTASettingsService::OTASettingsService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
|
||||
: _httpEndpoint(OTASettings::read, OTASettings::update, this, server, OTA_SETTINGS_SERVICE_PATH, securityManager)
|
||||
, _fsPersistence(OTASettings::read, OTASettings::update, this, fs, OTA_SETTINGS_FILE)
|
||||
, _arduinoOTA(nullptr) {
|
||||
WiFi.onEvent(std::bind(&OTASettingsService::WiFiEvent, this, _1, _2));
|
||||
addUpdateHandler([&] { configureArduinoOTA(); }, false);
|
||||
WiFi.onEvent([this](WiFiEvent_t event, WiFiEventInfo_t info) { WiFiEvent(event); });
|
||||
addUpdateHandler([this] { configureArduinoOTA(); }, false);
|
||||
}
|
||||
|
||||
void OTASettingsService::begin() {
|
||||
@@ -32,7 +30,7 @@ void OTASettingsService::configureArduinoOTA() {
|
||||
|
||||
if (_state.enabled) {
|
||||
_arduinoOTA = new ArduinoOTAClass;
|
||||
_arduinoOTA->setPort(_state.port);
|
||||
_arduinoOTA->setPort(static_cast<uint16_t>(_state.port));
|
||||
_arduinoOTA->setPassword(_state.password.c_str());
|
||||
|
||||
_arduinoOTA->onStart([] { emsesp::EMSESP::system_.upload_status(true); });
|
||||
@@ -64,7 +62,7 @@ void OTASettingsService::configureArduinoOTA() {
|
||||
}
|
||||
}
|
||||
|
||||
void OTASettingsService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) {
|
||||
void OTASettingsService::WiFiEvent(WiFiEvent_t event) {
|
||||
switch (event) {
|
||||
case ARDUINO_EVENT_WIFI_STA_GOT_IP:
|
||||
case ARDUINO_EVENT_ETH_GOT_IP:
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#ifndef OTASettingsService_h
|
||||
#define OTASettingsService_h
|
||||
|
||||
#include <HttpEndpoint.h>
|
||||
#include <FSPersistence.h>
|
||||
#include "HttpEndpoint.h"
|
||||
#include "FSPersistence.h"
|
||||
|
||||
#include <ArduinoOTA.h>
|
||||
#include <WiFiUdp.h>
|
||||
@@ -45,7 +45,7 @@ class OTASettingsService : public StatefulService<OTASettings> {
|
||||
ArduinoOTAClass * _arduinoOTA;
|
||||
|
||||
void configureArduinoOTA();
|
||||
void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info);
|
||||
void WiFiEvent(WiFiEvent_t event);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,15 +1,22 @@
|
||||
#include <RestartService.h>
|
||||
#include "RestartService.h"
|
||||
|
||||
#include <esp_ota_ops.h>
|
||||
|
||||
#include "../../src/emsesp_stub.hpp"
|
||||
|
||||
using namespace std::placeholders; // for `_1` etc
|
||||
|
||||
RestartService::RestartService(AsyncWebServer * server, SecurityManager * securityManager) {
|
||||
server->on(RESTART_SERVICE_PATH, HTTP_POST, securityManager->wrapRequest(std::bind(&RestartService::restart, this, _1), AuthenticationPredicates::IS_ADMIN));
|
||||
server->on(RESTART_SERVICE_PATH,
|
||||
HTTP_POST,
|
||||
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { restart(request); }, AuthenticationPredicates::IS_ADMIN));
|
||||
server->on(PARTITION_SERVICE_PATH,
|
||||
HTTP_POST,
|
||||
securityManager->wrapRequest(std::bind(&RestartService::partition, this, _1), AuthenticationPredicates::IS_ADMIN));
|
||||
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { partition(request); }, AuthenticationPredicates::IS_ADMIN));
|
||||
}
|
||||
|
||||
void RestartService::restartNow() {
|
||||
WiFi.disconnect(true);
|
||||
delay(500);
|
||||
ESP.restart();
|
||||
}
|
||||
|
||||
void RestartService::restart(AsyncWebServerRequest * request) {
|
||||
@@ -19,7 +26,7 @@ void RestartService::restart(AsyncWebServerRequest * request) {
|
||||
}
|
||||
|
||||
void RestartService::partition(AsyncWebServerRequest * request) {
|
||||
const esp_partition_t * factory_partition = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_FACTORY, NULL);
|
||||
const esp_partition_t * factory_partition = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_FACTORY, nullptr);
|
||||
if (factory_partition) {
|
||||
esp_ota_set_boot_partition(factory_partition);
|
||||
emsesp::EMSESP::system_.store_nvs_values();
|
||||
@@ -27,7 +34,7 @@ void RestartService::partition(AsyncWebServerRequest * request) {
|
||||
request->send(200);
|
||||
return;
|
||||
}
|
||||
const esp_partition_t * ota_partition = esp_ota_get_next_update_partition(NULL);
|
||||
const esp_partition_t * ota_partition = esp_ota_get_next_update_partition(nullptr);
|
||||
if (!ota_partition) {
|
||||
request->send(400); // bad request
|
||||
return;
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
|
||||
#include <WiFi.h>
|
||||
#include <AsyncTCP.h>
|
||||
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <SecurityManager.h>
|
||||
|
||||
#include "SecurityManager.h"
|
||||
|
||||
#define RESTART_SERVICE_PATH "/rest/restart"
|
||||
#define PARTITION_SERVICE_PATH "/rest/partition"
|
||||
@@ -14,11 +14,7 @@ class RestartService {
|
||||
public:
|
||||
RestartService(AsyncWebServer * server, SecurityManager * securityManager);
|
||||
|
||||
static void restartNow() {
|
||||
WiFi.disconnect(true);
|
||||
delay(500);
|
||||
ESP.restart();
|
||||
}
|
||||
static void restartNow();
|
||||
|
||||
private:
|
||||
void restart(AsyncWebServerRequest * request);
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
#ifndef SecurityManager_h
|
||||
#define SecurityManager_h
|
||||
|
||||
#include <Features.h>
|
||||
#include <ArduinoJsonJWT.h>
|
||||
#include "Features.h"
|
||||
#include "ArduinoJsonJWT.h"
|
||||
#include "ESPUtils.h"
|
||||
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <ESPUtils.h>
|
||||
#include <AsyncJson.h>
|
||||
#include <list>
|
||||
|
||||
@@ -26,28 +27,27 @@ class User {
|
||||
|
||||
public:
|
||||
User(String username, String password, bool admin)
|
||||
: username(username)
|
||||
, password(password)
|
||||
: username(std::move(username))
|
||||
, password(std::move(password))
|
||||
, admin(admin) {
|
||||
}
|
||||
};
|
||||
|
||||
class Authentication {
|
||||
public:
|
||||
User * user;
|
||||
boolean authenticated;
|
||||
User * user = nullptr;
|
||||
boolean authenticated = false;
|
||||
|
||||
public:
|
||||
Authentication(User & user)
|
||||
explicit Authentication(const User & user)
|
||||
: user(new User(user))
|
||||
, authenticated(true) {
|
||||
}
|
||||
Authentication()
|
||||
: user(nullptr)
|
||||
, authenticated(false) {
|
||||
}
|
||||
|
||||
Authentication() = default;
|
||||
|
||||
~Authentication() {
|
||||
delete (user);
|
||||
delete user;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -55,13 +55,14 @@ typedef std::function<boolean(Authentication & authentication)> AuthenticationPr
|
||||
|
||||
class AuthenticationPredicates {
|
||||
public:
|
||||
static bool NONE_REQUIRED(Authentication & authentication) {
|
||||
static bool NONE_REQUIRED(const Authentication & authentication) {
|
||||
(void)authentication;
|
||||
return true;
|
||||
};
|
||||
static bool IS_AUTHENTICATED(Authentication & authentication) {
|
||||
static bool IS_AUTHENTICATED(const Authentication & authentication) {
|
||||
return authentication.authenticated;
|
||||
};
|
||||
static bool IS_ADMIN(Authentication & authentication) {
|
||||
static bool IS_ADMIN(const Authentication & authentication) {
|
||||
return authentication.authenticated && authentication.user->admin;
|
||||
};
|
||||
};
|
||||
@@ -76,7 +77,7 @@ class SecurityManager {
|
||||
/*
|
||||
* Generate a JWT for the user provided
|
||||
*/
|
||||
virtual String generateJWT(User * user) = 0;
|
||||
virtual String generateJWT(const User * user) = 0;
|
||||
|
||||
/*
|
||||
* Check the request header for the Authorization token
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
#include <SecuritySettingsService.h>
|
||||
|
||||
#include "../../src/emsesp_stub.hpp"
|
||||
#include "SecuritySettingsService.h"
|
||||
|
||||
SecuritySettingsService::SecuritySettingsService(AsyncWebServer * server, FS * fs)
|
||||
: _httpEndpoint(SecuritySettings::read, SecuritySettings::update, this, server, SECURITY_SETTINGS_PATH, this)
|
||||
, _fsPersistence(SecuritySettings::read, SecuritySettings::update, this, fs, SECURITY_SETTINGS_FILE)
|
||||
, _jwtHandler(FACTORY_JWT_SECRET) {
|
||||
addUpdateHandler([&] { configureJWTHandler(); }, false);
|
||||
addUpdateHandler([this] { configureJWTHandler(); }, false);
|
||||
server->on(GENERATE_TOKEN_PATH,
|
||||
HTTP_GET,
|
||||
wrapRequest(std::bind(&SecuritySettingsService::generateToken, this, std::placeholders::_1), AuthenticationPredicates::IS_ADMIN));
|
||||
SecuritySettingsService::wrapRequest([this](AsyncWebServerRequest * request) { generateToken(request); }, AuthenticationPredicates::IS_ADMIN));
|
||||
}
|
||||
|
||||
void SecuritySettingsService::begin() {
|
||||
@@ -30,7 +28,7 @@ Authentication SecuritySettingsService::authenticateRequest(AsyncWebServerReques
|
||||
String value = tokenParamater->value();
|
||||
return authenticateJWT(value);
|
||||
}
|
||||
return Authentication();
|
||||
return {};
|
||||
}
|
||||
|
||||
void SecuritySettingsService::configureJWTHandler() {
|
||||
@@ -43,37 +41,37 @@ Authentication SecuritySettingsService::authenticateJWT(String & jwt) {
|
||||
if (payloadDocument.is<JsonObject>()) {
|
||||
JsonObject parsedPayload = payloadDocument.as<JsonObject>();
|
||||
String username = parsedPayload["username"];
|
||||
for (User _user : _state.users) {
|
||||
for (const User & _user : _state.users) {
|
||||
if (_user.username == username && validatePayload(parsedPayload, &_user)) {
|
||||
return Authentication(_user);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Authentication();
|
||||
return {};
|
||||
}
|
||||
|
||||
Authentication SecuritySettingsService::authenticate(const String & username, const String & password) {
|
||||
for (User _user : _state.users) {
|
||||
for (const User & _user : _state.users) {
|
||||
if (_user.username == username && _user.password == password) {
|
||||
return Authentication(_user);
|
||||
}
|
||||
}
|
||||
return Authentication();
|
||||
return {};
|
||||
}
|
||||
|
||||
inline void populateJWTPayload(JsonObject payload, User * user) {
|
||||
inline void populateJWTPayload(JsonObject payload, const User * user) {
|
||||
payload["username"] = user->username;
|
||||
payload["admin"] = user->admin;
|
||||
}
|
||||
|
||||
boolean SecuritySettingsService::validatePayload(JsonObject parsedPayload, User * user) {
|
||||
boolean SecuritySettingsService::validatePayload(JsonObject parsedPayload, const User * user) {
|
||||
JsonDocument jsonDocument;
|
||||
JsonObject payload = jsonDocument.to<JsonObject>();
|
||||
populateJWTPayload(payload, user);
|
||||
return payload == parsedPayload;
|
||||
}
|
||||
|
||||
String SecuritySettingsService::generateJWT(User * user) {
|
||||
String SecuritySettingsService::generateJWT(const User * user) {
|
||||
JsonDocument jsonDocument;
|
||||
JsonObject payload = jsonDocument.to<JsonObject>();
|
||||
populateJWTPayload(payload, user);
|
||||
@@ -111,9 +109,9 @@ ArJsonRequestHandlerFunction SecuritySettingsService::wrapCallback(ArJsonRequest
|
||||
|
||||
void SecuritySettingsService::generateToken(AsyncWebServerRequest * request) {
|
||||
AsyncWebParameter * usernameParam = request->getParam("username");
|
||||
for (User _user : _state.users) {
|
||||
for (const User & _user : _state.users) {
|
||||
if (_user.username == usernameParam->value()) {
|
||||
AsyncJsonResponse * response = new AsyncJsonResponse(false);
|
||||
auto * response = new AsyncJsonResponse(false);
|
||||
JsonObject root = response->getRoot();
|
||||
root["token"] = generateJWT(&_user);
|
||||
response->setLength();
|
||||
@@ -123,34 +121,3 @@ void SecuritySettingsService::generateToken(AsyncWebServerRequest * request) {
|
||||
}
|
||||
request->send(401);
|
||||
}
|
||||
|
||||
void SecuritySettings::read(SecuritySettings & settings, JsonObject root) {
|
||||
// secret
|
||||
root["jwt_secret"] = settings.jwtSecret;
|
||||
|
||||
// users
|
||||
JsonArray users = root["users"].to<JsonArray>();
|
||||
for (User user : settings.users) {
|
||||
JsonObject userRoot = users.add<JsonObject>();
|
||||
userRoot["username"] = user.username;
|
||||
userRoot["password"] = user.password;
|
||||
userRoot["admin"] = user.admin;
|
||||
}
|
||||
}
|
||||
|
||||
StateUpdateResult SecuritySettings::update(JsonObject root, SecuritySettings & settings) {
|
||||
// secret
|
||||
settings.jwtSecret = root["jwt_secret"] | FACTORY_JWT_SECRET;
|
||||
|
||||
// users
|
||||
settings.users.clear();
|
||||
if (root["users"].is<JsonArray>()) {
|
||||
for (JsonVariant user : root["users"].as<JsonArray>()) {
|
||||
settings.users.push_back(User(user["username"], user["password"], user["admin"]));
|
||||
}
|
||||
} else {
|
||||
settings.users.push_back(User(FACTORY_ADMIN_USERNAME, FACTORY_ADMIN_PASSWORD, true));
|
||||
settings.users.push_back(User(FACTORY_GUEST_USERNAME, FACTORY_GUEST_PASSWORD, false));
|
||||
}
|
||||
return StateUpdateResult::CHANGED;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#ifndef SecuritySettingsService_h
|
||||
#define SecuritySettingsService_h
|
||||
|
||||
#include <Features.h>
|
||||
#include <SecurityManager.h>
|
||||
#include <HttpEndpoint.h>
|
||||
#include <FSPersistence.h>
|
||||
#include "Features.h"
|
||||
#include "SecurityManager.h"
|
||||
#include "HttpEndpoint.h"
|
||||
#include "FSPersistence.h"
|
||||
|
||||
#ifndef FACTORY_ADMIN_USERNAME
|
||||
#define FACTORY_ADMIN_USERNAME "admin"
|
||||
@@ -33,23 +33,51 @@ class SecuritySettings {
|
||||
String jwtSecret;
|
||||
std::vector<User> users;
|
||||
|
||||
static void read(SecuritySettings & settings, JsonObject root);
|
||||
static StateUpdateResult update(JsonObject root, SecuritySettings & settings);
|
||||
static void read(SecuritySettings & settings, JsonObject root) {
|
||||
// secret
|
||||
root["jwt_secret"] = settings.jwtSecret;
|
||||
|
||||
// users
|
||||
JsonArray users = root["users"].to<JsonArray>();
|
||||
for (const User & user : settings.users) {
|
||||
JsonObject userRoot = users.add<JsonObject>();
|
||||
userRoot["username"] = user.username;
|
||||
userRoot["password"] = user.password;
|
||||
userRoot["admin"] = user.admin;
|
||||
}
|
||||
}
|
||||
|
||||
static StateUpdateResult update(JsonObject root, SecuritySettings & settings) {
|
||||
// secret
|
||||
settings.jwtSecret = root["jwt_secret"] | FACTORY_JWT_SECRET;
|
||||
|
||||
// users
|
||||
settings.users.clear();
|
||||
if (root["users"].is<JsonArray>()) {
|
||||
for (JsonVariant user : root["users"].as<JsonArray>()) {
|
||||
settings.users.emplace_back(user["username"], user["password"], user["admin"]);
|
||||
}
|
||||
} else {
|
||||
settings.users.emplace_back(FACTORY_ADMIN_USERNAME, FACTORY_ADMIN_PASSWORD, true);
|
||||
settings.users.emplace_back(FACTORY_GUEST_USERNAME, FACTORY_GUEST_PASSWORD, false);
|
||||
}
|
||||
return StateUpdateResult::CHANGED;
|
||||
}
|
||||
};
|
||||
|
||||
class SecuritySettingsService : public StatefulService<SecuritySettings>, public SecurityManager {
|
||||
class SecuritySettingsService final : public StatefulService<SecuritySettings>, public SecurityManager {
|
||||
public:
|
||||
SecuritySettingsService(AsyncWebServer * server, FS * fs);
|
||||
|
||||
void begin();
|
||||
|
||||
// Functions to implement SecurityManager
|
||||
Authentication authenticate(const String & username, const String & password);
|
||||
Authentication authenticateRequest(AsyncWebServerRequest * request);
|
||||
String generateJWT(User * user);
|
||||
ArRequestFilterFunction filterRequest(AuthenticationPredicate predicate);
|
||||
ArRequestHandlerFunction wrapRequest(ArRequestHandlerFunction onRequest, AuthenticationPredicate predicate);
|
||||
ArJsonRequestHandlerFunction wrapCallback(ArJsonRequestHandlerFunction callback, AuthenticationPredicate predicate);
|
||||
Authentication authenticate(const String & username, const String & password) override;
|
||||
Authentication authenticateRequest(AsyncWebServerRequest * request) override;
|
||||
String generateJWT(const User * user) override;
|
||||
ArRequestFilterFunction filterRequest(AuthenticationPredicate predicate) override;
|
||||
ArRequestHandlerFunction wrapRequest(ArRequestHandlerFunction onRequest, AuthenticationPredicate predicate) override;
|
||||
ArJsonRequestHandlerFunction wrapCallback(ArJsonRequestHandlerFunction callback, AuthenticationPredicate predicate) override;
|
||||
|
||||
private:
|
||||
HttpEndpoint<SecuritySettings> _httpEndpoint;
|
||||
@@ -68,7 +96,7 @@ class SecuritySettingsService : public StatefulService<SecuritySettings>, public
|
||||
/*
|
||||
* Verify the payload is correct
|
||||
*/
|
||||
boolean validatePayload(JsonObject parsedPayload, User * user);
|
||||
boolean validatePayload(JsonObject parsedPayload, const User * user);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,3 +1,3 @@
|
||||
#include <StatefulService.h>
|
||||
#include "StatefulService.h"
|
||||
|
||||
update_handler_id_t StateUpdateHandlerInfo::currentUpdatedHandlerId = 0;
|
||||
|
||||
@@ -1,20 +1,19 @@
|
||||
#include <SystemStatus.h>
|
||||
#include "SystemStatus.h"
|
||||
|
||||
#include <esp_ota_ops.h>
|
||||
|
||||
#include "../../src/emsesp_stub.hpp"
|
||||
|
||||
using namespace std::placeholders; // for `_1` etc
|
||||
|
||||
SystemStatus::SystemStatus(AsyncWebServer * server, SecurityManager * securityManager) {
|
||||
server->on(SYSTEM_STATUS_SERVICE_PATH,
|
||||
HTTP_GET,
|
||||
securityManager->wrapRequest(std::bind(&SystemStatus::systemStatus, this, _1), AuthenticationPredicates::IS_AUTHENTICATED));
|
||||
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { systemStatus(request); }, AuthenticationPredicates::IS_AUTHENTICATED));
|
||||
}
|
||||
|
||||
void SystemStatus::systemStatus(AsyncWebServerRequest * request) {
|
||||
emsesp::EMSESP::system_.refreshHeapMem(); // refresh free heap and max alloc heap
|
||||
|
||||
AsyncJsonResponse * response = new AsyncJsonResponse(false);
|
||||
auto * response = new AsyncJsonResponse(false);
|
||||
JsonObject root = response->getRoot();
|
||||
|
||||
#ifdef EMSESP_DEBUG
|
||||
@@ -49,11 +48,11 @@ void SystemStatus::systemStatus(AsyncWebServerRequest * request) {
|
||||
root["psram_size"] = emsesp::EMSESP::system_.PSram();
|
||||
root["free_psram"] = ESP.getFreePsram() / 1024;
|
||||
}
|
||||
const esp_partition_t * partition = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_FACTORY, NULL);
|
||||
const esp_partition_t * partition = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_FACTORY, nullptr);
|
||||
if (partition != NULL) { // factory partition found
|
||||
root["has_loader"] = true;
|
||||
} else { // check for not empty, smaller OTA partition
|
||||
partition = esp_ota_get_next_update_partition(NULL);
|
||||
partition = esp_ota_get_next_update_partition(nullptr);
|
||||
if (partition) {
|
||||
uint64_t buffer;
|
||||
esp_partition_read(partition, 0, &buffer, 8);
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
#include <AsyncTCP.h>
|
||||
#include <FS.h>
|
||||
#include <LittleFS.h>
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <SecurityManager.h>
|
||||
|
||||
#include "SecurityManager.h"
|
||||
|
||||
#define SYSTEM_STATUS_SERVICE_PATH "/rest/systemStatus"
|
||||
|
||||
|
||||
@@ -1,20 +1,27 @@
|
||||
#include <UploadFileService.h>
|
||||
#include <esp_ota_ops.h>
|
||||
#include <esp_app_format.h>
|
||||
|
||||
#include "UploadFileService.h"
|
||||
#include "../../src/emsesp_stub.hpp"
|
||||
|
||||
using namespace std::placeholders; // for `_1` etc
|
||||
#include <esp_app_format.h>
|
||||
|
||||
static bool is_firmware = false;
|
||||
static char md5[33] = "\0";
|
||||
static String getFilenameExtension(const String & filename) {
|
||||
const auto pos = filename.lastIndexOf('.');
|
||||
if (pos != -1) {
|
||||
return filename.substring(static_cast<unsigned int>(pos) + 1);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
UploadFileService::UploadFileService(AsyncWebServer * server, SecurityManager * securityManager)
|
||||
: _securityManager(securityManager) {
|
||||
server->on(UPLOAD_FILE_PATH,
|
||||
: _securityManager(securityManager)
|
||||
, _is_firmware(false)
|
||||
, _md5() {
|
||||
server->on(
|
||||
UPLOAD_FILE_PATH,
|
||||
HTTP_POST,
|
||||
std::bind(&UploadFileService::uploadComplete, this, _1),
|
||||
std::bind(&UploadFileService::handleUpload, this, _1, _2, _3, _4, _5, _6));
|
||||
[this](AsyncWebServerRequest * request) { uploadComplete(request); },
|
||||
[this](AsyncWebServerRequest * request, const String & filename, size_t index, uint8_t * data, size_t len, bool final) {
|
||||
handleUpload(request, filename, index, data, len, final);
|
||||
});
|
||||
}
|
||||
|
||||
void UploadFileService::handleUpload(AsyncWebServerRequest * request, const String & filename, size_t index, uint8_t * data, size_t len, bool final) {
|
||||
@@ -28,29 +35,27 @@ void UploadFileService::handleUpload(AsyncWebServerRequest * request, const Stri
|
||||
// at init
|
||||
if (!index) {
|
||||
// check details of the file, to see if its a valid bin or json file
|
||||
std::string fname(filename.c_str());
|
||||
auto position = fname.find_last_of(".");
|
||||
std::string extension = fname.substr(position + 1);
|
||||
size_t fsize = request->contentLength();
|
||||
const String extension = getFilenameExtension(filename);
|
||||
const std::size_t filesize = request->contentLength();
|
||||
|
||||
is_firmware = false;
|
||||
if ((extension == "bin") && (fsize > 1000000)) {
|
||||
is_firmware = true;
|
||||
_is_firmware = false;
|
||||
if ((extension == "bin") && (filesize > 1000000)) {
|
||||
_is_firmware = true;
|
||||
} else if (extension == "json") {
|
||||
md5[0] = '\0'; // clear md5
|
||||
_md5[0] = '\0'; // clear md5
|
||||
} else if (extension == "md5") {
|
||||
if (len == 32) {
|
||||
memcpy(md5, data, 32);
|
||||
md5[32] = '\0';
|
||||
if (len == _md5.size() - 1) {
|
||||
std::memcpy(_md5.data(), data, _md5.size() - 1);
|
||||
_md5.back() = '\0';
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
md5[0] = '\0';
|
||||
_md5.front() = '\0';
|
||||
handleError(request, 406); // Not Acceptable - unsupported file type
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_firmware) {
|
||||
if (_is_firmware) {
|
||||
// Check firmware header, 0xE9 magic offset 0 indicates esp bin, chip offset 12: esp32:0, S2:2, C3:5
|
||||
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
|
||||
if (len > 12 && (data[0] != 0xE9 || data[12] != 0)) {
|
||||
@@ -74,12 +79,12 @@ void UploadFileService::handleUpload(AsyncWebServerRequest * request, const Stri
|
||||
}
|
||||
#endif
|
||||
// it's firmware - initialize the ArduinoOTA updater
|
||||
if (Update.begin(fsize - sizeof(esp_image_header_t))) {
|
||||
if (strlen(md5) == 32) {
|
||||
Update.setMD5(md5);
|
||||
md5[0] = '\0';
|
||||
if (Update.begin(filesize - sizeof(esp_image_header_t))) {
|
||||
if (strlen(_md5.data()) == _md5.size() - 1) {
|
||||
Update.setMD5(_md5.data());
|
||||
_md5.front() = '\0';
|
||||
}
|
||||
request->onDisconnect(UploadFileService::handleEarlyDisconnect); // success, let's make sure we end the update if the client hangs up
|
||||
request->onDisconnect([this]() { handleEarlyDisconnect(); }); // success, let's make sure we end the update if the client hangs up
|
||||
} else {
|
||||
handleError(request, 507); // failed to begin, send an error response Insufficient Storage
|
||||
return;
|
||||
@@ -90,26 +95,20 @@ void UploadFileService::handleUpload(AsyncWebServerRequest * request, const Stri
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_firmware) {
|
||||
if (len) {
|
||||
if (len != request->_tempFile.write(data, len)) { // stream the incoming chunk to the opened file
|
||||
if (!_is_firmware) {
|
||||
if (len && len != request->_tempFile.write(data, len)) { // stream the incoming chunk to the opened file
|
||||
handleError(request, 507); // 507-Insufficient Storage
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// if we haven't delt with an error, continue with the firmware update
|
||||
if (!request->_tempObject) {
|
||||
} else if (!request->_tempObject) { // if we haven't delt with an error, continue with the firmware update
|
||||
if (Update.write(data, len) != len) {
|
||||
handleError(request, 500);
|
||||
return;
|
||||
}
|
||||
if (final) {
|
||||
if (!Update.end(true)) {
|
||||
if (final && !Update.end(true)) {
|
||||
handleError(request, 500);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UploadFileService::uploadComplete(AsyncWebServerRequest * request) {
|
||||
// did we complete uploading a json file?
|
||||
@@ -124,7 +123,7 @@ void UploadFileService::uploadComplete(AsyncWebServerRequest * request) {
|
||||
|
||||
// check if it was a firmware upgrade
|
||||
// if no error, send the success response as a JSON
|
||||
if (is_firmware && !request->_tempObject) {
|
||||
if (_is_firmware && !request->_tempObject) {
|
||||
emsesp::EMSESP::system_.store_nvs_values();
|
||||
request->onDisconnect(RestartService::restartNow);
|
||||
AsyncWebServerResponse * response = request->beginResponse(200);
|
||||
@@ -132,10 +131,10 @@ void UploadFileService::uploadComplete(AsyncWebServerRequest * request) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (strlen(md5) == 32) {
|
||||
if (strlen(_md5.data()) == _md5.size() - 1) {
|
||||
auto * response = new AsyncJsonResponse(false);
|
||||
JsonObject root = response->getRoot();
|
||||
root["md5"] = md5;
|
||||
root["md5"] = _md5.data();
|
||||
response->setLength();
|
||||
request->send(response);
|
||||
return;
|
||||
@@ -163,6 +162,6 @@ void UploadFileService::handleError(AsyncWebServerRequest * request, int code) {
|
||||
}
|
||||
|
||||
void UploadFileService::handleEarlyDisconnect() {
|
||||
is_firmware = false;
|
||||
_is_firmware = false;
|
||||
Update.abort();
|
||||
}
|
||||
@@ -1,16 +1,16 @@
|
||||
#ifndef UploadFileService_h
|
||||
#define UploadFileService_h
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "RestartService.h"
|
||||
#include "SecurityManager.h"
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <LittleFS.h>
|
||||
#include <Update.h>
|
||||
#include <WiFi.h>
|
||||
|
||||
#include <LittleFS.h>
|
||||
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <SecurityManager.h>
|
||||
#include <RestartService.h>
|
||||
#include <array>
|
||||
|
||||
#define UPLOAD_FILE_PATH "/rest/uploadFile"
|
||||
#define TEMP_FILENAME_PATH "/tmp_upload"
|
||||
@@ -21,10 +21,13 @@ class UploadFileService {
|
||||
|
||||
private:
|
||||
SecurityManager * _securityManager;
|
||||
bool _is_firmware;
|
||||
std::array<char, 33> _md5;
|
||||
|
||||
void handleUpload(AsyncWebServerRequest * request, const String & filename, size_t index, uint8_t * data, size_t len, bool final);
|
||||
void uploadComplete(AsyncWebServerRequest * request);
|
||||
void handleError(AsyncWebServerRequest * request, int code);
|
||||
static void handleEarlyDisconnect();
|
||||
void handleEarlyDisconnect();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,14 +1,12 @@
|
||||
#include <WiFiScanner.h>
|
||||
|
||||
using namespace std::placeholders; // for `_1` etc
|
||||
#include "WiFiScanner.h"
|
||||
|
||||
WiFiScanner::WiFiScanner(AsyncWebServer * server, SecurityManager * securityManager) {
|
||||
server->on(SCAN_NETWORKS_SERVICE_PATH,
|
||||
HTTP_GET,
|
||||
securityManager->wrapRequest(std::bind(&WiFiScanner::scanNetworks, this, _1), AuthenticationPredicates::IS_ADMIN));
|
||||
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { scanNetworks(request); }, AuthenticationPredicates::IS_ADMIN));
|
||||
server->on(LIST_NETWORKS_SERVICE_PATH,
|
||||
HTTP_GET,
|
||||
securityManager->wrapRequest(std::bind(&WiFiScanner::listNetworks, this, _1), AuthenticationPredicates::IS_ADMIN));
|
||||
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { listNetworks(request); }, AuthenticationPredicates::IS_ADMIN));
|
||||
};
|
||||
|
||||
void WiFiScanner::scanNetworks(AsyncWebServerRequest * request) {
|
||||
@@ -21,18 +19,18 @@ void WiFiScanner::scanNetworks(AsyncWebServerRequest * request) {
|
||||
}
|
||||
|
||||
void WiFiScanner::listNetworks(AsyncWebServerRequest * request) {
|
||||
int numNetworks = WiFi.scanComplete();
|
||||
const int numNetworks = WiFi.scanComplete();
|
||||
if (numNetworks > -1) {
|
||||
AsyncJsonResponse * response = new AsyncJsonResponse(false);
|
||||
auto * response = new AsyncJsonResponse(false);
|
||||
JsonObject root = response->getRoot();
|
||||
JsonArray networks = root["networks"].to<JsonArray>();
|
||||
for (int i = 0; i < numNetworks; i++) {
|
||||
for (uint8_t i = 0; i < numNetworks; i++) {
|
||||
JsonObject network = networks.add<JsonObject>();
|
||||
network["rssi"] = WiFi.RSSI(i);
|
||||
network["ssid"] = WiFi.SSID(i);
|
||||
network["bssid"] = WiFi.BSSIDstr(i);
|
||||
network["channel"] = WiFi.channel(i);
|
||||
network["encryption_type"] = (uint8_t)WiFi.encryptionType(i);
|
||||
network["encryption_type"] = static_cast<uint8_t>(WiFi.encryptionType(i));
|
||||
}
|
||||
response->setLength();
|
||||
request->send(response);
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
|
||||
#include <WiFi.h>
|
||||
#include <AsyncTCP.h>
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <SecurityManager.h>
|
||||
|
||||
#include "SecurityManager.h"
|
||||
|
||||
#define SCAN_NETWORKS_SERVICE_PATH "/rest/scanNetworks"
|
||||
#define LIST_NETWORKS_SERVICE_PATH "/rest/listNetworks"
|
||||
|
||||
@@ -68,7 +68,7 @@ class StatefulService {
|
||||
}
|
||||
}
|
||||
|
||||
StateUpdateResult update(std::function<StateUpdateResult(T &)> stateUpdater, ) {
|
||||
StateUpdateResult update(std::function<StateUpdateResult(T &)> stateUpdater) {
|
||||
beginTransaction();
|
||||
StateUpdateResult result = stateUpdater(_state);
|
||||
endTransaction();
|
||||
@@ -85,7 +85,7 @@ class StatefulService {
|
||||
return result;
|
||||
}
|
||||
|
||||
StateUpdateResult update(JsonObject jsonObject, JsonStateUpdater<T> stateUpdater, ) {
|
||||
StateUpdateResult update(JsonObject jsonObject, JsonStateUpdater<T> stateUpdater) {
|
||||
beginTransaction();
|
||||
StateUpdateResult result = stateUpdater(jsonObject, _state);
|
||||
endTransaction();
|
||||
|
||||
@@ -38,8 +38,7 @@
|
||||
#endif
|
||||
#include <Preferences.h>
|
||||
|
||||
#include <ESP8266React.h>
|
||||
|
||||
#include "ESP8266React.h"
|
||||
#include "web/WebStatusService.h"
|
||||
#include "web/WebDataService.h"
|
||||
#include "web/WebSettingsService.h"
|
||||
|
||||
@@ -24,8 +24,7 @@
|
||||
#include "version.h"
|
||||
#include "default_settings.h"
|
||||
#include "helpers.h"
|
||||
|
||||
#include <ESP8266React.h>
|
||||
#include "ESP8266React.h"
|
||||
|
||||
#include <uuid/log.h>
|
||||
|
||||
|
||||
@@ -21,16 +21,15 @@
|
||||
|
||||
#include <string>
|
||||
#include <deque>
|
||||
#include <uuid/log.h>
|
||||
|
||||
// UART drivers
|
||||
#if defined(ESP32)
|
||||
#include "uart/emsuart_esp32.h"
|
||||
#elif defined(EMSESP_STANDALONE)
|
||||
#include <emsuart_standalone.h>
|
||||
#include "emsuart_standalone.h"
|
||||
#endif
|
||||
|
||||
#include <uuid/log.h>
|
||||
|
||||
#include "helpers.h"
|
||||
|
||||
#define MAX_RX_TELEGRAMS 10 // size of Rx queue
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define EMSESP_APP_VERSION "3.6.5-dev.13"
|
||||
#define EMSESP_APP_VERSION "3.6.5-dev.14"
|
||||
|
||||
@@ -18,8 +18,6 @@
|
||||
|
||||
#include "emsesp.h"
|
||||
|
||||
using namespace std::placeholders; // for `_1` etc
|
||||
|
||||
namespace emsesp {
|
||||
|
||||
uint32_t WebAPIService::api_count_ = 0;
|
||||
@@ -27,17 +25,26 @@ uint16_t WebAPIService::api_fails_ = 0;
|
||||
|
||||
WebAPIService::WebAPIService(AsyncWebServer * server, SecurityManager * securityManager)
|
||||
: _securityManager(securityManager)
|
||||
, _apiHandler("/api", std::bind(&WebAPIService::webAPIService_post, this, _1, _2)) { // for POSTS, must use 'Content-Type: application/json' in header
|
||||
server->on("/api", HTTP_GET, std::bind(&WebAPIService::webAPIService_get, this, _1)); // for GETS
|
||||
, _apiHandler(EMSESP_API_SERVICE_PATH, [this](AsyncWebServerRequest * request, JsonVariant json) { webAPIService_post(request, json); }) { // for POSTs
|
||||
server->on(EMSESP_API_SERVICE_PATH, HTTP_GET, [this](AsyncWebServerRequest * request) { webAPIService_get(request); }); // for GETs
|
||||
server->addHandler(&_apiHandler);
|
||||
|
||||
// for settings
|
||||
server->on(GET_SETTINGS_PATH, HTTP_GET, securityManager->wrapRequest(std::bind(&WebAPIService::getSettings, this, _1), AuthenticationPredicates::IS_ADMIN));
|
||||
server->on(GET_SETTINGS_PATH,
|
||||
HTTP_GET,
|
||||
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { getSettings(request); }, 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));
|
||||
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { getCustomizations(request); }, AuthenticationPredicates::IS_ADMIN));
|
||||
|
||||
server->on(GET_SCHEDULE_PATH,
|
||||
HTTP_GET,
|
||||
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { getSchedule(request); }, AuthenticationPredicates::IS_ADMIN));
|
||||
|
||||
server->on(GET_ENTITIES_PATH,
|
||||
HTTP_GET,
|
||||
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { getEntities(request); }, AuthenticationPredicates::IS_ADMIN));
|
||||
}
|
||||
|
||||
// HTTP GET
|
||||
|
||||
@@ -20,8 +20,6 @@
|
||||
|
||||
namespace emsesp {
|
||||
|
||||
using namespace std::placeholders; // for `_1` etc
|
||||
|
||||
WebCustomEntityService::WebCustomEntityService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
|
||||
: _httpEndpoint(WebCustomEntity::read,
|
||||
WebCustomEntity::update,
|
||||
|
||||
@@ -20,27 +20,24 @@
|
||||
|
||||
namespace emsesp {
|
||||
|
||||
using namespace std::placeholders; // for `_1` etc
|
||||
|
||||
bool WebCustomization::_start = true;
|
||||
|
||||
WebCustomizationService::WebCustomizationService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
|
||||
: _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),
|
||||
securityManager->wrapCallback([this](AsyncWebServerRequest * request, JsonVariant json) { customization_entities(request, json); },
|
||||
AuthenticationPredicates::IS_AUTHENTICATED)) {
|
||||
server->on(DEVICE_ENTITIES_PATH,
|
||||
HTTP_GET,
|
||||
securityManager->wrapRequest(std::bind(&WebCustomizationService::device_entities, this, _1), AuthenticationPredicates::IS_AUTHENTICATED));
|
||||
|
||||
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { device_entities(request); }, AuthenticationPredicates::IS_AUTHENTICATED));
|
||||
|
||||
server->on(DEVICES_SERVICE_PATH,
|
||||
HTTP_GET,
|
||||
securityManager->wrapRequest(std::bind(&WebCustomizationService::devices, this, _1), AuthenticationPredicates::IS_AUTHENTICATED));
|
||||
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { devices(request); }, AuthenticationPredicates::IS_AUTHENTICATED));
|
||||
|
||||
server->on(RESET_CUSTOMIZATION_SERVICE_PATH,
|
||||
HTTP_POST,
|
||||
securityManager->wrapRequest(std::bind(&WebCustomizationService::reset_customization, this, _1), AuthenticationPredicates::IS_ADMIN));
|
||||
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { reset_customization(request); }, AuthenticationPredicates::IS_ADMIN));
|
||||
|
||||
_masked_entities_handler.setMethod(HTTP_POST);
|
||||
_masked_entities_handler.setMaxContentLength(2048);
|
||||
|
||||
@@ -20,33 +20,36 @@
|
||||
|
||||
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))
|
||||
securityManager->wrapCallback([this](AsyncWebServerRequest * request, JsonVariant json) { write_device_value(request, json); },
|
||||
AuthenticationPredicates::IS_ADMIN))
|
||||
, _write_temperature_handler(WRITE_TEMPERATURE_SENSOR_SERVICE_PATH,
|
||||
securityManager->wrapCallback(std::bind(&WebDataService::write_temperature_sensor, this, _1, _2),
|
||||
securityManager->wrapCallback([this](AsyncWebServerRequest * request,
|
||||
JsonVariant json) { write_temperature_sensor(request, json); },
|
||||
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)) {
|
||||
securityManager->wrapCallback([this](AsyncWebServerRequest * request, JsonVariant json) { write_analog_sensor(request, json); },
|
||||
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));
|
||||
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { device_data(request); }, AuthenticationPredicates::IS_AUTHENTICATED));
|
||||
|
||||
|
||||
server->on(CORE_DATA_SERVICE_PATH,
|
||||
HTTP_GET,
|
||||
securityManager->wrapRequest(std::bind(&WebDataService::core_data, this, _1), AuthenticationPredicates::IS_AUTHENTICATED));
|
||||
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { core_data(request); }, AuthenticationPredicates::IS_AUTHENTICATED));
|
||||
|
||||
server->on(SENSOR_DATA_SERVICE_PATH,
|
||||
HTTP_GET,
|
||||
securityManager->wrapRequest(std::bind(&WebDataService::sensor_data, this, _1), AuthenticationPredicates::IS_AUTHENTICATED));
|
||||
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { sensor_data(request); }, 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));
|
||||
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { scan_devices(request); }, AuthenticationPredicates::IS_ADMIN));
|
||||
|
||||
|
||||
_write_value_handler.setMethod(HTTP_POST);
|
||||
_write_value_handler.setMaxContentLength(256);
|
||||
|
||||
@@ -18,19 +18,18 @@
|
||||
|
||||
#include "emsesp.h"
|
||||
|
||||
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)) {
|
||||
, setValues_(LOG_SETTINGS_PATH, [this](AsyncWebServerRequest * request, JsonVariant json) { setValues(request, json); }) {
|
||||
events_.setFilter(securityManager->filterRequest(AuthenticationPredicates::IS_ADMIN));
|
||||
|
||||
server->on(LOG_SETTINGS_PATH, HTTP_GET, std::bind(&WebLogService::getValues, this, _1)); // get settings
|
||||
// get settings
|
||||
server->on(LOG_SETTINGS_PATH, HTTP_POST, [this](AsyncWebServerRequest * request) { getValues(request); });
|
||||
|
||||
// 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));
|
||||
server->on(FETCH_LOG_PATH, HTTP_POST, [this](AsyncWebServerRequest * request) { fetchLog(request); });
|
||||
|
||||
server->addHandler(&setValues_);
|
||||
server->addHandler(&events_);
|
||||
|
||||
@@ -21,8 +21,6 @@
|
||||
|
||||
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) {
|
||||
|
||||
@@ -22,17 +22,13 @@ namespace emsesp {
|
||||
|
||||
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)
|
||||
, _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([&] { onUpdate(); }, false);
|
||||
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { board_profile(request); }, AuthenticationPredicates::IS_AUTHENTICATED));
|
||||
addUpdateHandler([this] { onUpdate(); }, false);
|
||||
}
|
||||
|
||||
void WebSettings::read(WebSettings & settings, JsonObject root) {
|
||||
|
||||
@@ -18,14 +18,12 @@
|
||||
|
||||
#include "emsesp.h"
|
||||
|
||||
using namespace std::placeholders; // for `_1` etc
|
||||
|
||||
namespace emsesp {
|
||||
|
||||
WebStatusService::WebStatusService(AsyncWebServer * server, SecurityManager * securityManager) {
|
||||
server->on(EMSESP_STATUS_SERVICE_PATH,
|
||||
HTTP_GET,
|
||||
securityManager->wrapRequest(std::bind(&WebStatusService::webStatusService, this, _1), AuthenticationPredicates::IS_AUTHENTICATED));
|
||||
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { webStatusService(request); }, AuthenticationPredicates::IS_AUTHENTICATED));
|
||||
}
|
||||
|
||||
void WebStatusService::webStatusService(AsyncWebServerRequest * request) {
|
||||
|
||||
Reference in New Issue
Block a user