experimenting with some refactoring
This commit is contained in:
@ -1,86 +0,0 @@
|
||||
#include <APSettingsService.h>
|
||||
|
||||
APSettingsService::APSettingsService(AsyncWebServer* server, FS* fs, SecurityManager* securityManager) : AdminSettingsService(server, fs, securityManager, AP_SETTINGS_SERVICE_PATH, AP_SETTINGS_FILE) {
|
||||
onConfigUpdated();
|
||||
}
|
||||
|
||||
APSettingsService::~APSettingsService() {}
|
||||
|
||||
void APSettingsService::loop() {
|
||||
unsigned long currentMillis = millis();
|
||||
unsigned long manageElapsed = (unsigned long)(currentMillis - _lastManaged);
|
||||
if (manageElapsed >= MANAGE_NETWORK_DELAY){
|
||||
_lastManaged = currentMillis;
|
||||
manageAP();
|
||||
}
|
||||
handleDNS();
|
||||
}
|
||||
|
||||
void APSettingsService::manageAP() {
|
||||
WiFiMode_t currentWiFiMode = WiFi.getMode();
|
||||
if (_provisionMode == AP_MODE_ALWAYS || (_provisionMode == AP_MODE_DISCONNECTED && WiFi.status() != WL_CONNECTED)) {
|
||||
if (currentWiFiMode == WIFI_OFF || currentWiFiMode == WIFI_STA) {
|
||||
startAP();
|
||||
}
|
||||
} else {
|
||||
if (currentWiFiMode == WIFI_AP || currentWiFiMode == WIFI_AP_STA) {
|
||||
stopAP();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void APSettingsService::startAP() {
|
||||
Serial.println("Starting software access point");
|
||||
WiFi.softAP(_ssid.c_str(), _password.c_str());
|
||||
if (!_dnsServer) {
|
||||
IPAddress apIp = WiFi.softAPIP();
|
||||
Serial.print("Starting captive portal on ");
|
||||
Serial.println(apIp);
|
||||
_dnsServer = new DNSServer;
|
||||
_dnsServer->start(DNS_PORT, "*", apIp);
|
||||
}
|
||||
}
|
||||
|
||||
void APSettingsService::stopAP() {
|
||||
if (_dnsServer) {
|
||||
Serial.println("Stopping captive portal");
|
||||
_dnsServer->stop();
|
||||
delete _dnsServer;
|
||||
_dnsServer = nullptr;
|
||||
}
|
||||
Serial.println("Stopping software access point");
|
||||
WiFi.softAPdisconnect(true);
|
||||
}
|
||||
|
||||
void APSettingsService::handleDNS() {
|
||||
if (_dnsServer) {
|
||||
_dnsServer->processNextRequest();
|
||||
}
|
||||
}
|
||||
|
||||
void APSettingsService::readFromJsonObject(JsonObject& root) {
|
||||
_provisionMode = root["provision_mode"] | AP_MODE_ALWAYS;
|
||||
switch (_provisionMode) {
|
||||
case AP_MODE_ALWAYS:
|
||||
case AP_MODE_DISCONNECTED:
|
||||
case AP_MODE_NEVER:
|
||||
break;
|
||||
default:
|
||||
_provisionMode = AP_MODE_ALWAYS;
|
||||
}
|
||||
_ssid = root["ssid"] | AP_DEFAULT_SSID;
|
||||
_password = root["password"] | AP_DEFAULT_PASSWORD;
|
||||
}
|
||||
|
||||
void APSettingsService::writeToJsonObject(JsonObject& root) {
|
||||
root["provision_mode"] = _provisionMode;
|
||||
root["ssid"] = _ssid;
|
||||
root["password"] = _password;
|
||||
}
|
||||
|
||||
void APSettingsService::onConfigUpdated() {
|
||||
_lastManaged = millis() - MANAGE_NETWORK_DELAY;
|
||||
|
||||
// stop softAP - forces reconfiguration in loop()
|
||||
stopAP();
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
#ifndef APSettingsConfig_h
|
||||
#define APSettingsConfig_h
|
||||
|
||||
#include <SettingsService.h>
|
||||
#include <DNSServer.h>
|
||||
#include <IPAddress.h>
|
||||
|
||||
#define MANAGE_NETWORK_DELAY 10000
|
||||
|
||||
#define AP_MODE_ALWAYS 0
|
||||
#define AP_MODE_DISCONNECTED 1
|
||||
#define AP_MODE_NEVER 2
|
||||
|
||||
#define DNS_PORT 53
|
||||
|
||||
#define AP_DEFAULT_SSID "ssid"
|
||||
#define AP_DEFAULT_PASSWORD "password"
|
||||
|
||||
#define AP_SETTINGS_FILE "/config/apSettings.json"
|
||||
#define AP_SETTINGS_SERVICE_PATH "/rest/apSettings"
|
||||
|
||||
class APSettingsService : public AdminSettingsService {
|
||||
|
||||
public:
|
||||
|
||||
APSettingsService(AsyncWebServer* server, FS* fs, SecurityManager* securityManager);
|
||||
~APSettingsService();
|
||||
|
||||
void loop();
|
||||
|
||||
protected:
|
||||
|
||||
void readFromJsonObject(JsonObject& root);
|
||||
void writeToJsonObject(JsonObject& root);
|
||||
void onConfigUpdated();
|
||||
|
||||
private:
|
||||
|
||||
// access point settings
|
||||
uint8_t _provisionMode;
|
||||
String _ssid;
|
||||
String _password;
|
||||
|
||||
// for the mangement delay loop
|
||||
unsigned long _lastManaged;
|
||||
|
||||
// for the captive portal
|
||||
DNSServer *_dnsServer;
|
||||
|
||||
void manageAP();
|
||||
void startAP();
|
||||
void stopAP();
|
||||
void handleDNS();
|
||||
|
||||
};
|
||||
|
||||
#endif // end APSettingsConfig_h
|
@ -1,21 +0,0 @@
|
||||
#include <APStatus.h>
|
||||
|
||||
APStatus::APStatus(AsyncWebServer *server, SecurityManager* securityManager) : _server(server), _securityManager(securityManager) {
|
||||
_server->on(AP_STATUS_SERVICE_PATH, HTTP_GET,
|
||||
_securityManager->wrapRequest(std::bind(&APStatus::apStatus, this, std::placeholders::_1), AuthenticationPredicates::IS_AUTHENTICATED)
|
||||
);
|
||||
}
|
||||
|
||||
void APStatus::apStatus(AsyncWebServerRequest *request) {
|
||||
AsyncJsonResponse * response = new AsyncJsonResponse(MAX_AP_STATUS_SIZE);
|
||||
JsonObject root = response->getRoot();
|
||||
|
||||
WiFiMode_t currentWiFiMode = WiFi.getMode();
|
||||
root["active"] = (currentWiFiMode == WIFI_AP || currentWiFiMode == WIFI_AP_STA);
|
||||
root["ip_address"] = WiFi.softAPIP().toString();
|
||||
root["mac_address"] = WiFi.softAPmacAddress();
|
||||
root["station_num"] = WiFi.softAPgetStationNum();
|
||||
|
||||
response->setLength();
|
||||
request->send(response);
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
#ifndef APStatus_h
|
||||
#define APStatus_h
|
||||
|
||||
#if defined(ESP8266)
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <ESPAsyncTCP.h>
|
||||
#elif defined(ESP_PLATFORM)
|
||||
#include <WiFi.h>
|
||||
#include <AsyncTCP.h>
|
||||
#endif
|
||||
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <AsyncArduinoJson6.h>
|
||||
#include <IPAddress.h>
|
||||
#include <SecurityManager.h>
|
||||
|
||||
#define MAX_AP_STATUS_SIZE 1024
|
||||
#define AP_STATUS_SERVICE_PATH "/rest/apStatus"
|
||||
|
||||
class APStatus {
|
||||
|
||||
public:
|
||||
|
||||
APStatus(AsyncWebServer *server, SecurityManager* securityManager);
|
||||
|
||||
private:
|
||||
|
||||
AsyncWebServer* _server;
|
||||
SecurityManager* _securityManager;
|
||||
|
||||
void apStatus(AsyncWebServerRequest *request);
|
||||
|
||||
};
|
||||
|
||||
#endif // end APStatus_h
|
@ -1,143 +0,0 @@
|
||||
#include "ArduinoJsonJWT.h"
|
||||
|
||||
ArduinoJsonJWT::ArduinoJsonJWT(String secret) : _secret(secret) { }
|
||||
|
||||
void ArduinoJsonJWT::setSecret(String secret){
|
||||
_secret = secret;
|
||||
}
|
||||
|
||||
String ArduinoJsonJWT::getSecret(){
|
||||
return _secret;
|
||||
}
|
||||
|
||||
/*
|
||||
* ESP32 uses mbedtls, ESP2866 uses bearssl.
|
||||
*
|
||||
* Both come with decent HMAC implmentations 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];
|
||||
{
|
||||
#if defined(ESP_PLATFORM)
|
||||
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);
|
||||
#else
|
||||
br_hmac_key_context keyCtx;
|
||||
br_hmac_key_init(&keyCtx, &br_sha256_vtable, _secret.c_str(), _secret.length());
|
||||
br_hmac_context hmacCtx;
|
||||
br_hmac_init(&hmacCtx, &keyCtx, 0);
|
||||
br_hmac_update(&hmacCtx, payload.c_str(), payload.length());
|
||||
br_hmac_out(&hmacCtx, hmacResult);
|
||||
#endif
|
||||
}
|
||||
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());
|
||||
|
||||
// add the header to payload
|
||||
jwt = JWT_HEADER + '.' + jwt;
|
||||
|
||||
// add signature
|
||||
jwt += '.' + sign(jwt);
|
||||
|
||||
return jwt;
|
||||
}
|
||||
|
||||
void ArduinoJsonJWT::parseJWT(String jwt, JsonDocument &jsonDocument) {
|
||||
// clear json document before we begin, jsonDocument wil be null on failure
|
||||
jsonDocument.clear();
|
||||
|
||||
// must have the correct header and delimiter
|
||||
if (!jwt.startsWith(JWT_HEADER) || jwt.indexOf('.') != JWT_HEADER_SIZE) {
|
||||
return;
|
||||
}
|
||||
|
||||
// check there is a signature delimieter
|
||||
int signatureDelimiterIndex = jwt.lastIndexOf('.');
|
||||
if (signatureDelimiterIndex == JWT_HEADER_SIZE) {
|
||||
return;
|
||||
}
|
||||
|
||||
// check the signature is valid
|
||||
String signature = jwt.substring(signatureDelimiterIndex + 1);
|
||||
jwt = jwt.substring(0, signatureDelimiterIndex);
|
||||
if (sign(jwt) != signature){
|
||||
return;
|
||||
}
|
||||
|
||||
// decode payload
|
||||
jwt = jwt.substring(JWT_HEADER_SIZE + 1);
|
||||
jwt = decode(jwt);
|
||||
|
||||
// parse payload, clearing json document after failure
|
||||
DeserializationError error = deserializeJson(jsonDocument, jwt);
|
||||
if (error != DeserializationError::Ok || !jsonDocument.is<JsonObject>()){
|
||||
jsonDocument.clear();
|
||||
}
|
||||
}
|
||||
|
||||
String ArduinoJsonJWT::encode(const char *cstr, int inputLen) {
|
||||
// prepare encoder
|
||||
base64_encodestate _state;
|
||||
#if defined(ESP8266)
|
||||
base64_init_encodestate_nonewlines(&_state);
|
||||
size_t encodedLength = base64_encode_expected_len_nonewlines(inputLen) + 1;
|
||||
#elif defined(ESP_PLATFORM)
|
||||
base64_init_encodestate(&_state);
|
||||
size_t encodedLength = base64_encode_expected_len(inputLen) + 1;
|
||||
#endif
|
||||
// prepare buffer of correct length, returning an empty string on failure
|
||||
char* buffer = (char*) malloc(encodedLength * sizeof(char));
|
||||
if (buffer == nullptr) {
|
||||
return "";
|
||||
}
|
||||
|
||||
// encode to buffer
|
||||
int len = base64_encode_block(cstr, inputLen, &buffer[0], &_state);
|
||||
len += base64_encode_blockend(&buffer[len], &_state);
|
||||
buffer[len] = 0;
|
||||
|
||||
// convert to arduino string, freeing buffer
|
||||
String value = String(buffer);
|
||||
free(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);
|
||||
}
|
||||
value.replace('+', '-');
|
||||
value.replace('/', '_');
|
||||
|
||||
// return as string
|
||||
return value;
|
||||
}
|
||||
|
||||
String ArduinoJsonJWT::decode(String value) {
|
||||
// convert to standard base64
|
||||
value.replace('-', '+');
|
||||
value.replace( '_', '/');
|
||||
|
||||
// prepare buffer of correct length
|
||||
char buffer[base64_decode_expected_len(value.length()) + 1];
|
||||
|
||||
// decode
|
||||
int len = base64_decode_chars(value.c_str(), value.length(), &buffer[0]);
|
||||
buffer[len] = 0;
|
||||
|
||||
// return as string
|
||||
return String(buffer);
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
#ifndef ArduinoJsonJWT_H
|
||||
#define ArduinoJsonJWT_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <libb64/cdecode.h>
|
||||
#include <libb64/cencode.h>
|
||||
#if defined(ESP_PLATFORM)
|
||||
#include <mbedtls/md.h>
|
||||
#else
|
||||
#include <bearssl/bearssl_hmac.h>
|
||||
#endif
|
||||
|
||||
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);
|
||||
|
||||
void setSecret(String secret);
|
||||
String getSecret();
|
||||
|
||||
String buildJWT(JsonObject &payload);
|
||||
void parseJWT(String jwt, JsonDocument &jsonDocument);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
@ -1,167 +0,0 @@
|
||||
|
||||
/**
|
||||
* A copy of AsyncJson.h from ESPAsyncWebServer, updated for ArduinoJson6.
|
||||
*/
|
||||
|
||||
#ifndef ASYNC_ARDUINO_JSON_6_H
|
||||
#define ASYNC_ARDUINO_JSON_6_H
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
#include <WebResponseImpl.h>
|
||||
#include <ESPAsyncWebServer.h>
|
||||
|
||||
constexpr const char* JSON_MIMETYPE = "application/json";
|
||||
|
||||
class ChunkPrint : public Print {
|
||||
private:
|
||||
uint8_t* _destination;
|
||||
size_t _to_skip;
|
||||
size_t _to_write;
|
||||
size_t _pos;
|
||||
public:
|
||||
ChunkPrint(uint8_t* destination, size_t from, size_t len)
|
||||
: _destination(destination), _to_skip(from), _to_write(len), _pos{0} {}
|
||||
virtual ~ChunkPrint(){}
|
||||
size_t write(uint8_t c){
|
||||
if (_to_skip > 0) {
|
||||
_to_skip--;
|
||||
return 1;
|
||||
} else if (_to_write > 0) {
|
||||
_to_write--;
|
||||
_destination[_pos++] = c;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
size_t write(const uint8_t *buffer, size_t size) {
|
||||
size_t written = 0;
|
||||
while (written < size && write(buffer[written])) {
|
||||
written++;
|
||||
}
|
||||
return written;
|
||||
}
|
||||
};
|
||||
|
||||
class AsyncJsonResponse: public AsyncAbstractResponse {
|
||||
private:
|
||||
DynamicJsonDocument _jsonDocument;
|
||||
bool _isValid;
|
||||
JsonObject _root;
|
||||
|
||||
public:
|
||||
AsyncJsonResponse(int maxSize): _jsonDocument(maxSize), _isValid{false} {
|
||||
_code = 200;
|
||||
_contentType = JSON_MIMETYPE;
|
||||
_root = _jsonDocument.to<JsonObject>();
|
||||
}
|
||||
~AsyncJsonResponse() {}
|
||||
JsonObject getRoot() {
|
||||
return _root;
|
||||
}
|
||||
bool _sourceValid() const {
|
||||
return _isValid;
|
||||
}
|
||||
size_t setLength() {
|
||||
_contentLength = measureJson(_jsonDocument);
|
||||
if (_contentLength) { _isValid = true; }
|
||||
return _contentLength;
|
||||
}
|
||||
size_t getSize() {
|
||||
return _jsonDocument.size();
|
||||
}
|
||||
size_t _fillBuffer(uint8_t *data, size_t len){
|
||||
ChunkPrint dest(data, _sentLength, len);
|
||||
serializeJson(_jsonDocument, dest);
|
||||
return len;
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::function<void(AsyncWebServerRequest *request, JsonVariant json)> ArJsonRequestHandlerFunction;
|
||||
|
||||
class AsyncCallbackJsonWebHandler: public AsyncWebHandler {
|
||||
private:
|
||||
protected:
|
||||
const String _uri;
|
||||
WebRequestMethodComposite _method;
|
||||
ArJsonRequestHandlerFunction _onRequest;
|
||||
size_t _contentLength;
|
||||
size_t _maxContentLength;
|
||||
public:
|
||||
AsyncCallbackJsonWebHandler(const String& uri, ArJsonRequestHandlerFunction onRequest) : _uri(uri), _method(HTTP_POST|HTTP_PUT|HTTP_PATCH), _onRequest(onRequest), _maxContentLength(16384) {}
|
||||
void setMethod(WebRequestMethodComposite method){ _method = method; }
|
||||
void setMaxContentLength(int maxContentLength){ _maxContentLength = maxContentLength; }
|
||||
void onRequest(ArJsonRequestHandlerFunction fn){ _onRequest = fn; }
|
||||
virtual bool canHandle(AsyncWebServerRequest *request) override final{
|
||||
if(!_onRequest)
|
||||
return false;
|
||||
|
||||
if(!(_method & request->method()))
|
||||
return false;
|
||||
|
||||
if(_uri.length() && (_uri != request->url() && !request->url().startsWith(_uri+"/")))
|
||||
return false;
|
||||
|
||||
if (!request->contentType().equalsIgnoreCase(JSON_MIMETYPE))
|
||||
return false;
|
||||
|
||||
request->addInterestingHeader("ANY");
|
||||
return true;
|
||||
}
|
||||
virtual void handleRequest(AsyncWebServerRequest *request) override final {
|
||||
if(_onRequest) {
|
||||
if (request->_tempObject != nullptr) {
|
||||
DynamicJsonDocument _jsonDocument(_maxContentLength);
|
||||
DeserializationError err = deserializeJson(_jsonDocument, (uint8_t*)(request->_tempObject));
|
||||
if (err == DeserializationError::Ok) {
|
||||
_onRequest(request, _jsonDocument.as<JsonVariant>());
|
||||
return;
|
||||
}
|
||||
}
|
||||
request->send(_contentLength > _maxContentLength ? 413 : 400);
|
||||
} else {
|
||||
request->send(500);
|
||||
}
|
||||
}
|
||||
virtual void handleUpload(AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final) override final {
|
||||
}
|
||||
virtual void handleBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) override final {
|
||||
if (_onRequest) {
|
||||
_contentLength = total;
|
||||
if (total > 0 && request->_tempObject == nullptr && total < _maxContentLength) {
|
||||
request->_tempObject = malloc(total);
|
||||
}
|
||||
if (request->_tempObject != nullptr) {
|
||||
memcpy((uint8_t*)(request->_tempObject) + index, data, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual bool isRequestHandlerTrivial() override final {return _onRequest ? false : true;}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Listens for a response being destroyed and calls a callback during said distruction.
|
||||
*
|
||||
* Used so we can take action after the response has been rendered to the client.
|
||||
*
|
||||
* Avoids having to fork ESPAsyncWebServer with a callback feature - still not a nice use of a destructor!
|
||||
*/
|
||||
|
||||
typedef std::function<void()> AsyncJsonCallback;
|
||||
|
||||
class AsyncJsonCallbackResponse: public AsyncJsonResponse {
|
||||
|
||||
private:
|
||||
|
||||
AsyncJsonCallback _callback;
|
||||
|
||||
public:
|
||||
|
||||
AsyncJsonCallbackResponse(AsyncJsonCallback callback, int maxSize) : AsyncJsonResponse(maxSize), _callback{callback} {}
|
||||
~AsyncJsonCallbackResponse() {
|
||||
_callback();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
@ -1,120 +0,0 @@
|
||||
#ifndef Async_Json_Request_Web_Handler_H_
|
||||
#define Async_Json_Request_Web_Handler_H_
|
||||
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
#define ASYNC_JSON_REQUEST_DEFAULT_MAX_SIZE 1024
|
||||
#define ASYNC_JSON_REQUEST_MIMETYPE "application/json"
|
||||
|
||||
/*
|
||||
* Handy little utility for dealing with small JSON request body payloads.
|
||||
*
|
||||
* Need to be careful using this as we are somewhat limited by RAM.
|
||||
*
|
||||
* Really only of use where there is a determinate payload size.
|
||||
*/
|
||||
|
||||
typedef std::function<void(AsyncWebServerRequest *request, JsonDocument &jsonDocument)> JsonRequestCallback;
|
||||
|
||||
class AsyncJsonWebHandler: public AsyncWebHandler {
|
||||
|
||||
private:
|
||||
WebRequestMethodComposite _method;
|
||||
JsonRequestCallback _onRequest;
|
||||
size_t _maxContentLength;
|
||||
|
||||
protected:
|
||||
String _uri;
|
||||
|
||||
public:
|
||||
|
||||
AsyncJsonWebHandler() :
|
||||
_method(HTTP_POST|HTTP_PUT|HTTP_PATCH),
|
||||
_onRequest(nullptr),
|
||||
_maxContentLength(ASYNC_JSON_REQUEST_DEFAULT_MAX_SIZE),
|
||||
_uri() {}
|
||||
|
||||
~AsyncJsonWebHandler() {}
|
||||
|
||||
void setUri(const String& uri) { _uri = uri; }
|
||||
void setMethod(WebRequestMethodComposite method) { _method = method; }
|
||||
void setMaxContentLength(size_t maxContentLength) { _maxContentLength = maxContentLength; }
|
||||
void onRequest(JsonRequestCallback fn) { _onRequest = fn; }
|
||||
|
||||
virtual bool canHandle(AsyncWebServerRequest *request) override final {
|
||||
if(!_onRequest)
|
||||
return false;
|
||||
|
||||
if(!(_method & request->method()))
|
||||
return false;
|
||||
|
||||
if(_uri.length() && (_uri != request->url() && !request->url().startsWith(_uri+"/")))
|
||||
return false;
|
||||
|
||||
if (!request->contentType().equalsIgnoreCase(ASYNC_JSON_REQUEST_MIMETYPE))
|
||||
return false;
|
||||
|
||||
request->addInterestingHeader("ANY");
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void handleRequest(AsyncWebServerRequest *request) override final {
|
||||
// no request configured
|
||||
if(!_onRequest) {
|
||||
Serial.print("No request callback was configured for endpoint: ");
|
||||
Serial.println(_uri);
|
||||
request->send(500);
|
||||
return;
|
||||
}
|
||||
|
||||
// we have been handed too much data, return a 413 (payload too large)
|
||||
if (request->contentLength() > _maxContentLength) {
|
||||
request->send(413);
|
||||
return;
|
||||
}
|
||||
|
||||
// parse JSON and if possible handle the request
|
||||
if (request->_tempObject) {
|
||||
DynamicJsonDocument jsonDocument(_maxContentLength);
|
||||
DeserializationError error = deserializeJson(jsonDocument, (uint8_t *) request->_tempObject);
|
||||
if (error == DeserializationError::Ok) {
|
||||
_onRequest(request, jsonDocument);
|
||||
}else{
|
||||
request->send(400);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// fallthrough, we have a null pointer, return 500.
|
||||
// this can be due to running out of memory or never receiving body data.
|
||||
request->send(500);
|
||||
}
|
||||
|
||||
virtual void handleBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) override final {
|
||||
if (_onRequest) {
|
||||
// don't allocate if data is too large
|
||||
if (total > _maxContentLength){
|
||||
return;
|
||||
}
|
||||
|
||||
// try to allocate memory on first call
|
||||
// NB: the memory allocated here is freed by ~AsyncWebServerRequest
|
||||
if(index == 0 && !request->_tempObject){
|
||||
request->_tempObject = malloc(total);
|
||||
}
|
||||
|
||||
// copy the data into the buffer, if we have a buffer!
|
||||
if (request->_tempObject) {
|
||||
memcpy((uint8_t *) request->_tempObject+index, data, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool isRequestHandlerTrivial() override final {
|
||||
return _onRequest ? false : true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif // end Async_Json_Request_Web_Handler_H_
|
@ -1,45 +0,0 @@
|
||||
#include <AuthenticationService.h>
|
||||
|
||||
AuthenticationService::AuthenticationService(AsyncWebServer* server, SecurityManager* securityManager):
|
||||
_server(server), _securityManager(securityManager) {
|
||||
server->on(VERIFY_AUTHORIZATION_PATH, HTTP_GET, std::bind(&AuthenticationService::verifyAuthorization, this, std::placeholders::_1));
|
||||
|
||||
_signInHandler.setUri(SIGN_IN_PATH);
|
||||
_signInHandler.setMethod(HTTP_POST);
|
||||
_signInHandler.setMaxContentLength(MAX_AUTHENTICATION_SIZE);
|
||||
_signInHandler.onRequest(std::bind(&AuthenticationService::signIn, this, std::placeholders::_1, std::placeholders::_2));
|
||||
server->addHandler(&_signInHandler);
|
||||
}
|
||||
|
||||
AuthenticationService::~AuthenticationService() {}
|
||||
|
||||
/**
|
||||
* Verifys that the request supplied a valid JWT.
|
||||
*/
|
||||
void AuthenticationService::verifyAuthorization(AsyncWebServerRequest *request) {
|
||||
Authentication authentication = _securityManager->authenticateRequest(request);
|
||||
request->send(authentication.isAuthenticated() ? 200: 401);
|
||||
}
|
||||
|
||||
/**
|
||||
* Signs in a user if the username and password match. Provides a JWT to be used in the Authorization header in subsequent requests.
|
||||
*/
|
||||
void AuthenticationService::signIn(AsyncWebServerRequest *request, JsonDocument &jsonDocument){
|
||||
if (jsonDocument.is<JsonObject>()) {
|
||||
String username = jsonDocument["username"];
|
||||
String password = jsonDocument["password"];
|
||||
Authentication authentication = _securityManager->authenticate(username, password);
|
||||
if (authentication.isAuthenticated()) {
|
||||
User* user = authentication.getUser();
|
||||
AsyncJsonResponse * response = new AsyncJsonResponse(MAX_AUTHENTICATION_SIZE);
|
||||
JsonObject jsonObject = response->getRoot();
|
||||
jsonObject["access_token"] = _securityManager->generateJWT(user);
|
||||
response->setLength();
|
||||
request->send(response);
|
||||
return;
|
||||
}
|
||||
}
|
||||
AsyncWebServerResponse *response = request->beginResponse(401);
|
||||
request->send(response);
|
||||
}
|
||||
|
@ -1,33 +0,0 @@
|
||||
#ifndef AuthenticationService_H_
|
||||
#define AuthenticationService_H_
|
||||
|
||||
#include <SecurityManager.h>
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <AsyncJsonWebHandler.h>
|
||||
#include <AsyncArduinoJson6.h>
|
||||
|
||||
#define VERIFY_AUTHORIZATION_PATH "/rest/verifyAuthorization"
|
||||
#define SIGN_IN_PATH "/rest/signIn"
|
||||
|
||||
#define MAX_AUTHENTICATION_SIZE 256
|
||||
|
||||
class AuthenticationService {
|
||||
|
||||
public:
|
||||
|
||||
AuthenticationService(AsyncWebServer* server, SecurityManager* securityManager) ;
|
||||
~AuthenticationService();
|
||||
|
||||
private:
|
||||
// server instance
|
||||
AsyncWebServer* _server;
|
||||
SecurityManager* _securityManager;
|
||||
AsyncJsonWebHandler _signInHandler;
|
||||
|
||||
// endpoint functions
|
||||
void signIn(AsyncWebServerRequest *request, JsonDocument &jsonDocument);
|
||||
void verifyAuthorization(AsyncWebServerRequest *request);
|
||||
|
||||
};
|
||||
|
||||
#endif // end SecurityManager_h
|
9
src/DemoProject.cpp
Normal file
9
src/DemoProject.cpp
Normal file
@ -0,0 +1,9 @@
|
||||
#include <DemoProject.h>
|
||||
|
||||
void DemoProject::begin() {
|
||||
|
||||
}
|
||||
|
||||
void DemoProject::loop() {
|
||||
|
||||
}
|
23
src/DemoProject.h
Normal file
23
src/DemoProject.h
Normal file
@ -0,0 +1,23 @@
|
||||
#ifndef DemoProject_h
|
||||
#define DemoProject_h
|
||||
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <SecurityManager.h>
|
||||
|
||||
class DemoProject {
|
||||
|
||||
public:
|
||||
|
||||
DemoProject(AsyncWebServer *server, SecurityManager* securityManager) : _server(server), _securityManager(securityManager) {}
|
||||
|
||||
void begin();
|
||||
void loop();
|
||||
|
||||
private:
|
||||
|
||||
AsyncWebServer* _server;
|
||||
SecurityManager* _securityManager;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
@ -1,111 +0,0 @@
|
||||
#include <NTPSettingsService.h>
|
||||
|
||||
NTPSettingsService::NTPSettingsService(AsyncWebServer* server, FS* fs, SecurityManager* securityManager) : AdminSettingsService(server, fs, securityManager, NTP_SETTINGS_SERVICE_PATH, NTP_SETTINGS_FILE) {
|
||||
|
||||
#if defined(ESP8266)
|
||||
_onStationModeDisconnectedHandler = WiFi.onStationModeDisconnected(std::bind(&NTPSettingsService::onStationModeDisconnected, this, std::placeholders::_1));
|
||||
_onStationModeGotIPHandler = WiFi.onStationModeGotIP(std::bind(&NTPSettingsService::onStationModeGotIP, this, std::placeholders::_1));
|
||||
#elif defined(ESP_PLATFORM)
|
||||
WiFi.onEvent(std::bind(&NTPSettingsService::onStationModeDisconnected, this, std::placeholders::_1, std::placeholders::_2), WiFiEvent_t::SYSTEM_EVENT_STA_DISCONNECTED);
|
||||
WiFi.onEvent(std::bind(&NTPSettingsService::onStationModeGotIP, this, std::placeholders::_1, std::placeholders::_2), WiFiEvent_t::SYSTEM_EVENT_STA_GOT_IP);
|
||||
#endif
|
||||
|
||||
NTP.onNTPSyncEvent ([this](NTPSyncEvent_t ntpEvent) {
|
||||
_ntpEvent = ntpEvent;
|
||||
_syncEventTriggered = true;
|
||||
});
|
||||
}
|
||||
|
||||
NTPSettingsService::~NTPSettingsService() {}
|
||||
|
||||
void NTPSettingsService::loop() {
|
||||
// detect when we need to re-configure NTP and do it in the main loop
|
||||
if (_reconfigureNTP) {
|
||||
_reconfigureNTP = false;
|
||||
configureNTP();
|
||||
}
|
||||
|
||||
// output sync event to serial
|
||||
if (_syncEventTriggered) {
|
||||
processSyncEvent(_ntpEvent);
|
||||
_syncEventTriggered = false;
|
||||
}
|
||||
|
||||
// keep time synchronized in background
|
||||
now();
|
||||
}
|
||||
|
||||
void NTPSettingsService::readFromJsonObject(JsonObject& root) {
|
||||
_server = root["server"] | NTP_SETTINGS_SERVICE_DEFAULT_SERVER;
|
||||
_interval = root["interval"];
|
||||
|
||||
// validate server is specified, resorting to default
|
||||
_server.trim();
|
||||
if (!_server){
|
||||
_server = NTP_SETTINGS_SERVICE_DEFAULT_SERVER;
|
||||
}
|
||||
|
||||
// make sure interval is in bounds
|
||||
if (_interval < NTP_SETTINGS_MIN_INTERVAL){
|
||||
_interval = NTP_SETTINGS_MIN_INTERVAL;
|
||||
} else if (_interval > NTP_SETTINGS_MAX_INTERVAL) {
|
||||
_interval = NTP_SETTINGS_MAX_INTERVAL;
|
||||
}
|
||||
}
|
||||
|
||||
void NTPSettingsService::writeToJsonObject(JsonObject& root) {
|
||||
root["server"] = _server;
|
||||
root["interval"] = _interval;
|
||||
}
|
||||
|
||||
void NTPSettingsService::onConfigUpdated() {
|
||||
_reconfigureNTP = true;
|
||||
}
|
||||
|
||||
#if defined(ESP8266)
|
||||
void NTPSettingsService::onStationModeGotIP(const WiFiEventStationModeGotIP& event) {
|
||||
Serial.printf("Got IP address, starting NTP Synchronization\n");
|
||||
_reconfigureNTP = true;
|
||||
}
|
||||
|
||||
void NTPSettingsService::onStationModeDisconnected(const WiFiEventStationModeDisconnected& event) {
|
||||
Serial.printf("WiFi connection dropped, stopping NTP.\n");
|
||||
_reconfigureNTP = false;
|
||||
NTP.stop();
|
||||
}
|
||||
#elif defined(ESP_PLATFORM)
|
||||
void NTPSettingsService::onStationModeGotIP(WiFiEvent_t event, WiFiEventInfo_t info) {
|
||||
Serial.printf("Got IP address, starting NTP Synchronization\n");
|
||||
_reconfigureNTP = true;
|
||||
}
|
||||
|
||||
void NTPSettingsService::onStationModeDisconnected(WiFiEvent_t event, WiFiEventInfo_t info) {
|
||||
Serial.printf("WiFi connection dropped, stopping NTP.\n");
|
||||
_reconfigureNTP = false;
|
||||
NTP.stop();
|
||||
}
|
||||
#endif
|
||||
|
||||
void NTPSettingsService::configureNTP() {
|
||||
Serial.println("Configuring NTP...");
|
||||
|
||||
// disable sync
|
||||
NTP.stop();
|
||||
|
||||
// enable sync
|
||||
NTP.begin(_server);
|
||||
NTP.setInterval(_interval);
|
||||
}
|
||||
|
||||
void NTPSettingsService::processSyncEvent(NTPSyncEvent_t ntpEvent) {
|
||||
if (ntpEvent) {
|
||||
Serial.print ("Time Sync error: ");
|
||||
if (ntpEvent == noResponse)
|
||||
Serial.println ("NTP server not reachable");
|
||||
else if (ntpEvent == invalidAddress)
|
||||
Serial.println ("Invalid NTP server address");
|
||||
} else {
|
||||
Serial.print ("Got NTP time: ");
|
||||
Serial.println (NTP.getTimeDateString (NTP.getLastNTPSync ()));
|
||||
}
|
||||
}
|
@ -1,60 +0,0 @@
|
||||
#ifndef NTPSettingsService_h
|
||||
#define NTPSettingsService_h
|
||||
|
||||
#include <SettingsService.h>
|
||||
|
||||
#include <TimeLib.h>
|
||||
#include <NtpClientLib.h>
|
||||
|
||||
// default time server
|
||||
#define NTP_SETTINGS_SERVICE_DEFAULT_SERVER "pool.ntp.org"
|
||||
#define NTP_SETTINGS_SERVICE_DEFAULT_INTERVAL 3600
|
||||
|
||||
// min poll delay of 60 secs, max 1 day
|
||||
#define NTP_SETTINGS_MIN_INTERVAL 60
|
||||
#define NTP_SETTINGS_MAX_INTERVAL 86400
|
||||
|
||||
#define NTP_SETTINGS_FILE "/config/ntpSettings.json"
|
||||
#define NTP_SETTINGS_SERVICE_PATH "/rest/ntpSettings"
|
||||
|
||||
class NTPSettingsService : public AdminSettingsService {
|
||||
|
||||
public:
|
||||
|
||||
NTPSettingsService(AsyncWebServer* server, FS* fs, SecurityManager* securityManager);
|
||||
~NTPSettingsService();
|
||||
|
||||
void loop();
|
||||
|
||||
protected:
|
||||
|
||||
void readFromJsonObject(JsonObject& root);
|
||||
void writeToJsonObject(JsonObject& root);
|
||||
void onConfigUpdated();
|
||||
|
||||
private:
|
||||
|
||||
String _server;
|
||||
int _interval;
|
||||
|
||||
bool _reconfigureNTP = false;
|
||||
bool _syncEventTriggered = false;
|
||||
NTPSyncEvent_t _ntpEvent;
|
||||
|
||||
#if defined(ESP8266)
|
||||
WiFiEventHandler _onStationModeDisconnectedHandler;
|
||||
WiFiEventHandler _onStationModeGotIPHandler;
|
||||
|
||||
void onStationModeGotIP(const WiFiEventStationModeGotIP& event);
|
||||
void onStationModeDisconnected(const WiFiEventStationModeDisconnected& event);
|
||||
#elif defined(ESP_PLATFORM)
|
||||
void onStationModeGotIP(WiFiEvent_t event, WiFiEventInfo_t info);
|
||||
void onStationModeDisconnected(WiFiEvent_t event, WiFiEventInfo_t info);
|
||||
#endif
|
||||
|
||||
void configureNTP();
|
||||
void processSyncEvent(NTPSyncEvent_t ntpEvent);
|
||||
|
||||
};
|
||||
|
||||
#endif // end NTPSettingsService_h
|
@ -1,30 +0,0 @@
|
||||
#include <NTPStatus.h>
|
||||
|
||||
NTPStatus::NTPStatus(AsyncWebServer *server, SecurityManager* securityManager) : _server(server), _securityManager(securityManager) {
|
||||
_server->on(NTP_STATUS_SERVICE_PATH, HTTP_GET,
|
||||
_securityManager->wrapRequest(std::bind(&NTPStatus::ntpStatus, this, std::placeholders::_1), AuthenticationPredicates::IS_AUTHENTICATED)
|
||||
);
|
||||
}
|
||||
|
||||
void NTPStatus::ntpStatus(AsyncWebServerRequest *request) {
|
||||
AsyncJsonResponse * response = new AsyncJsonResponse(MAX_NTP_STATUS_SIZE);
|
||||
JsonObject root = response->getRoot();
|
||||
|
||||
// request time now first, this can sometimes force a sync
|
||||
time_t timeNow = now();
|
||||
timeStatus_t status = timeStatus();
|
||||
time_t lastSync = NTP.getLastNTPSync();
|
||||
root["status"] = (int) status;
|
||||
root["last_sync"] = lastSync;
|
||||
root["server"] = NTP.getNtpServerName();
|
||||
root["interval"] = NTP.getInterval();
|
||||
root["uptime"] = NTP.getUptime();
|
||||
|
||||
// only add now to response if we have successfully synced
|
||||
if (status != timeNotSet){
|
||||
root["now"] = timeNow;
|
||||
}
|
||||
|
||||
response->setLength();
|
||||
request->send(response);
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
#ifndef NTPStatus_h
|
||||
#define NTPStatus_h
|
||||
|
||||
#if defined(ESP8266)
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <ESPAsyncTCP.h>
|
||||
#elif defined(ESP_PLATFORM)
|
||||
#include <WiFi.h>
|
||||
#include <AsyncTCP.h>
|
||||
#endif
|
||||
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <AsyncArduinoJson6.h>
|
||||
#include <TimeLib.h>
|
||||
#include <NtpClientLib.h>
|
||||
#include <SecurityManager.h>
|
||||
|
||||
#define MAX_NTP_STATUS_SIZE 1024
|
||||
#define NTP_STATUS_SERVICE_PATH "/rest/ntpStatus"
|
||||
|
||||
class NTPStatus {
|
||||
|
||||
public:
|
||||
|
||||
NTPStatus(AsyncWebServer *server, SecurityManager* securityManager);
|
||||
|
||||
private:
|
||||
|
||||
AsyncWebServer* _server;
|
||||
SecurityManager* _securityManager;
|
||||
|
||||
void ntpStatus(AsyncWebServerRequest *request);
|
||||
|
||||
};
|
||||
|
||||
#endif // end NTPStatus_h
|
@ -1,82 +0,0 @@
|
||||
#include <OTASettingsService.h>
|
||||
|
||||
OTASettingsService::OTASettingsService(AsyncWebServer* server, FS* fs, SecurityManager* securityManager) : AdminSettingsService(server, fs, securityManager, OTA_SETTINGS_SERVICE_PATH, OTA_SETTINGS_FILE) {
|
||||
#if defined(ESP8266)
|
||||
_onStationModeGotIPHandler = WiFi.onStationModeGotIP(std::bind(&OTASettingsService::onStationModeGotIP, this, std::placeholders::_1));
|
||||
#elif defined(ESP_PLATFORM)
|
||||
WiFi.onEvent(std::bind(&OTASettingsService::onStationModeGotIP, this, std::placeholders::_1, std::placeholders::_2), WiFiEvent_t::SYSTEM_EVENT_STA_GOT_IP);
|
||||
#endif
|
||||
}
|
||||
|
||||
OTASettingsService::~OTASettingsService() {}
|
||||
|
||||
void OTASettingsService::loop() {
|
||||
if (_enabled && _arduinoOTA){
|
||||
_arduinoOTA->handle();
|
||||
}
|
||||
}
|
||||
|
||||
void OTASettingsService::onConfigUpdated() {
|
||||
configureArduinoOTA();
|
||||
}
|
||||
|
||||
void OTASettingsService::readFromJsonObject(JsonObject& root) {
|
||||
_enabled = root["enabled"];
|
||||
_port = root["port"];
|
||||
_password = root["password"] | DEFAULT_OTA_PASSWORD;
|
||||
|
||||
// provide defaults
|
||||
if (_port < 0){
|
||||
_port = DEFAULT_OTA_PORT;
|
||||
}
|
||||
}
|
||||
|
||||
void OTASettingsService::writeToJsonObject(JsonObject& root) {
|
||||
root["enabled"] = _enabled;
|
||||
root["port"] = _port;
|
||||
root["password"] = _password;
|
||||
}
|
||||
|
||||
void OTASettingsService::configureArduinoOTA() {
|
||||
if (_arduinoOTA){
|
||||
#if defined(ESP_PLATFORM)
|
||||
_arduinoOTA->end();
|
||||
#endif
|
||||
delete _arduinoOTA;
|
||||
_arduinoOTA = nullptr;
|
||||
}
|
||||
if (_enabled) {
|
||||
Serial.println("Starting OTA Update Service");
|
||||
_arduinoOTA = new ArduinoOTAClass;
|
||||
_arduinoOTA->setPort(_port);
|
||||
_arduinoOTA->setPassword(_password.c_str());
|
||||
_arduinoOTA->onStart([]() {
|
||||
Serial.println("Starting");
|
||||
});
|
||||
_arduinoOTA->onEnd([]() {
|
||||
Serial.println("\nEnd");
|
||||
});
|
||||
_arduinoOTA->onProgress([](unsigned int progress, unsigned int total) {
|
||||
Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
|
||||
});
|
||||
_arduinoOTA->onError([](ota_error_t error) {
|
||||
Serial.printf("Error[%u]: ", error);
|
||||
if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
|
||||
else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
|
||||
else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
|
||||
else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
|
||||
else if (error == OTA_END_ERROR) Serial.println("End Failed");
|
||||
});
|
||||
_arduinoOTA->begin();
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(ESP8266)
|
||||
void OTASettingsService::onStationModeGotIP(const WiFiEventStationModeGotIP& event) {
|
||||
configureArduinoOTA();
|
||||
}
|
||||
#elif defined(ESP_PLATFORM)
|
||||
void OTASettingsService::onStationModeGotIP(WiFiEvent_t event, WiFiEventInfo_t info) {
|
||||
configureArduinoOTA();
|
||||
}
|
||||
#endif
|
@ -1,55 +0,0 @@
|
||||
#ifndef OTASettingsService_h
|
||||
#define OTASettingsService_h
|
||||
|
||||
#include <SettingsService.h>
|
||||
|
||||
#if defined(ESP8266)
|
||||
#include <ESP8266mDNS.h>
|
||||
#elif defined(ESP_PLATFORM)
|
||||
#include <ESPmDNS.h>
|
||||
#endif
|
||||
|
||||
#include <WiFiUdp.h>
|
||||
#include <ArduinoOTA.h>
|
||||
|
||||
// Emergency defaults
|
||||
#define DEFAULT_OTA_PORT 8266
|
||||
#define DEFAULT_OTA_PASSWORD "esp-react"
|
||||
|
||||
#define OTA_SETTINGS_FILE "/config/otaSettings.json"
|
||||
#define OTA_SETTINGS_SERVICE_PATH "/rest/otaSettings"
|
||||
|
||||
class OTASettingsService : public AdminSettingsService {
|
||||
|
||||
public:
|
||||
|
||||
OTASettingsService(AsyncWebServer* server, FS* fs, SecurityManager* securityManager);
|
||||
~OTASettingsService();
|
||||
|
||||
void loop();
|
||||
|
||||
protected:
|
||||
|
||||
void onConfigUpdated();
|
||||
void readFromJsonObject(JsonObject& root);
|
||||
void writeToJsonObject(JsonObject& root);
|
||||
|
||||
private:
|
||||
|
||||
ArduinoOTAClass *_arduinoOTA;
|
||||
bool _enabled;
|
||||
int _port;
|
||||
String _password;
|
||||
|
||||
void configureArduinoOTA();
|
||||
|
||||
#if defined(ESP8266)
|
||||
WiFiEventHandler _onStationModeGotIPHandler;
|
||||
void onStationModeGotIP(const WiFiEventStationModeGotIP& event);
|
||||
#elif defined(ESP_PLATFORM)
|
||||
void onStationModeGotIP(WiFiEvent_t event, WiFiEventInfo_t info);
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
#endif // end NTPSettingsService_h
|
@ -1,68 +0,0 @@
|
||||
#include <SecurityManager.h>
|
||||
|
||||
Authentication SecurityManager::authenticateRequest(AsyncWebServerRequest *request) {
|
||||
AsyncWebHeader* authorizationHeader = request->getHeader(AUTHORIZATION_HEADER);
|
||||
if (authorizationHeader) {
|
||||
String value = authorizationHeader->value();
|
||||
if (value.startsWith(AUTHORIZATION_HEADER_PREFIX)){
|
||||
value = value.substring(AUTHORIZATION_HEADER_PREFIX_LEN);
|
||||
return authenticateJWT(value);
|
||||
}
|
||||
}
|
||||
return Authentication();
|
||||
}
|
||||
|
||||
Authentication SecurityManager::authenticateJWT(String jwt) {
|
||||
DynamicJsonDocument payloadDocument(MAX_JWT_SIZE);
|
||||
_jwtHandler.parseJWT(jwt, payloadDocument);
|
||||
if (payloadDocument.is<JsonObject>()) {
|
||||
JsonObject parsedPayload = payloadDocument.as<JsonObject>();
|
||||
String username = parsedPayload["username"];
|
||||
for (User _user : _users) {
|
||||
if (_user.getUsername() == username && validatePayload(parsedPayload, &_user)){
|
||||
return Authentication(_user);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Authentication();
|
||||
}
|
||||
|
||||
Authentication SecurityManager::authenticate(String username, String password) {
|
||||
for (User _user : _users) {
|
||||
if (_user.getUsername() == username && _user.getPassword() == password){
|
||||
return Authentication(_user);
|
||||
}
|
||||
}
|
||||
return Authentication();
|
||||
}
|
||||
|
||||
inline void populateJWTPayload(JsonObject &payload, User *user) {
|
||||
payload["username"] = user->getUsername();
|
||||
payload["admin"] = user -> isAdmin();
|
||||
}
|
||||
|
||||
boolean SecurityManager::validatePayload(JsonObject &parsedPayload, User *user) {
|
||||
DynamicJsonDocument _jsonDocument(MAX_JWT_SIZE);
|
||||
JsonObject payload = _jsonDocument.to<JsonObject>();
|
||||
populateJWTPayload(payload, user);
|
||||
return payload == parsedPayload;
|
||||
}
|
||||
|
||||
String SecurityManager::generateJWT(User *user) {
|
||||
DynamicJsonDocument _jsonDocument(MAX_JWT_SIZE);
|
||||
JsonObject payload = _jsonDocument.to<JsonObject>();
|
||||
populateJWTPayload(payload, user);
|
||||
return _jwtHandler.buildJWT(payload);
|
||||
}
|
||||
|
||||
ArRequestHandlerFunction SecurityManager::wrapRequest(ArRequestHandlerFunction onRequest, AuthenticationPredicate predicate) {
|
||||
return [this, onRequest, predicate](AsyncWebServerRequest *request){
|
||||
Authentication authentication = authenticateRequest(request);
|
||||
if (!predicate(authentication)) {
|
||||
request->send(401);
|
||||
return;
|
||||
}
|
||||
onRequest(request);
|
||||
};
|
||||
}
|
||||
|
@ -1,110 +0,0 @@
|
||||
#ifndef SecurityManager_h
|
||||
#define SecurityManager_h
|
||||
|
||||
#include <list>
|
||||
#include <ArduinoJsonJWT.h>
|
||||
#include <ESPAsyncWebServer.h>
|
||||
|
||||
#define DEFAULT_JWT_SECRET "esp8266-react"
|
||||
|
||||
#define AUTHORIZATION_HEADER "Authorization"
|
||||
#define AUTHORIZATION_HEADER_PREFIX "Bearer "
|
||||
#define AUTHORIZATION_HEADER_PREFIX_LEN 7
|
||||
|
||||
#define MAX_JWT_SIZE 128
|
||||
|
||||
class User {
|
||||
private:
|
||||
String _username;
|
||||
String _password;
|
||||
bool _admin;
|
||||
public:
|
||||
User(String username, String password, bool admin): _username(username), _password(password), _admin(admin) {}
|
||||
String getUsername() {
|
||||
return _username;
|
||||
}
|
||||
String getPassword() {
|
||||
return _password;
|
||||
}
|
||||
bool isAdmin() {
|
||||
return _admin;
|
||||
}
|
||||
};
|
||||
|
||||
class Authentication {
|
||||
private:
|
||||
User *_user;
|
||||
boolean _authenticated;
|
||||
public:
|
||||
Authentication(User& user): _user(new User(user)), _authenticated(true) {}
|
||||
Authentication() : _user(nullptr), _authenticated(false) {}
|
||||
~Authentication() {
|
||||
delete(_user);
|
||||
}
|
||||
User* getUser() {
|
||||
return _user;
|
||||
}
|
||||
bool isAuthenticated() {
|
||||
return _authenticated;
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::function<boolean(Authentication &authentication)> AuthenticationPredicate;
|
||||
|
||||
class AuthenticationPredicates {
|
||||
public:
|
||||
static bool NONE_REQUIRED(Authentication &authentication) {
|
||||
return true;
|
||||
};
|
||||
static bool IS_AUTHENTICATED(Authentication &authentication) {
|
||||
return authentication.isAuthenticated();
|
||||
};
|
||||
static bool IS_ADMIN(Authentication &authentication) {
|
||||
return authentication.isAuthenticated() && authentication.getUser()->isAdmin();
|
||||
};
|
||||
};
|
||||
|
||||
class SecurityManager {
|
||||
|
||||
public:
|
||||
|
||||
/*
|
||||
* Authenticate, returning the user if found
|
||||
*/
|
||||
Authentication authenticate(String username, String password);
|
||||
|
||||
/*
|
||||
* Check the request header for the Authorization token
|
||||
*/
|
||||
Authentication authenticateRequest(AsyncWebServerRequest *request);
|
||||
|
||||
/*
|
||||
* Generate a JWT for the user provided
|
||||
*/
|
||||
String generateJWT(User *user);
|
||||
|
||||
/**
|
||||
* Wrap the provided request to provide validation against an AuthenticationPredicate.
|
||||
*/
|
||||
ArRequestHandlerFunction wrapRequest(ArRequestHandlerFunction onRequest, AuthenticationPredicate predicate);
|
||||
|
||||
protected:
|
||||
|
||||
ArduinoJsonJWT _jwtHandler = ArduinoJsonJWT(DEFAULT_JWT_SECRET);
|
||||
std::list<User> _users;
|
||||
|
||||
private:
|
||||
|
||||
/*
|
||||
* Lookup the user by JWT
|
||||
*/
|
||||
Authentication authenticateJWT(String jwt);
|
||||
|
||||
/*
|
||||
* Verify the payload is correct
|
||||
*/
|
||||
boolean validatePayload(JsonObject &parsedPayload, User *user);
|
||||
|
||||
};
|
||||
|
||||
#endif // end SecurityManager_h
|
@ -1,35 +0,0 @@
|
||||
#include <SecuritySettingsService.h>
|
||||
|
||||
SecuritySettingsService::SecuritySettingsService(AsyncWebServer* server, FS* fs) : AdminSettingsService(server, fs, this, SECURITY_SETTINGS_PATH, SECURITY_SETTINGS_FILE), SecurityManager() {}
|
||||
SecuritySettingsService::~SecuritySettingsService() {}
|
||||
|
||||
void SecuritySettingsService::readFromJsonObject(JsonObject& root) {
|
||||
// secret
|
||||
_jwtHandler.setSecret(root["jwt_secret"] | DEFAULT_JWT_SECRET);
|
||||
|
||||
// users
|
||||
_users.clear();
|
||||
if (root["users"].is<JsonArray>()) {
|
||||
for (JsonVariant user : root["users"].as<JsonArray>()) {
|
||||
_users.push_back(User(user["username"], user["password"], user["admin"]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SecuritySettingsService::writeToJsonObject(JsonObject& root) {
|
||||
// secret
|
||||
root["jwt_secret"] = _jwtHandler.getSecret();
|
||||
|
||||
// users
|
||||
JsonArray users = root.createNestedArray("users");
|
||||
for (User _user : _users) {
|
||||
JsonObject user = users.createNestedObject();
|
||||
user["username"] = _user.getUsername();
|
||||
user["password"] = _user.getPassword();
|
||||
user["admin"] = _user.isAdmin();
|
||||
}
|
||||
}
|
||||
|
||||
void SecuritySettingsService::begin() {
|
||||
readFromFS();
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
#ifndef SecuritySettingsService_h
|
||||
#define SecuritySettingsService_h
|
||||
|
||||
#include <SettingsService.h>
|
||||
#include <SecurityManager.h>
|
||||
|
||||
#define SECURITY_SETTINGS_FILE "/config/securitySettings.json"
|
||||
#define SECURITY_SETTINGS_PATH "/rest/securitySettings"
|
||||
|
||||
class SecuritySettingsService : public AdminSettingsService, public SecurityManager {
|
||||
|
||||
public:
|
||||
|
||||
SecuritySettingsService(AsyncWebServer* server, FS* fs);
|
||||
~SecuritySettingsService();
|
||||
|
||||
void begin();
|
||||
|
||||
protected:
|
||||
|
||||
void readFromJsonObject(JsonObject& root);
|
||||
void writeToJsonObject(JsonObject& root);
|
||||
|
||||
};
|
||||
|
||||
#endif // end SecuritySettingsService_h
|
@ -1,98 +0,0 @@
|
||||
#ifndef SettingsPersistence_h
|
||||
#define SettingsPersistence_h
|
||||
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <FS.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <AsyncJsonWebHandler.h>
|
||||
#include <AsyncArduinoJson6.h>
|
||||
|
||||
/**
|
||||
* At the moment, not expecting settings service to have to deal with large JSON
|
||||
* files this could be made configurable fairly simply, it's exposed on
|
||||
* AsyncJsonWebHandler with a setter.
|
||||
*/
|
||||
#define MAX_SETTINGS_SIZE 1024
|
||||
|
||||
/*
|
||||
* Mixin for classes which need to save settings to/from a file on the the file system as JSON.
|
||||
*/
|
||||
class SettingsPersistence {
|
||||
|
||||
protected:
|
||||
|
||||
// will store and retrieve config from the file system
|
||||
FS* _fs;
|
||||
|
||||
// the file path our settings will be saved to
|
||||
char const* _filePath;
|
||||
|
||||
bool writeToFS() {
|
||||
// create and populate a new json object
|
||||
DynamicJsonDocument jsonDocument = DynamicJsonDocument(MAX_SETTINGS_SIZE);
|
||||
JsonObject root = jsonDocument.to<JsonObject>();
|
||||
writeToJsonObject(root);
|
||||
|
||||
// serialize it to filesystem
|
||||
File configFile = _fs->open(_filePath, "w");
|
||||
|
||||
// failed to open file, return false
|
||||
if (!configFile) {
|
||||
return false;
|
||||
}
|
||||
|
||||
serializeJson(jsonDocument, configFile);
|
||||
configFile.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void readFromFS(){
|
||||
File configFile = _fs->open(_filePath, "r");
|
||||
|
||||
// use defaults if no config found
|
||||
if (configFile) {
|
||||
// Protect against bad data uploaded to file system
|
||||
// We never expect the config file to get very large, so cap it.
|
||||
size_t size = configFile.size();
|
||||
if (size <= MAX_SETTINGS_SIZE) {
|
||||
DynamicJsonDocument jsonDocument = DynamicJsonDocument(MAX_SETTINGS_SIZE);
|
||||
DeserializationError error = deserializeJson(jsonDocument, configFile);
|
||||
if (error == DeserializationError::Ok && jsonDocument.is<JsonObject>()){
|
||||
JsonObject root = jsonDocument.as<JsonObject>();
|
||||
readFromJsonObject(root);
|
||||
configFile.close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
configFile.close();
|
||||
}
|
||||
|
||||
// If we reach here we have not been successful in loading the config,
|
||||
// hard-coded emergency defaults are now applied.
|
||||
applyDefaultConfig();
|
||||
}
|
||||
|
||||
|
||||
// serialization routene, from local config to JsonObject
|
||||
virtual void readFromJsonObject(JsonObject& root){}
|
||||
virtual void writeToJsonObject(JsonObject& root){}
|
||||
|
||||
// We assume the readFromJsonObject supplies sensible defaults if an empty object
|
||||
// is supplied, this virtual function allows that to be changed.
|
||||
virtual void applyDefaultConfig(){
|
||||
DynamicJsonDocument jsonDocument = DynamicJsonDocument(MAX_SETTINGS_SIZE);
|
||||
JsonObject root = jsonDocument.to<JsonObject>();
|
||||
readFromJsonObject(root);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
SettingsPersistence(FS* fs, char const* filePath):
|
||||
_fs(fs), _filePath(filePath) {}
|
||||
|
||||
virtual ~SettingsPersistence() {}
|
||||
|
||||
};
|
||||
|
||||
#endif // end SettingsPersistence
|
@ -1,124 +0,0 @@
|
||||
#ifndef SettingsService_h
|
||||
#define SettingsService_h
|
||||
|
||||
#if defined(ESP8266)
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <ESPAsyncTCP.h>
|
||||
#elif defined(ESP_PLATFORM)
|
||||
#include <WiFi.h>
|
||||
#include <AsyncTCP.h>
|
||||
#endif
|
||||
|
||||
#include <SecurityManager.h>
|
||||
#include <SettingsPersistence.h>
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <AsyncJsonWebHandler.h>
|
||||
#include <AsyncArduinoJson6.h>
|
||||
|
||||
|
||||
/*
|
||||
* Abstraction of a service which stores it's settings as JSON in a file system.
|
||||
*/
|
||||
class SettingsService : public SettingsPersistence {
|
||||
|
||||
public:
|
||||
|
||||
SettingsService(AsyncWebServer* server, FS* fs, char const* servicePath, char const* filePath):
|
||||
SettingsPersistence(fs, filePath), _server(server) {
|
||||
|
||||
// configure fetch config handler
|
||||
_server->on(servicePath, HTTP_GET, std::bind(&SettingsService::fetchConfig, this, std::placeholders::_1));
|
||||
|
||||
// configure update settings handler
|
||||
_updateHandler.setUri(servicePath);
|
||||
_updateHandler.setMethod(HTTP_POST);
|
||||
_updateHandler.setMaxContentLength(MAX_SETTINGS_SIZE);
|
||||
_updateHandler.onRequest(std::bind(&SettingsService::updateConfig, this, std::placeholders::_1, std::placeholders::_2));
|
||||
_server->addHandler(&_updateHandler);
|
||||
}
|
||||
|
||||
virtual ~SettingsService() {}
|
||||
|
||||
virtual void begin() {
|
||||
readFromFS();
|
||||
}
|
||||
|
||||
protected:
|
||||
// will serve setting endpoints from here
|
||||
AsyncWebServer* _server;
|
||||
|
||||
AsyncJsonWebHandler _updateHandler;
|
||||
|
||||
virtual void fetchConfig(AsyncWebServerRequest *request) {
|
||||
// handle the request
|
||||
AsyncJsonResponse * response = new AsyncJsonResponse(MAX_SETTINGS_SIZE);
|
||||
JsonObject jsonObject = response->getRoot();
|
||||
writeToJsonObject(jsonObject);
|
||||
response->setLength();
|
||||
request->send(response);
|
||||
}
|
||||
|
||||
virtual void updateConfig(AsyncWebServerRequest *request, JsonDocument &jsonDocument) {
|
||||
// handle the request
|
||||
if (jsonDocument.is<JsonObject>()){
|
||||
JsonObject newConfig = jsonDocument.as<JsonObject>();
|
||||
readFromJsonObject(newConfig);
|
||||
writeToFS();
|
||||
|
||||
// write settings back with a callback to reconfigure the wifi
|
||||
AsyncJsonCallbackResponse * response = new AsyncJsonCallbackResponse([this] () {onConfigUpdated();}, MAX_SETTINGS_SIZE);
|
||||
JsonObject jsonObject = response->getRoot();
|
||||
writeToJsonObject(jsonObject);
|
||||
response->setLength();
|
||||
request->send(response);
|
||||
} else {
|
||||
request->send(400);
|
||||
}
|
||||
}
|
||||
|
||||
// implement to perform action when config has been updated
|
||||
virtual void onConfigUpdated(){}
|
||||
|
||||
};
|
||||
|
||||
class AdminSettingsService : public SettingsService {
|
||||
public:
|
||||
AdminSettingsService(AsyncWebServer* server, FS* fs, SecurityManager* securityManager, char const* servicePath, char const* filePath):
|
||||
SettingsService(server, fs, servicePath, filePath), _securityManager(securityManager) {
|
||||
}
|
||||
|
||||
protected:
|
||||
// will validate the requests with the security manager
|
||||
SecurityManager* _securityManager;
|
||||
|
||||
void fetchConfig(AsyncWebServerRequest *request) {
|
||||
// verify the request against the predicate
|
||||
Authentication authentication = _securityManager->authenticateRequest(request);
|
||||
if (!getAuthenticationPredicate()(authentication)) {
|
||||
request->send(401);
|
||||
return;
|
||||
}
|
||||
// delegate to underlying implemetation
|
||||
SettingsService::fetchConfig(request);
|
||||
}
|
||||
|
||||
void updateConfig(AsyncWebServerRequest *request, JsonDocument &jsonDocument) {
|
||||
// verify the request against the predicate
|
||||
Authentication authentication = _securityManager->authenticateRequest(request);
|
||||
if (!getAuthenticationPredicate()(authentication)) {
|
||||
request->send(401);
|
||||
return;
|
||||
}
|
||||
// delegate to underlying implemetation
|
||||
SettingsService::updateConfig(request, jsonDocument);
|
||||
}
|
||||
|
||||
// override to override the default authentication predicate, IS_ADMIN
|
||||
AuthenticationPredicate getAuthenticationPredicate() {
|
||||
return AuthenticationPredicates::IS_ADMIN;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif // end SettingsService
|
@ -1,92 +0,0 @@
|
||||
#ifndef Service_h
|
||||
#define Service_h
|
||||
|
||||
#if defined(ESP8266)
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <ESPAsyncTCP.h>
|
||||
#elif defined(ESP_PLATFORM)
|
||||
#include <WiFi.h>
|
||||
#include <AsyncTCP.h>
|
||||
#endif
|
||||
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <AsyncArduinoJson6.h>
|
||||
#include <AsyncJsonWebHandler.h>
|
||||
|
||||
/**
|
||||
* At the moment, not expecting services to have to deal with large JSON
|
||||
* files this could be made configurable fairly simply, it's exposed on
|
||||
* AsyncJsonWebHandler with a setter.
|
||||
*/
|
||||
#define MAX_SETTINGS_SIZE 1024
|
||||
|
||||
/*
|
||||
* Abstraction of a service which reads and writes data from an endpoint.
|
||||
*
|
||||
* Not currently used, but indended for use by features which do not
|
||||
* require setting persistance.
|
||||
*/
|
||||
class SimpleService {
|
||||
|
||||
private:
|
||||
|
||||
AsyncJsonWebHandler _updateHandler;
|
||||
|
||||
void fetchConfig(AsyncWebServerRequest *request){
|
||||
AsyncJsonResponse * response = new AsyncJsonResponse(MAX_SETTINGS_SIZE);
|
||||
JsonObject jsonObject = response->getRoot();
|
||||
writeToJsonObject(jsonObject);
|
||||
response->setLength();
|
||||
request->send(response);
|
||||
}
|
||||
|
||||
void updateConfig(AsyncWebServerRequest *request, JsonDocument &jsonDocument){
|
||||
if (jsonDocument.is<JsonObject>()){
|
||||
JsonObject newConfig = jsonDocument.as<JsonObject>();
|
||||
readFromJsonObject(newConfig);
|
||||
|
||||
// write settings back with a callback to reconfigure the wifi
|
||||
AsyncJsonCallbackResponse * response = new AsyncJsonCallbackResponse([this] () {onConfigUpdated();}, MAX_SETTINGS_SIZE);
|
||||
JsonObject jsonObject = response->getRoot();
|
||||
writeToJsonObject(jsonObject);
|
||||
response->setLength();
|
||||
request->send(response);
|
||||
} else {
|
||||
request->send(400);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
// will serve setting endpoints from here
|
||||
AsyncWebServer* _server;
|
||||
|
||||
// reads the local config from the
|
||||
virtual void readFromJsonObject(JsonObject& root){}
|
||||
virtual void writeToJsonObject(JsonObject& root){}
|
||||
|
||||
// implement to perform action when config has been updated
|
||||
virtual void onConfigUpdated(){}
|
||||
|
||||
public:
|
||||
|
||||
SimpleService(AsyncWebServer* server, char const* servicePath):
|
||||
_server(server) {
|
||||
|
||||
// configure fetch config handler
|
||||
_server->on(servicePath, HTTP_GET, std::bind(&SimpleService::fetchConfig, this, std::placeholders::_1));
|
||||
|
||||
// configure update settings handler
|
||||
_updateHandler.setUri(servicePath);
|
||||
_updateHandler.setMethod(HTTP_POST);
|
||||
_updateHandler.setMaxContentLength(MAX_SETTINGS_SIZE);
|
||||
_updateHandler.onRequest(std::bind(&SimpleService::updateConfig, this, std::placeholders::_1, std::placeholders::_2));
|
||||
_server->addHandler(&_updateHandler);
|
||||
}
|
||||
|
||||
virtual ~SimpleService() {}
|
||||
|
||||
};
|
||||
|
||||
#endif // end SimpleService
|
@ -1,26 +0,0 @@
|
||||
#include <SystemStatus.h>
|
||||
|
||||
SystemStatus::SystemStatus(AsyncWebServer *server, SecurityManager* securityManager) : _server(server), _securityManager(securityManager) {
|
||||
_server->on(SYSTEM_STATUS_SERVICE_PATH, HTTP_GET,
|
||||
_securityManager->wrapRequest(std::bind(&SystemStatus::systemStatus, this, std::placeholders::_1), AuthenticationPredicates::IS_AUTHENTICATED)
|
||||
);
|
||||
}
|
||||
|
||||
void SystemStatus::systemStatus(AsyncWebServerRequest *request) {
|
||||
AsyncJsonResponse * response = new AsyncJsonResponse(MAX_ESP_STATUS_SIZE);
|
||||
JsonObject root = response->getRoot();
|
||||
#if defined(ESP8266)
|
||||
root["esp_platform"] = "esp8266";
|
||||
#elif defined(ESP_PLATFORM)
|
||||
root["esp_platform"] = "esp32";
|
||||
#endif
|
||||
root["cpu_freq_mhz"] = ESP.getCpuFreqMHz();
|
||||
root["free_heap"] = ESP.getFreeHeap();
|
||||
root["sketch_size"] = ESP.getSketchSize();
|
||||
root["free_sketch_space"] = ESP.getFreeSketchSpace();
|
||||
root["sdk_version"] = ESP.getSdkVersion();
|
||||
root["flash_chip_size"] = ESP.getFlashChipSize();
|
||||
root["flash_chip_speed"] = ESP.getFlashChipSpeed();
|
||||
response->setLength();
|
||||
request->send(response);
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
#ifndef SystemStatus_h
|
||||
#define SystemStatus_h
|
||||
|
||||
#if defined(ESP8266)
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <ESPAsyncTCP.h>
|
||||
#elif defined(ESP_PLATFORM)
|
||||
#include <WiFi.h>
|
||||
#include <AsyncTCP.h>
|
||||
#endif
|
||||
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <AsyncArduinoJson6.h>
|
||||
#include <SecurityManager.h>
|
||||
|
||||
#define MAX_ESP_STATUS_SIZE 1024
|
||||
#define SYSTEM_STATUS_SERVICE_PATH "/rest/systemStatus"
|
||||
|
||||
class SystemStatus {
|
||||
|
||||
public:
|
||||
|
||||
SystemStatus(AsyncWebServer *server, SecurityManager* securityManager);
|
||||
|
||||
private:
|
||||
|
||||
AsyncWebServer* _server;
|
||||
SecurityManager* _securityManager;
|
||||
|
||||
void systemStatus(AsyncWebServerRequest *request);
|
||||
|
||||
};
|
||||
|
||||
#endif // end SystemStatus_h
|
@ -1,68 +0,0 @@
|
||||
#include <WiFiScanner.h>
|
||||
|
||||
WiFiScanner::WiFiScanner(AsyncWebServer *server, SecurityManager* securityManager) : _server(server) {
|
||||
_server->on(SCAN_NETWORKS_SERVICE_PATH, HTTP_GET,
|
||||
securityManager->wrapRequest(std::bind(&WiFiScanner::scanNetworks, this, std::placeholders::_1), AuthenticationPredicates::IS_ADMIN)
|
||||
);
|
||||
_server->on(LIST_NETWORKS_SERVICE_PATH, HTTP_GET,
|
||||
securityManager->wrapRequest(std::bind(&WiFiScanner::listNetworks, this, std::placeholders::_1), AuthenticationPredicates::IS_ADMIN)
|
||||
);
|
||||
}
|
||||
|
||||
void WiFiScanner::scanNetworks(AsyncWebServerRequest *request) {
|
||||
if (WiFi.scanComplete() != -1){
|
||||
WiFi.scanDelete();
|
||||
WiFi.scanNetworks(true);
|
||||
}
|
||||
request->send(202);
|
||||
}
|
||||
|
||||
void WiFiScanner::listNetworks(AsyncWebServerRequest *request) {
|
||||
int numNetworks = WiFi.scanComplete();
|
||||
if (numNetworks > -1){
|
||||
AsyncJsonResponse * response = new AsyncJsonResponse(MAX_WIFI_SCANNER_SIZE);
|
||||
JsonObject root = response->getRoot();
|
||||
JsonArray networks = root.createNestedArray("networks");
|
||||
for (int i=0; i<numNetworks ; i++){
|
||||
JsonObject network = networks.createNestedObject();
|
||||
network["rssi"] = WiFi.RSSI(i);
|
||||
network["ssid"] = WiFi.SSID(i);
|
||||
network["bssid"] = WiFi.BSSIDstr(i);
|
||||
network["channel"] = WiFi.channel(i);
|
||||
#if defined(ESP8266)
|
||||
network["encryption_type"] = convertEncryptionType(WiFi.encryptionType(i));
|
||||
#elif defined(ESP_PLATFORM)
|
||||
network["encryption_type"] = (uint8_t) WiFi.encryptionType(i);
|
||||
#endif
|
||||
}
|
||||
response->setLength();
|
||||
request->send(response);
|
||||
} else if (numNetworks == -1){
|
||||
request->send(202);
|
||||
}else{
|
||||
scanNetworks(request);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(ESP8266)
|
||||
/*
|
||||
* Convert encryption type to standard used by ESP32 rather than the translated form which the esp8266 libaries expose.
|
||||
*
|
||||
* This allows us to use a single set of mappings in the UI.
|
||||
*/
|
||||
uint8_t WiFiScanner::convertEncryptionType(uint8_t encryptionType){
|
||||
switch (encryptionType){
|
||||
case ENC_TYPE_NONE:
|
||||
return AUTH_OPEN;
|
||||
case ENC_TYPE_WEP:
|
||||
return AUTH_WEP;
|
||||
case ENC_TYPE_TKIP:
|
||||
return AUTH_WPA_PSK;
|
||||
case ENC_TYPE_CCMP:
|
||||
return AUTH_WPA2_PSK;
|
||||
case ENC_TYPE_AUTO:
|
||||
return AUTH_WPA_WPA2_PSK;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
#endif
|
@ -1,42 +0,0 @@
|
||||
#ifndef WiFiScanner_h
|
||||
#define WiFiScanner_h
|
||||
|
||||
#if defined(ESP8266)
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <ESPAsyncTCP.h>
|
||||
#elif defined(ESP_PLATFORM)
|
||||
#include <WiFi.h>
|
||||
#include <AsyncTCP.h>
|
||||
#endif
|
||||
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <AsyncArduinoJson6.h>
|
||||
#include <TimeLib.h>
|
||||
#include <SecurityManager.h>
|
||||
|
||||
#define SCAN_NETWORKS_SERVICE_PATH "/rest/scanNetworks"
|
||||
#define LIST_NETWORKS_SERVICE_PATH "/rest/listNetworks"
|
||||
|
||||
#define MAX_WIFI_SCANNER_SIZE 1024
|
||||
|
||||
class WiFiScanner {
|
||||
|
||||
public:
|
||||
|
||||
WiFiScanner(AsyncWebServer *server, SecurityManager* securityManager);
|
||||
|
||||
private:
|
||||
|
||||
AsyncWebServer* _server;
|
||||
|
||||
void scanNetworks(AsyncWebServerRequest *request);
|
||||
void listNetworks(AsyncWebServerRequest *request);
|
||||
|
||||
#if defined(ESP8266)
|
||||
uint8_t convertEncryptionType(uint8_t encryptionType);
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
#endif // end WiFiScanner_h
|
@ -1,127 +0,0 @@
|
||||
#include <WiFiSettingsService.h>
|
||||
|
||||
WiFiSettingsService::WiFiSettingsService(AsyncWebServer* server, FS* fs, SecurityManager* securityManager) : AdminSettingsService(server, fs, securityManager, WIFI_SETTINGS_SERVICE_PATH, WIFI_SETTINGS_FILE) {
|
||||
#if defined(ESP8266)
|
||||
_onStationModeDisconnectedHandler = WiFi.onStationModeDisconnected(std::bind(&WiFiSettingsService::onStationModeDisconnected, this, std::placeholders::_1));
|
||||
#elif defined(ESP_PLATFORM)
|
||||
WiFi.onEvent(std::bind(&WiFiSettingsService::onStationModeDisconnected, this, std::placeholders::_1, std::placeholders::_2), WiFiEvent_t::SYSTEM_EVENT_STA_DISCONNECTED);
|
||||
#endif
|
||||
}
|
||||
|
||||
WiFiSettingsService::~WiFiSettingsService() {}
|
||||
|
||||
void WiFiSettingsService::begin() {
|
||||
SettingsService::begin();
|
||||
reconfigureWiFiConnection();
|
||||
}
|
||||
|
||||
void WiFiSettingsService::readFromJsonObject(JsonObject& root){
|
||||
_ssid = root["ssid"] | "";
|
||||
_password = root["password"] | "";
|
||||
_hostname = root["hostname"] | "";
|
||||
_staticIPConfig = root["static_ip_config"] | false;
|
||||
|
||||
// extended settings
|
||||
readIP(root, "local_ip", _localIP);
|
||||
readIP(root, "gateway_ip", _gatewayIP);
|
||||
readIP(root, "subnet_mask", _subnetMask);
|
||||
readIP(root, "dns_ip_1", _dnsIP1);
|
||||
readIP(root, "dns_ip_2", _dnsIP2);
|
||||
|
||||
// Swap around the dns servers if 2 is populated but 1 is not
|
||||
if (_dnsIP1 == INADDR_NONE && _dnsIP2 != INADDR_NONE){
|
||||
_dnsIP1 = _dnsIP2;
|
||||
_dnsIP2 = INADDR_NONE;
|
||||
}
|
||||
|
||||
// Turning off static ip config if we don't meet the minimum requirements
|
||||
// of ipAddress, gateway and subnet. This may change to static ip only
|
||||
// as sensible defaults can be assumed for gateway and subnet
|
||||
if (_staticIPConfig && (_localIP == INADDR_NONE || _gatewayIP == INADDR_NONE || _subnetMask == INADDR_NONE)){
|
||||
_staticIPConfig = false;
|
||||
}
|
||||
}
|
||||
|
||||
void WiFiSettingsService::writeToJsonObject(JsonObject& root){
|
||||
// connection settings
|
||||
root["ssid"] = _ssid;
|
||||
root["password"] = _password;
|
||||
root["hostname"] = _hostname;
|
||||
root["static_ip_config"] = _staticIPConfig;
|
||||
|
||||
// extended settings
|
||||
writeIP(root, "local_ip", _localIP);
|
||||
writeIP(root, "gateway_ip", _gatewayIP);
|
||||
writeIP(root, "subnet_mask", _subnetMask);
|
||||
writeIP(root, "dns_ip_1", _dnsIP1);
|
||||
writeIP(root, "dns_ip_2", _dnsIP2);
|
||||
}
|
||||
|
||||
void WiFiSettingsService::onConfigUpdated() {
|
||||
reconfigureWiFiConnection();
|
||||
}
|
||||
|
||||
void WiFiSettingsService::reconfigureWiFiConnection() {
|
||||
// disconnect and de-configure wifi
|
||||
WiFi.disconnect(true);
|
||||
|
||||
// reset last connection attempt to force loop to reconnect immediately
|
||||
_lastConnectionAttempt = 0;
|
||||
}
|
||||
|
||||
void WiFiSettingsService::readIP(JsonObject& root, String key, IPAddress& _ip){
|
||||
if (!root[key].is<String>() || !_ip.fromString(root[key].as<String>())){
|
||||
_ip = INADDR_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
void WiFiSettingsService::writeIP(JsonObject& root, String key, IPAddress& _ip){
|
||||
if (_ip != INADDR_NONE){
|
||||
root[key] = _ip.toString();
|
||||
}
|
||||
}
|
||||
|
||||
void WiFiSettingsService::loop() {
|
||||
unsigned long currentMillis = millis();
|
||||
if (!_lastConnectionAttempt || (unsigned long)(currentMillis - _lastConnectionAttempt) >= WIFI_RECONNECTION_DELAY) {
|
||||
_lastConnectionAttempt = currentMillis;
|
||||
manageSTA();
|
||||
}
|
||||
}
|
||||
|
||||
void WiFiSettingsService::manageSTA() {
|
||||
// Abort if already connected, or if we have no SSID
|
||||
if (WiFi.isConnected() || _ssid.length() == 0) {
|
||||
return;
|
||||
}
|
||||
// Connect or reconnect as required
|
||||
if ((WiFi.getMode() & WIFI_STA) == 0) {
|
||||
Serial.println("Connecting to WiFi.");
|
||||
if (_staticIPConfig) {
|
||||
// configure for static IP
|
||||
WiFi.config(_localIP, _gatewayIP, _subnetMask, _dnsIP1, _dnsIP2);
|
||||
} else {
|
||||
// configure for DHCP
|
||||
#if defined(ESP8266)
|
||||
WiFi.config(INADDR_ANY, INADDR_ANY, INADDR_ANY);
|
||||
WiFi.hostname(_hostname);
|
||||
#elif defined(ESP_PLATFORM)
|
||||
WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE);
|
||||
WiFi.setHostname(_hostname.c_str());
|
||||
#endif
|
||||
}
|
||||
// attempt to connect to the network
|
||||
WiFi.begin(_ssid.c_str(), _password.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(ESP8266)
|
||||
void WiFiSettingsService::onStationModeDisconnected(const WiFiEventStationModeDisconnected& event) {
|
||||
WiFi.disconnect(true);
|
||||
}
|
||||
#elif defined(ESP_PLATFORM)
|
||||
void WiFiSettingsService::onStationModeDisconnected(WiFiEvent_t event, WiFiEventInfo_t info) {
|
||||
WiFi.disconnect(true);
|
||||
}
|
||||
#endif
|
||||
|
@ -1,58 +0,0 @@
|
||||
#ifndef WiFiSettingsService_h
|
||||
#define WiFiSettingsService_h
|
||||
|
||||
#include <SettingsService.h>
|
||||
#include <IPAddress.h>
|
||||
|
||||
#define WIFI_SETTINGS_FILE "/config/wifiSettings.json"
|
||||
#define WIFI_SETTINGS_SERVICE_PATH "/rest/wifiSettings"
|
||||
#define WIFI_RECONNECTION_DELAY 1000 * 60
|
||||
|
||||
class WiFiSettingsService : public AdminSettingsService {
|
||||
|
||||
public:
|
||||
|
||||
WiFiSettingsService(AsyncWebServer* server, FS* fs, SecurityManager* securityManager);
|
||||
~WiFiSettingsService();
|
||||
|
||||
void begin();
|
||||
void loop();
|
||||
|
||||
protected:
|
||||
|
||||
void readFromJsonObject(JsonObject& root);
|
||||
void writeToJsonObject(JsonObject& root);
|
||||
void onConfigUpdated();
|
||||
|
||||
private:
|
||||
// connection settings
|
||||
String _ssid;
|
||||
String _password;
|
||||
String _hostname;
|
||||
bool _staticIPConfig;
|
||||
|
||||
// for the mangement delay loop
|
||||
unsigned long _lastConnectionAttempt;
|
||||
|
||||
// optional configuration for static IP address
|
||||
IPAddress _localIP;
|
||||
IPAddress _gatewayIP;
|
||||
IPAddress _subnetMask;
|
||||
IPAddress _dnsIP1;
|
||||
IPAddress _dnsIP2;
|
||||
|
||||
#if defined(ESP8266)
|
||||
WiFiEventHandler _onStationModeDisconnectedHandler;
|
||||
void onStationModeDisconnected(const WiFiEventStationModeDisconnected& event);
|
||||
#elif defined(ESP_PLATFORM)
|
||||
void onStationModeDisconnected(WiFiEvent_t event, WiFiEventInfo_t info);
|
||||
#endif
|
||||
|
||||
void readIP(JsonObject& root, String key, IPAddress& _ip);
|
||||
void writeIP(JsonObject& root, String key, IPAddress& _ip);
|
||||
void reconfigureWiFiConnection();
|
||||
void manageSTA();
|
||||
|
||||
};
|
||||
|
||||
#endif // end WiFiSettingsService_h
|
@ -1,78 +0,0 @@
|
||||
#include <WiFiStatus.h>
|
||||
|
||||
WiFiStatus::WiFiStatus(AsyncWebServer *server, SecurityManager* securityManager) : _server(server), _securityManager(securityManager) {
|
||||
_server->on(WIFI_STATUS_SERVICE_PATH, HTTP_GET,
|
||||
_securityManager->wrapRequest(std::bind(&WiFiStatus::wifiStatus, this, std::placeholders::_1), AuthenticationPredicates::IS_AUTHENTICATED)
|
||||
);
|
||||
#if defined(ESP8266)
|
||||
_onStationModeConnectedHandler = WiFi.onStationModeConnected(onStationModeConnected);
|
||||
_onStationModeDisconnectedHandler = WiFi.onStationModeDisconnected(onStationModeDisconnected);
|
||||
_onStationModeGotIPHandler = WiFi.onStationModeGotIP(onStationModeGotIP);
|
||||
#elif defined(ESP_PLATFORM)
|
||||
WiFi.onEvent(onStationModeConnected, WiFiEvent_t::SYSTEM_EVENT_STA_CONNECTED);
|
||||
WiFi.onEvent(onStationModeDisconnected, WiFiEvent_t::SYSTEM_EVENT_STA_DISCONNECTED);
|
||||
WiFi.onEvent(onStationModeGotIP, WiFiEvent_t::SYSTEM_EVENT_STA_GOT_IP);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(ESP8266)
|
||||
void WiFiStatus::onStationModeConnected(const WiFiEventStationModeConnected& event) {
|
||||
Serial.print("WiFi Connected. SSID=");
|
||||
Serial.println(event.ssid);
|
||||
}
|
||||
|
||||
void WiFiStatus::onStationModeDisconnected(const WiFiEventStationModeDisconnected& event) {
|
||||
Serial.print("WiFi Disconnected. Reason code=");
|
||||
Serial.println(event.reason);
|
||||
}
|
||||
|
||||
void WiFiStatus::onStationModeGotIP(const WiFiEventStationModeGotIP& event) {
|
||||
Serial.print("WiFi Got IP. localIP=");
|
||||
Serial.print(event.ip);
|
||||
Serial.print(", hostName=");
|
||||
Serial.println(WiFi.hostname());
|
||||
}
|
||||
#elif defined(ESP_PLATFORM)
|
||||
void WiFiStatus::onStationModeConnected(WiFiEvent_t event, WiFiEventInfo_t info) {
|
||||
Serial.println("WiFi Connected.");
|
||||
}
|
||||
|
||||
void WiFiStatus::onStationModeDisconnected(WiFiEvent_t event, WiFiEventInfo_t info) {
|
||||
Serial.print("WiFi Disconnected. Reason code=");
|
||||
Serial.println(info.disconnected.reason);
|
||||
}
|
||||
|
||||
void WiFiStatus::onStationModeGotIP(WiFiEvent_t event, WiFiEventInfo_t info) {
|
||||
Serial.print("WiFi Got IP. localIP=");
|
||||
Serial.print(WiFi.localIP().toString());
|
||||
Serial.print(", hostName=");
|
||||
Serial.println(WiFi.getHostname());
|
||||
}
|
||||
#endif
|
||||
|
||||
void WiFiStatus::wifiStatus(AsyncWebServerRequest *request) {
|
||||
AsyncJsonResponse * response = new AsyncJsonResponse(MAX_WIFI_STATUS_SIZE);
|
||||
JsonObject root = response->getRoot();
|
||||
wl_status_t status = WiFi.status();
|
||||
root["status"] = (uint8_t) status;
|
||||
if (status == WL_CONNECTED){
|
||||
root["local_ip"] = WiFi.localIP().toString();
|
||||
root["mac_address"] = WiFi.macAddress();
|
||||
root["rssi"] = WiFi.RSSI();
|
||||
root["ssid"] = WiFi.SSID();
|
||||
root["bssid"] = WiFi.BSSIDstr();
|
||||
root["channel"] = WiFi.channel();
|
||||
root["subnet_mask"] = WiFi.subnetMask().toString();
|
||||
root["gateway_ip"] = WiFi.gatewayIP().toString();
|
||||
IPAddress dnsIP1 = WiFi.dnsIP(0);
|
||||
IPAddress dnsIP2 = WiFi.dnsIP(1);
|
||||
if (dnsIP1 != INADDR_NONE){
|
||||
root["dns_ip_1"] = dnsIP1.toString();
|
||||
}
|
||||
if (dnsIP2 != INADDR_NONE){
|
||||
root["dns_ip_2"] = dnsIP2.toString();
|
||||
}
|
||||
}
|
||||
response->setLength();
|
||||
request->send(response);
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
#ifndef WiFiStatus_h
|
||||
#define WiFiStatus_h
|
||||
|
||||
#if defined(ESP8266)
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <ESPAsyncTCP.h>
|
||||
#elif defined(ESP_PLATFORM)
|
||||
#include <WiFi.h>
|
||||
#include <AsyncTCP.h>
|
||||
#endif
|
||||
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <AsyncArduinoJson6.h>
|
||||
#include <IPAddress.h>
|
||||
#include <SecurityManager.h>
|
||||
|
||||
#define MAX_WIFI_STATUS_SIZE 1024
|
||||
#define WIFI_STATUS_SERVICE_PATH "/rest/wifiStatus"
|
||||
|
||||
class WiFiStatus {
|
||||
|
||||
public:
|
||||
|
||||
WiFiStatus(AsyncWebServer *server, SecurityManager* securityManager);
|
||||
|
||||
private:
|
||||
|
||||
AsyncWebServer* _server;
|
||||
SecurityManager* _securityManager;
|
||||
|
||||
#if defined(ESP8266)
|
||||
// handler refrences for logging important WiFi events over serial
|
||||
WiFiEventHandler _onStationModeConnectedHandler;
|
||||
WiFiEventHandler _onStationModeDisconnectedHandler;
|
||||
WiFiEventHandler _onStationModeGotIPHandler;
|
||||
// static functions for logging WiFi events to the UART
|
||||
static void onStationModeConnected(const WiFiEventStationModeConnected& event);
|
||||
static void onStationModeDisconnected(const WiFiEventStationModeDisconnected& event);
|
||||
static void onStationModeGotIP(const WiFiEventStationModeGotIP& event);
|
||||
#elif defined(ESP_PLATFORM)
|
||||
// static functions for logging WiFi events to the UART
|
||||
static void onStationModeConnected(WiFiEvent_t event, WiFiEventInfo_t info);
|
||||
static void onStationModeDisconnected(WiFiEvent_t event, WiFiEventInfo_t info);
|
||||
static void onStationModeGotIP(WiFiEvent_t event, WiFiEventInfo_t info);
|
||||
#endif
|
||||
|
||||
void wifiStatus(AsyncWebServerRequest *request);
|
||||
|
||||
};
|
||||
|
||||
#endif // end WiFiStatus_h
|
98
src/main.cpp
98
src/main.cpp
@ -1,99 +1,31 @@
|
||||
#include <Arduino.h>
|
||||
|
||||
#if defined(ESP8266)
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <ESPAsyncTCP.h>
|
||||
#elif defined(ESP_PLATFORM)
|
||||
#include <WiFi.h>
|
||||
#include <AsyncTCP.h>
|
||||
#include <SPIFFS.h>
|
||||
#endif
|
||||
|
||||
#include <ESP8266React.h>
|
||||
#include <DemoProject.h>
|
||||
#include <FS.h>
|
||||
#include <SecuritySettingsService.h>
|
||||
#include <WiFiSettingsService.h>
|
||||
#include <APSettingsService.h>
|
||||
#include <NTPSettingsService.h>
|
||||
#include <OTASettingsService.h>
|
||||
#include <AuthenticationService.h>
|
||||
#include <WiFiScanner.h>
|
||||
#include <WiFiStatus.h>
|
||||
#include <NTPStatus.h>
|
||||
#include <APStatus.h>
|
||||
#include <SystemStatus.h>
|
||||
|
||||
#define SERIAL_BAUD_RATE 115200
|
||||
|
||||
AsyncWebServer server(80);
|
||||
ESP8266React espServer(&SPIFFS);
|
||||
|
||||
SecuritySettingsService securitySettingsService = SecuritySettingsService(&server, &SPIFFS);
|
||||
WiFiSettingsService wifiSettingsService = WiFiSettingsService(&server, &SPIFFS, &securitySettingsService);
|
||||
APSettingsService apSettingsService = APSettingsService(&server, &SPIFFS, &securitySettingsService);
|
||||
NTPSettingsService ntpSettingsService = NTPSettingsService(&server, &SPIFFS, &securitySettingsService);
|
||||
OTASettingsService otaSettingsService = OTASettingsService(&server, &SPIFFS, &securitySettingsService);
|
||||
AuthenticationService authenticationService = AuthenticationService(&server, &securitySettingsService);
|
||||
|
||||
WiFiScanner wifiScanner = WiFiScanner(&server, &securitySettingsService);
|
||||
WiFiStatus wifiStatus = WiFiStatus(&server, &securitySettingsService);
|
||||
NTPStatus ntpStatus = NTPStatus(&server, &securitySettingsService);
|
||||
APStatus apStatus = APStatus(&server, &securitySettingsService);
|
||||
SystemStatus systemStatus = SystemStatus(&server, &securitySettingsService);;
|
||||
DemoProject demoProject = DemoProject(&server, espServer.getSecurityManager());
|
||||
|
||||
void setup() {
|
||||
// Disable wifi config persistance and auto reconnect
|
||||
WiFi.persistent(false);
|
||||
WiFi.setAutoReconnect(false);
|
||||
|
||||
#if defined(ESP_PLATFORM)
|
||||
// Init the wifi driver on ESP32
|
||||
WiFi.mode(WIFI_MODE_MAX);
|
||||
WiFi.mode(WIFI_MODE_NULL);
|
||||
#endif
|
||||
|
||||
Serial.begin(SERIAL_BAUD_RATE);
|
||||
SPIFFS.begin();
|
||||
|
||||
// set up the framework
|
||||
espServer.init(&server);
|
||||
|
||||
// begin the demo project
|
||||
demoProject.begin();
|
||||
|
||||
// Start security settings service first
|
||||
securitySettingsService.begin();
|
||||
|
||||
// Start services
|
||||
ntpSettingsService.begin();
|
||||
otaSettingsService.begin();
|
||||
apSettingsService.begin();
|
||||
wifiSettingsService.begin();
|
||||
|
||||
// Serving static resources from /www/
|
||||
server.serveStatic("/js/", SPIFFS, "/www/js/");
|
||||
server.serveStatic("/css/", SPIFFS, "/www/css/");
|
||||
server.serveStatic("/fonts/", SPIFFS, "/www/fonts/");
|
||||
server.serveStatic("/app/", SPIFFS, "/www/app/");
|
||||
server.serveStatic("/favicon.ico", SPIFFS, "/www/favicon.ico");
|
||||
|
||||
// Serving all other get requests with "/www/index.htm"
|
||||
// OPTIONS get a straight up 200 response
|
||||
server.onNotFound([](AsyncWebServerRequest *request) {
|
||||
if (request->method() == HTTP_GET) {
|
||||
request->send(SPIFFS, "/www/index.html");
|
||||
} else if (request->method() == HTTP_OPTIONS) {
|
||||
request->send(200);
|
||||
} else {
|
||||
request->send(404);
|
||||
}
|
||||
});
|
||||
|
||||
// Disable CORS if required
|
||||
#if defined(ENABLE_CORS)
|
||||
DefaultHeaders::Instance().addHeader("Access-Control-Allow-Origin", CORS_ORIGIN);
|
||||
DefaultHeaders::Instance().addHeader("Access-Control-Allow-Headers", "Accept, Content-Type, Authorization");
|
||||
DefaultHeaders::Instance().addHeader("Access-Control-Allow-Credentials", "true");
|
||||
#endif
|
||||
|
||||
server.begin();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
wifiSettingsService.loop();
|
||||
apSettingsService.loop();
|
||||
ntpSettingsService.loop();
|
||||
otaSettingsService.loop();
|
||||
// run the framework loop
|
||||
espServer.loop();
|
||||
|
||||
// run the demo project loop
|
||||
demoProject.loop();
|
||||
}
|
||||
|
Reference in New Issue
Block a user