From 57bda044e59580bcdc95351ac3fb5fb73112f353 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sat, 18 Mar 2023 01:37:59 +0100 Subject: [PATCH] 0.5.102 Warning: old exports are not compatible any more! further save settings improvements (only store inverters which are existing) improved display of settings save return value made save settings asynchronous (more heap memory is free) --- src/CHANGES.md | 4 +++ src/app.cpp | 2 ++ src/app.h | 25 ++++++++++++++++-- src/appInterface.h | 2 ++ src/config/settings.h | 57 ++++++++++++++++++++++++++--------------- src/web/RestApi.h | 17 +++++++++--- src/web/html/index.html | 4 +-- src/web/html/setup.html | 12 ++++----- src/web/web.h | 17 +++++++----- 9 files changed, 99 insertions(+), 41 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 131e891d..4c1346cb 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -3,8 +3,12 @@ (starting from release version `0.5.66`) ## 0.5.102 +* Warning: old exports are not compatible any more! * fix JSON import #775 * fix save settings, at least already stored settings are not lost #771 +* further save settings improvements (only store inverters which are existing) +* improved display of settings save return value +* made save settings asynchronous (more heap memory is free) ## 0.5.101 * fix SSD1306 diff --git a/src/app.cpp b/src/app.cpp index a69d73a1..23030d76 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -374,6 +374,8 @@ void app::resetSystem(void) { mSendLastIvId = 0; mShowRebootRequest = false; mIVCommunicationOn = true; + mSavePending = false; + mSaveReboot = false; memset(&mStat, 0, sizeof(statistics_t)); } diff --git a/src/app.h b/src/app.h index a792ffe8..afd90565 100644 --- a/src/app.h +++ b/src/app.h @@ -68,9 +68,12 @@ class app : public IApp, public ah::Scheduler { return Scheduler::getTimestamp(); } - bool saveSettings(bool stopFs = false) { + bool saveSettings(bool reboot) { mShowRebootRequest = true; // only message on index, no reboot - return mSettings.saveSettings(stopFs); + mSavePending = true; + mSaveReboot = reboot; + once(std::bind(&app::tickSave, this), 2, "save"); + return true; } bool readSettings(const char *path) { @@ -81,6 +84,14 @@ class app : public IApp, public ah::Scheduler { return mSettings.eraseSettings(eraseWifi); } + bool getSavePending() { + return mSavePending; + } + + bool getLastSaveSucceed() { + return mSettings.getLastSaveSucceed(); + } + statistics_t *getStatistics() { return &mStat; } @@ -214,6 +225,14 @@ class app : public IApp, public ah::Scheduler { ESP.restart(); } + void tickSave(void) { + mSettings.saveSettings(); + mSavePending = false; + + if(mSaveReboot) + once(std::bind(&app::tickReboot, this), 2, "rboot"); + } + void tickNtpUpdate(void); void tickCalcSunrise(void); void tickIVCommunication(void); @@ -253,6 +272,8 @@ class app : public IApp, public ah::Scheduler { char mVersion[12]; settings mSettings; settings_t *mConfig; + bool mSavePending; + bool mSaveReboot; uint8_t mSendLastIvId; bool mSendFirst; diff --git a/src/appInterface.h b/src/appInterface.h index 4c7d6042..a79dcdb1 100644 --- a/src/appInterface.h +++ b/src/appInterface.h @@ -17,6 +17,8 @@ class IApp { virtual bool saveSettings(bool stopFs) = 0; virtual bool readSettings(const char *path) = 0; virtual bool eraseSettings(bool eraseWifi) = 0; + virtual bool getSavePending() = 0; + virtual bool getLastSaveSucceed() = 0; virtual void setOnUpdate() = 0; virtual void setRebootFlag() = 0; virtual const char *getVersion() = 0; diff --git a/src/config/settings.h b/src/config/settings.h index 29974862..24bb6a9e 100644 --- a/src/config/settings.h +++ b/src/config/settings.h @@ -15,9 +15,9 @@ #include "../utils/helper.h" #if defined(ESP32) - #define MAX_ALLOWED_BUF_SIZE ESP.getMaxAllocHeap() - 2048 + #define MAX_ALLOWED_BUF_SIZE ESP.getMaxAllocHeap() - 1024 #else - #define MAX_ALLOWED_BUF_SIZE ESP.getMaxFreeBlockSize() - 2048 + #define MAX_ALLOWED_BUF_SIZE ESP.getMaxFreeBlockSize() - 1024 #endif /** @@ -161,7 +161,9 @@ typedef struct { class settings { public: - settings() {} + settings() { + mLastSaveSucceed = false; + } void setup() { DPRINTLN(DBG_INFO, F("Initializing FS ..")); @@ -208,6 +210,10 @@ class settings { return mCfg.valid; } + inline bool getLastSaveSucceed() { + return mLastSaveSucceed; + } + void getInfo(uint32_t *used, uint32_t *size) { #if !defined(ESP32) FSInfo info; @@ -254,7 +260,7 @@ class settings { return mCfg.valid; } - bool saveSettings(bool stopFs = false) { + bool saveSettings() { DPRINTLN(DBG_DEBUG, F("save settings")); DynamicJsonDocument json(MAX_ALLOWED_BUF_SIZE); @@ -269,31 +275,35 @@ class settings { jsonPlugin(root.createNestedObject(F("plugin")), true); jsonInst(root.createNestedObject(F("inst")), true); - DPRINT(DBG_INFO, "memory usage: "); + DPRINT(DBG_INFO, F("memory usage: ")); DBGPRINTLN(String(json.memoryUsage())); + DPRINT(DBG_INFO, F("capacity: ")); + DBGPRINTLN(String(json.capacity())); + DPRINT(DBG_INFO, F("max alloc: ")); + DBGPRINTLN(String(MAX_ALLOWED_BUF_SIZE)); if(json.overflowed()) { DPRINTLN(DBG_ERROR, F("buffer too small!")); + mLastSaveSucceed = false; return false; } File fp = LittleFS.open("/settings.json", "w"); if(!fp) { DPRINTLN(DBG_ERROR, F("can't open settings file!")); + mLastSaveSucceed = false; return false; } if(0 == serializeJson(root, fp)) { DPRINTLN(DBG_ERROR, F("can't write settings file!")); + mLastSaveSucceed = false; return false; } fp.close(); - DPRINTLN(DBG_INFO, F("settings saved")); - if(stopFs) - stop(); - + mLastSaveSucceed = true; return true; } @@ -301,7 +311,7 @@ class settings { if(true == eraseWifi) return LittleFS.format(); loadDefaults(!eraseWifi); - return saveSettings(true); + return saveSettings(); } private: @@ -549,36 +559,41 @@ class settings { if(set) ivArr = obj.createNestedArray(F("iv")); for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { - if(set) - jsonIv(ivArr.createNestedObject(), &mCfg.inst.iv[i], true); - else - jsonIv(obj[F("iv")][i], &mCfg.inst.iv[i]); + if(set) { + if(mCfg.inst.iv[i].serial.u64 != 0ULL) + jsonIv(ivArr.createNestedObject(), &mCfg.inst.iv[i], true); + } + else { + if(!obj[F("iv")][i].isNull()) + jsonIv(obj[F("iv")][i], &mCfg.inst.iv[i]); + } } } void jsonIv(JsonObject obj, cfgIv_t *cfg, bool set = false) { if(set) { - obj[F("en")] = (bool)cfg->enabled; - obj[F("name")] = cfg->name; - obj[F("sn")] = cfg->serial.u64; + obj[F("en")] = (bool)cfg->enabled; + obj[F("name")] = cfg->name; + obj[F("sn")] = cfg->serial.u64; for(uint8_t i = 0; i < 4; i++) { - obj[F("yield")][i] = cfg->yieldCor[i]; + obj[F("yc")][i] = cfg->yieldCor[i]; obj[F("pwr")][i] = cfg->chMaxPwr[i]; - obj[F("chName")][i] = cfg->chName[i]; + obj[F("chn")][i] = cfg->chName[i]; } } else { cfg->enabled = (bool)obj[F("en")]; snprintf(cfg->name, MAX_NAME_LENGTH, "%s", obj[F("name")].as()); cfg->serial.u64 = obj[F("sn")]; for(uint8_t i = 0; i < 4; i++) { - cfg->yieldCor[i] = obj[F("yield")][i]; + cfg->yieldCor[i] = obj[F("yc")][i]; cfg->chMaxPwr[i] = obj[F("pwr")][i]; - snprintf(cfg->chName[i], MAX_NAME_LENGTH, "%s", obj[F("chName")][i].as()); + snprintf(cfg->chName[i], MAX_NAME_LENGTH, "%s", obj[F("chn")][i].as()); } } } settings_t mCfg; + bool mLastSaveSucceed; }; #endif /*__SETTINGS_H__*/ diff --git a/src/web/RestApi.h b/src/web/RestApi.h index 9b14e439..ecabd1f4 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -80,6 +80,7 @@ class RestApi { if(path == "html/system") getHtmlSystem(root); else if(path == "html/logout") getHtmlLogout(root); else if(path == "html/save") getHtmlSave(root); + else if(path == "html/chk_save") getHtmlChkSave(root); else if(path == "system") getSysInfo(root); else if(path == "generic") getGeneric(root); else if(path == "reboot") getReboot(root); @@ -266,9 +267,19 @@ class RestApi { void getHtmlSave(JsonObject obj) { getGeneric(obj.createNestedObject(F("generic"))); - obj[F("refresh")] = 2; - obj[F("refresh_url")] = "/setup"; - obj[F("html")] = F("settings succesfully save"); + obj[F("refresh")] = 1; + obj[F("refresh_url")] = F("/chk_save"); + obj[F("html")] = F("saving settings ..."); + } + + void getHtmlChkSave(JsonObject obj) { + getGeneric(obj.createNestedObject(F("generic"))); + obj[F("refresh")] = (mApp->getLastSaveSucceed()) ? 10 : 1; + obj[F("refresh_url")] = mApp->getSavePending() ? F("/chk_save") : F("/setup"); + if(mApp->getSavePending()) + obj[F("html")] = F("saving settings ..."); + else + obj[F("html")] = mApp->getLastSaveSucceed() ? F("settings succesfully saved") : F("failed saving settings"); } void getReboot(JsonObject obj) { diff --git a/src/web/html/index.html b/src/web/html/index.html index 27a46a9c..72537e5e 100644 --- a/src/web/html/index.html +++ b/src/web/html/index.html @@ -102,12 +102,12 @@ if(obj["disNightComm"]) { if(((obj["ts_sunrise"] - obj["ts_offset"]) < obj["ts_now"]) && ((obj["ts_sunset"] + obj["ts_offset"]) > obj["ts_now"])) { - commInfo = "Polling inverter(s), will stop at sunset " + (new Date((obj["ts_sunset"] + obj["ts_offset"]) * 1000).toLocaleString('de-DE')); + commInfo = "Polling inverter(s), will pause at sunset " + (new Date((obj["ts_sunset"] + obj["ts_offset"]) * 1000).toLocaleString('de-DE')); } else { commInfo = "Night time, inverter polling disabled, "; if(obj["ts_now"] > (obj["ts_sunrise"] - obj["ts_offset"])) { - commInfo += "stopped at " + (new Date((obj["ts_sunset"] + obj["ts_offset"]) * 1000).toLocaleString('de-DE')); + commInfo += "paused at " + (new Date((obj["ts_sunset"] + obj["ts_offset"]) * 1000).toLocaleString('de-DE')); } else { commInfo += "will start polling at " + (new Date((obj["ts_sunrise"] - obj["ts_offset"]) * 1000).toLocaleString('de-DE')); diff --git a/src/web/html/setup.html b/src/web/html/setup.html index 58144219..93841461 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -157,7 +157,7 @@
-
Reset values when inverter polling stops at sunset
+
Reset values when inverter polling pauses at sunset
@@ -209,7 +209,7 @@
-
Stop polling inverters during night
+
Pause polling inverters during night
@@ -291,8 +291,8 @@
Import / Export JSON Settings
-
Import
-
+
Import
+
@@ -300,8 +300,8 @@
-
Export
-
+
Export
+
Export settings (JSON file) (only values, passwords will be removed!)
diff --git a/src/web/web.h b/src/web/web.h index 814259b8..c1726f87 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -68,6 +68,7 @@ class Web { mWeb.on("/setup", HTTP_GET, std::bind(&Web::onSetup, this, std::placeholders::_1)); mWeb.on("/save", HTTP_ANY, std::bind(&Web::showSave, this, std::placeholders::_1)); + mWeb.on("/chk_save", HTTP_ANY, std::bind(&Web::onCheckSave, this, std::placeholders::_1)); mWeb.on("/live", HTTP_ANY, std::bind(&Web::onLive, this, std::placeholders::_1)); //mWeb.on("/api1", HTTP_POST, std::bind(&Web::showWebApi, this, std::placeholders::_1)); @@ -592,13 +593,15 @@ class Web { mApp->saveSettings((request->arg("reboot") == "on")); - if (request->arg("reboot") == "on") - onReboot(request); - else { - AsyncWebServerResponse *response = request->beginResponse_P(200, F("text/html; charset=UTF-8"), system_html, system_html_len); - response->addHeader(F("Content-Encoding"), "gzip"); - request->send(response); - } + AsyncWebServerResponse *response = request->beginResponse_P(200, F("text/html; charset=UTF-8"), system_html, system_html_len); + response->addHeader(F("Content-Encoding"), "gzip"); + request->send(response); + } + + void onCheckSave(AsyncWebServerRequest *request) { + AsyncWebServerResponse *response = request->beginResponse_P(200, F("text/html; charset=UTF-8"), system_html, system_html_len); + response->addHeader(F("Content-Encoding"), "gzip"); + request->send(response); } void onLive(AsyncWebServerRequest *request) {