Fork of the excellent esp8266-react - https://github.com/rjwats/esp8266-react
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

96 lines
2.8 KiB

  1. #ifndef SettingsPersistence_h
  2. #define SettingsPersistence_h
  3. #include <ArduinoJson.h>
  4. #include <AsyncJson.h>
  5. #include <AsyncJsonWebHandler.h>
  6. #include <ESPAsyncWebServer.h>
  7. #include <FS.h>
  8. /**
  9. * At the moment, not expecting settings service to have to deal with large JSON
  10. * files this could be made configurable fairly simply, it's exposed on
  11. * AsyncJsonWebHandler with a setter.
  12. */
  13. #define MAX_SETTINGS_SIZE 1024
  14. /*
  15. * Mixin for classes which need to save settings to/from a file on the the file system as JSON.
  16. */
  17. class SettingsPersistence {
  18. protected:
  19. // will store and retrieve config from the file system
  20. FS* _fs;
  21. // the file path our settings will be saved to
  22. char const* _filePath;
  23. bool writeToFS() {
  24. // create and populate a new json object
  25. DynamicJsonDocument jsonDocument = DynamicJsonDocument(MAX_SETTINGS_SIZE);
  26. JsonObject root = jsonDocument.to<JsonObject>();
  27. writeToJsonObject(root);
  28. // serialize it to filesystem
  29. File configFile = _fs->open(_filePath, "w");
  30. // failed to open file, return false
  31. if (!configFile) {
  32. return false;
  33. }
  34. serializeJson(jsonDocument, configFile);
  35. configFile.close();
  36. return true;
  37. }
  38. void readFromFS() {
  39. File configFile = _fs->open(_filePath, "r");
  40. // use defaults if no config found
  41. if (configFile) {
  42. // Protect against bad data uploaded to file system
  43. // We never expect the config file to get very large, so cap it.
  44. size_t size = configFile.size();
  45. if (size <= MAX_SETTINGS_SIZE) {
  46. DynamicJsonDocument jsonDocument = DynamicJsonDocument(MAX_SETTINGS_SIZE);
  47. DeserializationError error = deserializeJson(jsonDocument, configFile);
  48. if (error == DeserializationError::Ok && jsonDocument.is<JsonObject>()) {
  49. JsonObject root = jsonDocument.as<JsonObject>();
  50. readFromJsonObject(root);
  51. configFile.close();
  52. return;
  53. }
  54. }
  55. configFile.close();
  56. }
  57. // If we reach here we have not been successful in loading the config,
  58. // hard-coded emergency defaults are now applied.
  59. applyDefaultConfig();
  60. }
  61. // serialization routene, from local config to JsonObject
  62. virtual void readFromJsonObject(JsonObject& root) {
  63. }
  64. virtual void writeToJsonObject(JsonObject& root) {
  65. }
  66. // We assume the readFromJsonObject supplies sensible defaults if an empty object
  67. // is supplied, this virtual function allows that to be changed.
  68. virtual void applyDefaultConfig() {
  69. DynamicJsonDocument jsonDocument = DynamicJsonDocument(MAX_SETTINGS_SIZE);
  70. JsonObject root = jsonDocument.to<JsonObject>();
  71. readFromJsonObject(root);
  72. }
  73. public:
  74. SettingsPersistence(FS* fs, char const* filePath) : _fs(fs), _filePath(filePath) {
  75. }
  76. virtual ~SettingsPersistence() {
  77. }
  78. };
  79. #endif // end SettingsPersistence