mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-07 00:09:51 +03:00
auto update settings 1.9->2.0. Closes #431
This commit is contained in:
@@ -6,93 +6,97 @@
|
|||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
class FSPersistence {
|
class FSPersistence {
|
||||||
public:
|
public:
|
||||||
FSPersistence(JsonStateReader<T> stateReader,
|
FSPersistence(JsonStateReader<T> stateReader,
|
||||||
JsonStateUpdater<T> stateUpdater,
|
JsonStateUpdater<T> stateUpdater,
|
||||||
StatefulService<T>* statefulService,
|
StatefulService<T> * statefulService,
|
||||||
FS* fs,
|
FS * fs,
|
||||||
char const* filePath,
|
char const * filePath,
|
||||||
size_t bufferSize = DEFAULT_BUFFER_SIZE) :
|
size_t bufferSize = DEFAULT_BUFFER_SIZE)
|
||||||
_stateReader(stateReader),
|
: _stateReader(stateReader)
|
||||||
_stateUpdater(stateUpdater),
|
, _stateUpdater(stateUpdater)
|
||||||
_statefulService(statefulService),
|
, _statefulService(statefulService)
|
||||||
_fs(fs),
|
, _fs(fs)
|
||||||
_filePath(filePath),
|
, _filePath(filePath)
|
||||||
_bufferSize(bufferSize),
|
, _bufferSize(bufferSize)
|
||||||
_updateHandlerId(0) {
|
, _updateHandlerId(0) {
|
||||||
enableUpdateHandler();
|
enableUpdateHandler();
|
||||||
}
|
}
|
||||||
|
|
||||||
void readFromFS() {
|
void readFromFS() {
|
||||||
File settingsFile = _fs->open(_filePath, "r");
|
File settingsFile = _fs->open(_filePath, "r");
|
||||||
|
|
||||||
if (settingsFile) {
|
if (settingsFile) {
|
||||||
DynamicJsonDocument jsonDocument = DynamicJsonDocument(_bufferSize);
|
DynamicJsonDocument jsonDocument = DynamicJsonDocument(_bufferSize);
|
||||||
DeserializationError error = deserializeJson(jsonDocument, settingsFile);
|
DeserializationError error = deserializeJson(jsonDocument, settingsFile);
|
||||||
if (error == DeserializationError::Ok && jsonDocument.is<JsonObject>()) {
|
if (error == DeserializationError::Ok && jsonDocument.is<JsonObject>()) {
|
||||||
JsonObject jsonObject = jsonDocument.as<JsonObject>();
|
JsonObject jsonObject = jsonDocument.as<JsonObject>();
|
||||||
_statefulService->updateWithoutPropagation(jsonObject, _stateUpdater);
|
_statefulService->updateWithoutPropagation(jsonObject, _stateUpdater);
|
||||||
|
settingsFile.close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
settingsFile.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we reach here we have not been successful in loading the config,
|
||||||
|
// hard-coded emergency defaults are now applied.
|
||||||
|
applyDefaults();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool writeToFS() {
|
||||||
|
// create and populate a new json object
|
||||||
|
DynamicJsonDocument jsonDocument = DynamicJsonDocument(_bufferSize);
|
||||||
|
JsonObject jsonObject = jsonDocument.to<JsonObject>();
|
||||||
|
_statefulService->read(jsonObject, _stateReader);
|
||||||
|
|
||||||
|
// serialize it to filesystem
|
||||||
|
File settingsFile = _fs->open(_filePath, "w");
|
||||||
|
|
||||||
|
// failed to open file, return false
|
||||||
|
if (!settingsFile) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serial.printf("Write File: %s: ", _filePath);
|
||||||
|
// serializeJson(jsonDocument, Serial);
|
||||||
|
// Serial.println();
|
||||||
|
|
||||||
|
// serialize the data to the file
|
||||||
|
serializeJson(jsonDocument, settingsFile);
|
||||||
settingsFile.close();
|
settingsFile.close();
|
||||||
return;
|
return true;
|
||||||
}
|
|
||||||
settingsFile.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we reach here we have not been successful in loading the config,
|
void disableUpdateHandler() {
|
||||||
// hard-coded emergency defaults are now applied.
|
if (_updateHandlerId) {
|
||||||
applyDefaults();
|
_statefulService->removeUpdateHandler(_updateHandlerId);
|
||||||
}
|
_updateHandlerId = 0;
|
||||||
|
}
|
||||||
bool writeToFS() {
|
|
||||||
// create and populate a new json object
|
|
||||||
DynamicJsonDocument jsonDocument = DynamicJsonDocument(_bufferSize);
|
|
||||||
JsonObject jsonObject = jsonDocument.to<JsonObject>();
|
|
||||||
_statefulService->read(jsonObject, _stateReader);
|
|
||||||
|
|
||||||
// serialize it to filesystem
|
|
||||||
File settingsFile = _fs->open(_filePath, "w");
|
|
||||||
|
|
||||||
// failed to open file, return false
|
|
||||||
if (!settingsFile) {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// serialize the data to the file
|
void enableUpdateHandler() {
|
||||||
serializeJson(jsonDocument, settingsFile);
|
if (!_updateHandlerId) {
|
||||||
settingsFile.close();
|
_updateHandlerId = _statefulService->addUpdateHandler([&](const String & originId) { writeToFS(); });
|
||||||
return true;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void disableUpdateHandler() {
|
|
||||||
if (_updateHandlerId) {
|
|
||||||
_statefulService->removeUpdateHandler(_updateHandlerId);
|
|
||||||
_updateHandlerId = 0;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void enableUpdateHandler() {
|
private:
|
||||||
if (!_updateHandlerId) {
|
JsonStateReader<T> _stateReader;
|
||||||
_updateHandlerId = _statefulService->addUpdateHandler([&](const String& originId) { writeToFS(); });
|
JsonStateUpdater<T> _stateUpdater;
|
||||||
|
StatefulService<T> * _statefulService;
|
||||||
|
FS * _fs;
|
||||||
|
char const * _filePath;
|
||||||
|
size_t _bufferSize;
|
||||||
|
update_handler_id_t _updateHandlerId;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// We assume the updater supplies sensible defaults if an empty object
|
||||||
|
// is supplied, this virtual function allows that to be changed.
|
||||||
|
virtual void applyDefaults() {
|
||||||
|
DynamicJsonDocument jsonDocument = DynamicJsonDocument(_bufferSize);
|
||||||
|
JsonObject jsonObject = jsonDocument.as<JsonObject>();
|
||||||
|
_statefulService->updateWithoutPropagation(jsonObject, _stateUpdater);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
JsonStateReader<T> _stateReader;
|
|
||||||
JsonStateUpdater<T> _stateUpdater;
|
|
||||||
StatefulService<T>* _statefulService;
|
|
||||||
FS* _fs;
|
|
||||||
char const* _filePath;
|
|
||||||
size_t _bufferSize;
|
|
||||||
update_handler_id_t _updateHandlerId;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
// We assume the updater supplies sensible defaults if an empty object
|
|
||||||
// is supplied, this virtual function allows that to be changed.
|
|
||||||
virtual void applyDefaults() {
|
|
||||||
DynamicJsonDocument jsonDocument = DynamicJsonDocument(_bufferSize);
|
|
||||||
JsonObject jsonObject = jsonDocument.as<JsonObject>();
|
|
||||||
_statefulService->updateWithoutPropagation(jsonObject, _stateUpdater);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // end FSPersistence
|
#endif // end FSPersistence
|
||||||
|
|||||||
@@ -786,21 +786,24 @@ void EMSESP::send_raw_telegram(const char * data) {
|
|||||||
// start all the core services
|
// start all the core services
|
||||||
// the services must be loaded in the correct order
|
// the services must be loaded in the correct order
|
||||||
void EMSESP::start() {
|
void EMSESP::start() {
|
||||||
|
// see if we need to migrate from previous versions
|
||||||
|
if (!system_.check_upgrade()) {
|
||||||
|
#ifdef ESP32
|
||||||
|
SPIFFS.begin(true);
|
||||||
|
#elif defined(ESP8266)
|
||||||
|
LittleFS.begin();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
esp8266React.begin(); // loads system settings (wifi, mqtt, etc)
|
||||||
|
emsespSettingsService.begin(); // load EMS-ESP specific settings
|
||||||
|
}
|
||||||
|
|
||||||
// Load our library of known devices. Names are stored in Flash mem.
|
// Load our library of known devices. Names are stored in Flash mem.
|
||||||
device_library_.reserve(80);
|
device_library_.reserve(80);
|
||||||
device_library_ = {
|
device_library_ = {
|
||||||
#include "device_library.h"
|
#include "device_library.h"
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef ESP32
|
|
||||||
SPIFFS.begin(true);
|
|
||||||
#elif defined(ESP8266)
|
|
||||||
LittleFS.begin();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
esp8266React.begin(); // loads system settings (wifi, mqtt, etc)
|
|
||||||
emsespSettingsService.begin(); // load EMS-ESP specific settings
|
|
||||||
// system_.check_upgrade(); // see if we need to migrate from previous versions
|
|
||||||
console_.start(); // telnet and serial console
|
console_.start(); // telnet and serial console
|
||||||
mqtt_.start(); // mqtt init
|
mqtt_.start(); // mqtt init
|
||||||
system_.start(); // starts syslog, uart, sets version, initializes LED. Requires pre-loaded settings.
|
system_.start(); // starts syslog, uart, sets version, initializes LED. Requires pre-loaded settings.
|
||||||
|
|||||||
@@ -590,74 +590,71 @@ void System::console_commands(Shell & shell, unsigned int context) {
|
|||||||
Console::enter_custom_context(shell, context);
|
Console::enter_custom_context(shell, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
// upgrade from previous versions of EMS-ESP
|
// upgrade from previous versions of EMS-ESP, based on SPIFFS on an ESP8266
|
||||||
void System::check_upgrade() {
|
// returns true if an upgrade was done
|
||||||
/*
|
bool System::check_upgrade() {
|
||||||
// check for v1.9. It uses SPIFFS and only on the ESP8266
|
|
||||||
#if defined(ESP8266)
|
#if defined(ESP8266)
|
||||||
Serial.begin(115200);
|
|
||||||
|
|
||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||||
|
|
||||||
LittleFS.end();
|
SPIFFSConfig cfg;
|
||||||
SPIFFS.begin();
|
cfg.setAutoFormat(false); // prevent formatting when opening SPIFFS filesystem
|
||||||
|
SPIFFS.setConfig(cfg);
|
||||||
// first file
|
if (!SPIFFS.begin()) {
|
||||||
File file = SPIFFS.open("/myesp.json", "r");
|
return false; // is not SPIFFS
|
||||||
if (!file) {
|
|
||||||
Serial.println(F("Old config doesn't exist."));
|
|
||||||
SPIFFS.end();
|
|
||||||
LittleFS.begin();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Serial.begin(115200);
|
||||||
|
|
||||||
|
// open the two files
|
||||||
|
File file1 = SPIFFS.open("/myesp.json", "r");
|
||||||
|
File file2 = SPIFFS.open("/customconfig.json", "r");
|
||||||
|
if (!file1 || !file2) {
|
||||||
|
Serial.println(F("Unable to read the config files"));
|
||||||
|
file1.close();
|
||||||
|
file2.close();
|
||||||
|
SPIFFS.end();
|
||||||
|
return false; // can't open files
|
||||||
|
}
|
||||||
|
|
||||||
|
// read the content of the files
|
||||||
DeserializationError error;
|
DeserializationError error;
|
||||||
StaticJsonDocument<1024> doc; // for myESP settings
|
StaticJsonDocument<1024> doc1; // for myESP settings
|
||||||
error = deserializeJson(doc, file);
|
|
||||||
if (error) {
|
|
||||||
Serial.printf("Error. Failed to deserialize json, error %s", error.c_str());
|
|
||||||
file.close();
|
|
||||||
SPIFFS.end();
|
|
||||||
LittleFS.begin();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
file.close();
|
|
||||||
|
|
||||||
// second file
|
|
||||||
file = SPIFFS.open("/customconfig.json", "r");
|
|
||||||
if (!file) {
|
|
||||||
Serial.println(F("Old custom config file doesn't exist"));
|
|
||||||
SPIFFS.end();
|
|
||||||
LittleFS.begin();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
StaticJsonDocument<1024> doc2; // for custom EMS-ESP settings
|
StaticJsonDocument<1024> doc2; // for custom EMS-ESP settings
|
||||||
error = deserializeJson(doc2, file);
|
bool failed = false;
|
||||||
|
|
||||||
|
error = deserializeJson(doc1, file1);
|
||||||
if (error) {
|
if (error) {
|
||||||
Serial.printf("Error. Failed to deserialize json, error %s", error.c_str());
|
Serial.printf("Error. Failed to deserialize json, doc1, error %s", error.c_str());
|
||||||
file.close();
|
failed = true;
|
||||||
SPIFFS.end();
|
}
|
||||||
LittleFS.begin();
|
error = deserializeJson(doc2, file2);
|
||||||
return;
|
if (error) {
|
||||||
|
Serial.printf("Error. Failed to deserialize json, doc2, error %s", error.c_str());
|
||||||
|
failed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
file.close();
|
file1.close();
|
||||||
|
file2.close();
|
||||||
// close SPIFFS and open LittleFS
|
|
||||||
SPIFFS.end();
|
SPIFFS.end();
|
||||||
LittleFS.begin();
|
|
||||||
|
if (failed) {
|
||||||
|
return false; // parse error
|
||||||
|
}
|
||||||
|
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
|
|
||||||
|
LittleFS.begin();
|
||||||
|
EMSESP::esp8266React.begin(); // loads system settings (wifi, mqtt, etc)
|
||||||
|
EMSESP::emsespSettingsService.begin(); // load EMS-ESP specific settings
|
||||||
|
|
||||||
Serial.println(F("Migrating settings from EMS-ESP 1.9.x..."));
|
Serial.println(F("Migrating settings from EMS-ESP 1.9.x..."));
|
||||||
|
|
||||||
// get the json objects
|
// get the json objects
|
||||||
JsonObject network = doc["network"];
|
JsonObject network = doc1["network"];
|
||||||
JsonObject general = doc["general"];
|
JsonObject general = doc1["general"];
|
||||||
JsonObject mqtt = doc["mqtt"];
|
JsonObject mqtt = doc1["mqtt"];
|
||||||
JsonObject custom_settings = doc2["settings"]; // from 2nd file
|
JsonObject custom_settings = doc2["settings"]; // from 2nd file
|
||||||
|
|
||||||
EMSESP::esp8266React.getWiFiSettingsService()->update(
|
EMSESP::esp8266React.getWiFiSettingsService()->update(
|
||||||
@@ -717,8 +714,10 @@ void System::check_upgrade() {
|
|||||||
return StateUpdateResult::CHANGED;
|
return StateUpdateResult::CHANGED;
|
||||||
},
|
},
|
||||||
"local");
|
"local");
|
||||||
|
|
||||||
|
Serial.end();
|
||||||
|
return true;
|
||||||
#endif
|
#endif
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace emsesp
|
} // namespace emsesp
|
||||||
|
|||||||
18
src/system.h
18
src/system.h
@@ -54,18 +54,12 @@ class System {
|
|||||||
static uint8_t free_mem();
|
static uint8_t free_mem();
|
||||||
static void upload_status(bool in_progress);
|
static void upload_status(bool in_progress);
|
||||||
static bool upload_status();
|
static bool upload_status();
|
||||||
|
void syslog_init();
|
||||||
void syslog_init();
|
void set_heartbeat(bool system_heartbeat);
|
||||||
|
void send_heartbeat();
|
||||||
// heartbeat
|
static void show_mem(const char * note);
|
||||||
void set_heartbeat(bool system_heartbeat);
|
static void set_led();
|
||||||
void send_heartbeat();
|
bool check_upgrade();
|
||||||
|
|
||||||
static void show_mem(const char * note);
|
|
||||||
|
|
||||||
static void set_led();
|
|
||||||
|
|
||||||
void check_upgrade();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static uuid::log::Logger logger_;
|
static uuid::log::Logger logger_;
|
||||||
|
|||||||
Reference in New Issue
Block a user