Factory reset feature (#114)
Implemented factory-reset feature Extract factory settings into separate ini file Hide reset/factory reset from guest user Co-authored-by: kasedy <kasedy@gmail.com>
This commit is contained in:
@ -15,8 +15,17 @@
|
||||
|
||||
#define DNS_PORT 53
|
||||
|
||||
#define AP_DEFAULT_SSID "ESP8266-React"
|
||||
#define AP_DEFAULT_PASSWORD "esp-react"
|
||||
#ifndef FACTORY_AP_SSID
|
||||
#define FACTORY_AP_SSID "ESP8266-React"
|
||||
#endif
|
||||
|
||||
#ifndef FACTORY_AP_PASSWORD
|
||||
#define FACTORY_AP_PASSWORD "esp-react"
|
||||
#endif
|
||||
|
||||
#ifndef FACTORY_AP_PROVISION_MODE
|
||||
#define FACTORY_AP_PROVISION_MODE AP_MODE_DISCONNECTED
|
||||
#endif
|
||||
|
||||
#define AP_SETTINGS_FILE "/config/apSettings.json"
|
||||
#define AP_SETTINGS_SERVICE_PATH "/rest/apSettings"
|
||||
@ -34,7 +43,7 @@ class APSettings {
|
||||
}
|
||||
|
||||
static void deserialize(JsonObject& root, APSettings& settings) {
|
||||
settings.provisionMode = root["provision_mode"] | AP_MODE_ALWAYS;
|
||||
settings.provisionMode = root["provision_mode"] | FACTORY_AP_PROVISION_MODE;
|
||||
switch (settings.provisionMode) {
|
||||
case AP_MODE_ALWAYS:
|
||||
case AP_MODE_DISCONNECTED:
|
||||
@ -43,8 +52,8 @@ class APSettings {
|
||||
default:
|
||||
settings.provisionMode = AP_MODE_ALWAYS;
|
||||
}
|
||||
settings.ssid = root["ssid"] | AP_DEFAULT_SSID;
|
||||
settings.password = root["password"] | AP_DEFAULT_PASSWORD;
|
||||
settings.ssid = root["ssid"] | FACTORY_AP_SSID;
|
||||
settings.password = root["password"] | FACTORY_AP_PASSWORD;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -8,6 +8,7 @@ ESP8266React::ESP8266React(AsyncWebServer* server, FS* fs) :
|
||||
_otaSettingsService(server, fs, &_securitySettingsService),
|
||||
_mqttSettingsService(server, fs, &_securitySettingsService),
|
||||
_restartService(server, &_securitySettingsService),
|
||||
_factoryResetService(server, fs, &_securitySettingsService),
|
||||
_authenticationService(server, &_securitySettingsService),
|
||||
_wifiScanner(server, &_securitySettingsService),
|
||||
_wifiStatus(server, &_securitySettingsService),
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include <APSettingsService.h>
|
||||
#include <APStatus.h>
|
||||
#include <AuthenticationService.h>
|
||||
#include <FactoryResetService.h>
|
||||
#include <MqttSettingsService.h>
|
||||
#include <MqttStatus.h>
|
||||
#include <NTPSettingsService.h>
|
||||
@ -71,6 +72,10 @@ class ESP8266React {
|
||||
return _mqttSettingsService.getMqttClient();
|
||||
}
|
||||
|
||||
void factoryReset() {
|
||||
_factoryResetService.factoryReset();
|
||||
}
|
||||
|
||||
private:
|
||||
SecuritySettingsService _securitySettingsService;
|
||||
WiFiSettingsService _wifiSettingsService;
|
||||
@ -79,6 +84,7 @@ class ESP8266React {
|
||||
OTASettingsService _otaSettingsService;
|
||||
MqttSettingsService _mqttSettingsService;
|
||||
RestartService _restartService;
|
||||
FactoryResetService _factoryResetService;
|
||||
|
||||
AuthenticationService _authenticationService;
|
||||
|
||||
|
17
lib/framework/ESPUtils.h
Normal file
17
lib/framework/ESPUtils.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef ESPUtils_h
|
||||
#define ESPUtils_h
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
class ESPUtils {
|
||||
public:
|
||||
static String defaultDeviceValue(String prefix = "") {
|
||||
#ifdef ESP32
|
||||
return prefix + String((unsigned long)ESP.getEfuseMac(), HEX);
|
||||
#elif defined(ESP8266)
|
||||
return prefix + String(ESP.getChipId(), HEX);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
#endif // end ESPUtils
|
34
lib/framework/FactoryResetService.cpp
Normal file
34
lib/framework/FactoryResetService.cpp
Normal file
@ -0,0 +1,34 @@
|
||||
#include <FactoryResetService.h>
|
||||
|
||||
using namespace std::placeholders;
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
void FactoryResetService::handleRequest(AsyncWebServerRequest* request) {
|
||||
request->onDisconnect(std::bind(&FactoryResetService::factoryReset, this));
|
||||
request->send(200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete function assumes that all files are stored flat, within the config directory
|
||||
*/
|
||||
void FactoryResetService::factoryReset() {
|
||||
#ifdef ESP32
|
||||
File root = fs->open(FS_CONFIG_DIRECTORY);
|
||||
File file;
|
||||
while (file = root.openNextFile()) {
|
||||
fs->remove(file.name());
|
||||
}
|
||||
#elif defined(ESP8266)
|
||||
Dir configDirectory = fs->openDir(FS_CONFIG_DIRECTORY);
|
||||
while (configDirectory.next()) {
|
||||
fs->remove(configDirectory.fileName());
|
||||
}
|
||||
#endif
|
||||
ESP.restart();
|
||||
}
|
31
lib/framework/FactoryResetService.h
Normal file
31
lib/framework/FactoryResetService.h
Normal file
@ -0,0 +1,31 @@
|
||||
#ifndef FactoryResetService_h
|
||||
#define FactoryResetService_h
|
||||
|
||||
#ifdef ESP32
|
||||
#include <WiFi.h>
|
||||
#include <AsyncTCP.h>
|
||||
#elif defined(ESP8266)
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <ESPAsyncTCP.h>
|
||||
#endif
|
||||
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <SecurityManager.h>
|
||||
#include <FS.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:
|
||||
void handleRequest(AsyncWebServerRequest* request);
|
||||
};
|
||||
|
||||
#endif // end FactoryResetService_h
|
@ -1,3 +1,6 @@
|
||||
#ifndef JsonUtils_h
|
||||
#define JsonUtils_h
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <IPAddress.h>
|
||||
#include <ArduinoJson.h>
|
||||
@ -15,3 +18,5 @@ class JsonUtils {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif // end JsonUtils
|
||||
|
@ -22,8 +22,10 @@ class MqttConnector {
|
||||
|
||||
virtual void onConnect() = 0;
|
||||
|
||||
public:
|
||||
inline AsyncMqttClient* getMqttClient() const { return _mqttClient; }
|
||||
public:
|
||||
inline AsyncMqttClient* getMqttClient() const {
|
||||
return _mqttClient;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
|
@ -5,27 +5,54 @@
|
||||
#include <HttpEndpoint.h>
|
||||
#include <FSPersistence.h>
|
||||
#include <AsyncMqttClient.h>
|
||||
#include <ESPUtils.h>
|
||||
|
||||
#define MQTT_RECONNECTION_DELAY 5000
|
||||
|
||||
#define MQTT_SETTINGS_FILE "/config/mqttSettings.json"
|
||||
#define MQTT_SETTINGS_SERVICE_PATH "/rest/mqttSettings"
|
||||
|
||||
#define MQTT_SETTINGS_SERVICE_DEFAULT_ENABLED false
|
||||
#define MQTT_SETTINGS_SERVICE_DEFAULT_HOST "test.mosquitto.org"
|
||||
#define MQTT_SETTINGS_SERVICE_DEFAULT_PORT 1883
|
||||
#define MQTT_SETTINGS_SERVICE_DEFAULT_USERNAME ""
|
||||
#define MQTT_SETTINGS_SERVICE_DEFAULT_PASSWORD ""
|
||||
#define MQTT_SETTINGS_SERVICE_DEFAULT_CLIENT_ID generateClientId()
|
||||
#define MQTT_SETTINGS_SERVICE_DEFAULT_KEEP_ALIVE 16
|
||||
#define MQTT_SETTINGS_SERVICE_DEFAULT_CLEAN_SESSION true
|
||||
#define MQTT_SETTINGS_SERVICE_DEFAULT_MAX_TOPIC_LENGTH 128
|
||||
#ifndef FACTORY_MQTT_ENABLED
|
||||
#define FACTORY_MQTT_ENABLED false
|
||||
#endif
|
||||
|
||||
#ifndef FACTORY_MQTT_HOST
|
||||
#define FACTORY_MQTT_HOST "test.mosquitto.org"
|
||||
#endif
|
||||
|
||||
#ifndef FACTORY_MQTT_PORT
|
||||
#define FACTORY_MQTT_PORT 1883
|
||||
#endif
|
||||
|
||||
#ifndef FACTORY_MQTT_USERNAME
|
||||
#define FACTORY_MQTT_USERNAME ""
|
||||
#endif
|
||||
|
||||
#ifndef FACTORY_MQTT_PASSWORD
|
||||
#define FACTORY_MQTT_PASSWORD ""
|
||||
#endif
|
||||
|
||||
#ifndef FACTORY_MQTT_CLIENT_ID
|
||||
#define FACTORY_MQTT_CLIENT_ID generateClientId()
|
||||
#endif
|
||||
|
||||
#ifndef FACTORY_MQTT_KEEP_ALIVE
|
||||
#define FACTORY_MQTT_KEEP_ALIVE 16
|
||||
#endif
|
||||
|
||||
#ifndef FACTORY_MQTT_CLEAN_SESSION
|
||||
#define FACTORY_MQTT_CLEAN_SESSION true
|
||||
#endif
|
||||
|
||||
#ifndef FACTORY_MQTT_MAX_TOPIC_LENGTH
|
||||
#define FACTORY_MQTT_MAX_TOPIC_LENGTH 128
|
||||
#endif
|
||||
|
||||
static String generateClientId() {
|
||||
#ifdef ESP32
|
||||
return "esp32-" + String((unsigned long)ESP.getEfuseMac(), HEX);
|
||||
return ESPUtils::defaultDeviceValue("esp32-");
|
||||
#elif defined(ESP8266)
|
||||
return "esp8266-" + String(ESP.getChipId(), HEX);
|
||||
return ESPUtils::defaultDeviceValue("esp8266-");
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -61,15 +88,15 @@ class MqttSettings {
|
||||
}
|
||||
|
||||
static void deserialize(JsonObject& root, MqttSettings& settings) {
|
||||
settings.enabled = root["enabled"] | MQTT_SETTINGS_SERVICE_DEFAULT_ENABLED;
|
||||
settings.host = root["host"] | MQTT_SETTINGS_SERVICE_DEFAULT_HOST;
|
||||
settings.port = root["port"] | MQTT_SETTINGS_SERVICE_DEFAULT_PORT;
|
||||
settings.username = root["username"] | MQTT_SETTINGS_SERVICE_DEFAULT_USERNAME;
|
||||
settings.password = root["password"] | MQTT_SETTINGS_SERVICE_DEFAULT_PASSWORD;
|
||||
settings.clientId = root["client_id"] | MQTT_SETTINGS_SERVICE_DEFAULT_CLIENT_ID;
|
||||
settings.keepAlive = root["keep_alive"] | MQTT_SETTINGS_SERVICE_DEFAULT_KEEP_ALIVE;
|
||||
settings.cleanSession = root["clean_session"] | MQTT_SETTINGS_SERVICE_DEFAULT_CLEAN_SESSION;
|
||||
settings.maxTopicLength = root["max_topic_length"] | MQTT_SETTINGS_SERVICE_DEFAULT_MAX_TOPIC_LENGTH;
|
||||
settings.enabled = root["enabled"] | FACTORY_MQTT_ENABLED;
|
||||
settings.host = root["host"] | FACTORY_MQTT_HOST;
|
||||
settings.port = root["port"] | FACTORY_MQTT_PORT;
|
||||
settings.username = root["username"] | FACTORY_MQTT_USERNAME;
|
||||
settings.password = root["password"] | FACTORY_MQTT_PASSWORD;
|
||||
settings.clientId = root["client_id"] | FACTORY_MQTT_CLIENT_ID;
|
||||
settings.keepAlive = root["keep_alive"] | FACTORY_MQTT_KEEP_ALIVE;
|
||||
settings.cleanSession = root["clean_session"] | FACTORY_MQTT_CLEAN_SESSION;
|
||||
settings.maxTopicLength = root["max_topic_length"] | FACTORY_MQTT_MAX_TOPIC_LENGTH;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -11,11 +11,21 @@
|
||||
#include <sntp.h>
|
||||
#endif
|
||||
|
||||
// default time zone
|
||||
#define NTP_SETTINGS_SERVICE_DEFAULT_ENABLED true
|
||||
#define NTP_SETTINGS_SERVICE_DEFAULT_TIME_ZONE_LABEL "Europe/London"
|
||||
#define NTP_SETTINGS_SERVICE_DEFAULT_TIME_ZONE_FORMAT "GMT0BST,M3.5.0/1,M10.5.0"
|
||||
#define NTP_SETTINGS_SERVICE_DEFAULT_SERVER "time.google.com"
|
||||
#ifndef FACTORY_NTP_ENABLED
|
||||
#define FACTORY_NTP_ENABLED true
|
||||
#endif
|
||||
|
||||
#ifndef FACTORY_NTP_TIME_ZONE_LABEL
|
||||
#define FACTORY_NTP_TIME_ZONE_LABEL "Europe/London"
|
||||
#endif
|
||||
|
||||
#ifndef FACTORY_NTP_TIME_ZONE_FORMAT
|
||||
#define FACTORY_NTP_TIME_ZONE_FORMAT "GMT0BST,M3.5.0/1,M10.5.0"
|
||||
#endif
|
||||
|
||||
#ifndef FACTORY_NTP_SERVER
|
||||
#define FACTORY_NTP_SERVER "time.google.com"
|
||||
#endif
|
||||
|
||||
#define NTP_SETTINGS_FILE "/config/ntpSettings.json"
|
||||
#define NTP_SETTINGS_SERVICE_PATH "/rest/ntpSettings"
|
||||
@ -35,10 +45,10 @@ class NTPSettings {
|
||||
}
|
||||
|
||||
static void deserialize(JsonObject& root, NTPSettings& settings) {
|
||||
settings.enabled = root["enabled"] | NTP_SETTINGS_SERVICE_DEFAULT_ENABLED;
|
||||
settings.server = root["server"] | NTP_SETTINGS_SERVICE_DEFAULT_SERVER;
|
||||
settings.tzLabel = root["tz_label"] | NTP_SETTINGS_SERVICE_DEFAULT_TIME_ZONE_LABEL;
|
||||
settings.tzFormat = root["tz_format"] | NTP_SETTINGS_SERVICE_DEFAULT_TIME_ZONE_FORMAT;
|
||||
settings.enabled = root["enabled"] | FACTORY_NTP_ENABLED;
|
||||
settings.server = root["server"] | FACTORY_NTP_SERVER;
|
||||
settings.tzLabel = root["tz_label"] | FACTORY_NTP_TIME_ZONE_LABEL;
|
||||
settings.tzFormat = root["tz_format"] | FACTORY_NTP_TIME_ZONE_FORMAT;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -13,10 +13,17 @@
|
||||
#include <ArduinoOTA.h>
|
||||
#include <WiFiUdp.h>
|
||||
|
||||
// Emergency defaults
|
||||
#define DEFAULT_OTA_PORT 8266
|
||||
#define DEFAULT_OTA_PASSWORD "esp-react"
|
||||
#define DEFAULT_OTA_ENABLED true
|
||||
#ifndef FACTORY_OTA_PORT
|
||||
#define FACTORY_OTA_PORT 8266
|
||||
#endif
|
||||
|
||||
#ifndef FACTORY_OTA_PASSWORD
|
||||
#define FACTORY_OTA_PASSWORD "esp-react"
|
||||
#endif
|
||||
|
||||
#ifndef FACTORY_OTA_ENABLED
|
||||
#define FACTORY_OTA_ENABLED true
|
||||
#endif
|
||||
|
||||
#define OTA_SETTINGS_FILE "/config/otaSettings.json"
|
||||
#define OTA_SETTINGS_SERVICE_PATH "/rest/otaSettings"
|
||||
@ -34,9 +41,9 @@ class OTASettings {
|
||||
}
|
||||
|
||||
static void deserialize(JsonObject& root, OTASettings& settings) {
|
||||
settings.enabled = root["enabled"] | DEFAULT_OTA_ENABLED;
|
||||
settings.port = root["port"] | DEFAULT_OTA_PORT;
|
||||
settings.password = root["password"] | DEFAULT_OTA_PASSWORD;
|
||||
settings.enabled = root["enabled"] | FACTORY_OTA_ENABLED;
|
||||
settings.port = root["port"] | FACTORY_OTA_PORT;
|
||||
settings.password = root["password"] | FACTORY_OTA_PASSWORD;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -8,12 +8,6 @@ RestartService::RestartService(AsyncWebServer* server, SecurityManager* security
|
||||
}
|
||||
|
||||
void RestartService::restart(AsyncWebServerRequest* request) {
|
||||
request->onDisconnect([]() {
|
||||
#ifdef ESP32
|
||||
ESP.restart();
|
||||
#elif defined(ESP8266)
|
||||
ESP.reset();
|
||||
#endif
|
||||
});
|
||||
request->onDisconnect([]() { ESP.restart(); });
|
||||
request->send(200);
|
||||
}
|
||||
|
@ -3,10 +3,13 @@
|
||||
|
||||
#include <ArduinoJsonJWT.h>
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <ESPUtils.h>
|
||||
#include <AsyncJson.h>
|
||||
#include <list>
|
||||
|
||||
#define DEFAULT_JWT_SECRET "esp8266-react"
|
||||
#ifndef FACTORY_JWT_SECRET
|
||||
#define FACTORY_JWT_SECRET ESPUtils::defaultDeviceValue()
|
||||
#endif
|
||||
|
||||
#define ACCESS_TOKEN_PARAMATER "access_token"
|
||||
|
||||
|
@ -5,8 +5,21 @@
|
||||
#include <HttpEndpoint.h>
|
||||
#include <FSPersistence.h>
|
||||
|
||||
#define DEFAULT_ADMIN_USERNAME "admin"
|
||||
#define DEFAULT_GUEST_USERNAME "guest"
|
||||
#ifndef FACTORY_ADMIN_USERNAME
|
||||
#define FACTORY_ADMIN_USERNAME "admin"
|
||||
#endif
|
||||
|
||||
#ifndef FACTORY_ADMIN_PASSWORD
|
||||
#define FACTORY_ADMIN_PASSWORD "admin"
|
||||
#endif
|
||||
|
||||
#ifndef FACTORY_GUEST_USERNAME
|
||||
#define FACTORY_GUEST_USERNAME "guest"
|
||||
#endif
|
||||
|
||||
#ifndef FACTORY_GUEST_PASSWORD
|
||||
#define FACTORY_GUEST_PASSWORD "guest"
|
||||
#endif
|
||||
|
||||
#define SECURITY_SETTINGS_FILE "/config/securitySettings.json"
|
||||
#define SECURITY_SETTINGS_PATH "/rest/securitySettings"
|
||||
@ -32,7 +45,7 @@ class SecuritySettings {
|
||||
|
||||
static void deserialize(JsonObject& root, SecuritySettings& settings) {
|
||||
// secret
|
||||
settings.jwtSecret = root["jwt_secret"] | DEFAULT_JWT_SECRET;
|
||||
settings.jwtSecret = root["jwt_secret"] | FACTORY_JWT_SECRET;
|
||||
|
||||
// users
|
||||
settings.users.clear();
|
||||
@ -41,8 +54,8 @@ class SecuritySettings {
|
||||
settings.users.push_back(User(user["username"], user["password"], user["admin"]));
|
||||
}
|
||||
} else {
|
||||
settings.users.push_back(User(DEFAULT_ADMIN_USERNAME, DEFAULT_ADMIN_USERNAME, true));
|
||||
settings.users.push_back(User(DEFAULT_GUEST_USERNAME, DEFAULT_GUEST_USERNAME, false));
|
||||
settings.users.push_back(User(FACTORY_ADMIN_USERNAME, FACTORY_ADMIN_PASSWORD, true));
|
||||
settings.users.push_back(User(FACTORY_GUEST_USERNAME, FACTORY_GUEST_PASSWORD, false));
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -64,7 +77,7 @@ class SecuritySettingsService : public StatefulService<SecuritySettings>, public
|
||||
private:
|
||||
HttpEndpoint<SecuritySettings> _httpEndpoint;
|
||||
FSPersistence<SecuritySettings> _fsPersistence;
|
||||
ArduinoJsonJWT _jwtHandler = ArduinoJsonJWT(DEFAULT_JWT_SECRET);
|
||||
ArduinoJsonJWT _jwtHandler = ArduinoJsonJWT(FACTORY_JWT_SECRET);
|
||||
|
||||
void configureJWTHandler();
|
||||
|
||||
|
@ -10,6 +10,18 @@
|
||||
#define WIFI_SETTINGS_SERVICE_PATH "/rest/wifiSettings"
|
||||
#define WIFI_RECONNECTION_DELAY 1000 * 30
|
||||
|
||||
#ifndef FACTORY_WIFI_SSID
|
||||
#define FACTORY_WIFI_SSID ""
|
||||
#endif
|
||||
|
||||
#ifndef FACTORY_WIFI_PASSWORD
|
||||
#define FACTORY_WIFI_PASSWORD ""
|
||||
#endif
|
||||
|
||||
#ifndef FACTORY_WIFI_HOSTNAME
|
||||
#define FACTORY_WIFI_HOSTNAME ""
|
||||
#endif
|
||||
|
||||
class WiFiSettings {
|
||||
public:
|
||||
// core wifi configuration
|
||||
@ -41,9 +53,9 @@ class WiFiSettings {
|
||||
}
|
||||
|
||||
static void deserialize(JsonObject& root, WiFiSettings& settings) {
|
||||
settings.ssid = root["ssid"] | "";
|
||||
settings.password = root["password"] | "";
|
||||
settings.hostname = root["hostname"] | "";
|
||||
settings.ssid = root["ssid"] | FACTORY_WIFI_SSID;
|
||||
settings.password = root["password"] | FACTORY_WIFI_PASSWORD;
|
||||
settings.hostname = root["hostname"] | FACTORY_WIFI_HOSTNAME;
|
||||
settings.staticIPConfig = root["static_ip_config"] | false;
|
||||
|
||||
// extended settings
|
||||
|
Reference in New Issue
Block a user