#ifndef FSPersistence_h #define FSPersistence_h #include "StatefulService.h" #include "FS.h" template class FSPersistence { public: FSPersistence(JsonStateReader stateReader, JsonStateUpdater stateUpdater, StatefulService * statefulService, FS * fs, const char * filePath) : _stateReader(stateReader) , _stateUpdater(stateUpdater) , _statefulService(statefulService) , _fs(fs) , _filePath(filePath) , _updateHandlerId(0) { enableUpdateHandler(); } void readFromFS() { File settingsFile = _fs->open(_filePath, "r"); if (settingsFile) { JsonDocument jsonDocument; DeserializationError error = deserializeJson(jsonDocument, settingsFile); if (error == DeserializationError::Ok && jsonDocument.is()) { JsonObject jsonObject = jsonDocument.as(); _statefulService->updateWithoutPropagation(jsonObject, _stateUpdater); #if defined(EMSESP_DEBUG) // Serial.println(); // Serial.printf("Reading settings from %s ", _filePath); // serializeJson(jsonDocument, Serial); // Serial.println(); #endif 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. #if defined(EMSESP_DEBUG) // Serial.println(); // Serial.printf("Applying defaults to %s", _filePath); // Serial.println(); #endif applyDefaults(); writeToFS(); // added to make sure the initial file is created } bool writeToFS() { // create and populate a new json object JsonDocument jsonDocument; JsonObject jsonObject = jsonDocument.to(); _statefulService->read(jsonObject, _stateReader); // make directories if required, for new IDF4.2 & LittleFS String path(_filePath); int index = 0; while ((index = path.indexOf('/', static_cast(index) + 1)) != -1) { String segment = path.substring(0, static_cast(index)); if (!_fs->exists(segment)) { _fs->mkdir(segment); } } // serialize it to filesystem File settingsFile = _fs->open(_filePath, "w"); // failed to open file, return false if (!settingsFile || !jsonObject.size()) { return false; } // serialize the data to the file #if defined(EMSESP_DEBUG) // Serial.println(); // Serial.printf("Writing settings to %s ", _filePath); // serializeJson(jsonDocument, Serial); // Serial.println(); #endif serializeJson(jsonDocument, settingsFile); settingsFile.close(); return true; } void disableUpdateHandler() { if (_updateHandlerId) { _statefulService->removeUpdateHandler(_updateHandlerId); _updateHandlerId = 0; } } void enableUpdateHandler() { if (!_updateHandlerId) { _updateHandlerId = _statefulService->addUpdateHandler([&] { writeToFS(); }); } } private: JsonStateReader _stateReader; JsonStateUpdater _stateUpdater; StatefulService * _statefulService; FS * _fs; const char * _filePath; 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() { JsonDocument jsonDocument; JsonObject jsonObject = jsonDocument.as(); _statefulService->updateWithoutPropagation(jsonObject, _stateUpdater); } }; #endif