diff --git a/.github/workflows/compile_development.yml b/.github/workflows/compile_development.yml index ec435880..59460d5c 100644 --- a/.github/workflows/compile_development.yml +++ b/.github/workflows/compile_development.yml @@ -47,7 +47,7 @@ jobs: run: python convert.py - name: Run PlatformIO - run: pio run -d src --environment esp8266-release --environment esp8285-release --environment esp32-wroom32-release + run: pio run -d src --environment esp8266-release --environment esp8266-release-prometheus --environment esp8285-release --environment esp32-wroom32-release --environment esp32-wroom32-release-prometheus - name: Rename Binary files id: rename-binary-files diff --git a/.github/workflows/compile_release.yml b/.github/workflows/compile_release.yml index 91ae35bf..bd7cef5a 100644 --- a/.github/workflows/compile_release.yml +++ b/.github/workflows/compile_release.yml @@ -51,7 +51,7 @@ jobs: run: python convert.py - name: Run PlatformIO - run: pio run -d src --environment esp8266-release --environment esp8285-release --environment esp32-wroom32-release + run: pio run -d src --environment esp8266-release --environment esp8266-release-prometheus --environment esp8285-release --environment esp32-wroom32-release --environment esp32-wroom32-release-prometheus - name: Rename Binary files id: rename-binary-files diff --git a/User_Manual.md b/User_Manual.md index 242f5152..b605f3c9 100644 --- a/User_Manual.md +++ b/User_Manual.md @@ -91,9 +91,6 @@ The AhoyDTU will publish on the following topics ## Active Power Limit via Serial / Control Page URL: `/serial` -If you leave the field "Active Power Limit" empty during the setup and reboot the ahoy-dtu will set a value of 65535 in the setup. -That is the value you have to fill in case you want to operate the inverter without a active power limit. -If the value is 65535 or -1 after another reboot the value will be set automatically to "100" and in the drop-down menu "relative in percent persistent" will be set. Of course you can do this also by your self. You can change the setting in the following manner. Decide if you want to set @@ -115,24 +112,17 @@ Also an absolute active power limit below approx. 30 Watt seems to be not meanfu ### Generic Information -The AhoyDTU subscribes on three topics `/ctrl/#`, `/setup` and `/status`. +The AhoyDTU subscribes on following topics: + +- `/ctrl/limit/` +- `/ctrl/restart/` +- `/setup/set_time` 👆 `` can be set on setup page, default is `inverter`. 👆 `` is the number of the specific inverter in the setup page. -### Inverter Power (On / Off) -```mqtt -/ctrl/power/ -``` -with payload `1` = `ON` and `0` = `OFF` - -Example: -```mqtt -inverter/ctrl/power/0 1 -``` - ### Inverter restart ```mqtt /ctrl/restart/ @@ -142,50 +132,35 @@ Example: inverter/ctrl/restart/0 ``` -### Power Limit relative persistent [%] +### Power Limit relative (non persistent) [%] ```mqtt -/ctrl/limit_persistent_relative/ +/ctrl/limit/ ``` with a payload `[2 .. 100]` +**NOTE: optional a `%` can be sent as last character** + Example: ```mqtt -inverter/ctrl/limit_persistent_relative/0 70 +inverter/ctrl/limit/0 70 ``` -### Power Limit absolute persistent [Watts] +### Power Limit absolute (non persistent) [Watts] ```mqtt -/ctrl/limit_persistent_absolute/ +/ctrl/limit/ ``` with a payload `[0 .. 65535]` -Example: -```mqtt -inverter/ctrl/limit_persistent_absolute/0 600 -``` - -### Power Limit relative non persistent [%] -```mqtt -/ctrl/limit_nonpersistent_relative/ -``` -with a payload `[2 .. 100]` +**NOTE: the unit `W` is necessary to determine an absolute limit** Example: ```mqtt -inverter/ctrl/limit_nonpersistent_relative/0 70 -``` - -### Power Limit absolute non persistent [Watts] -```mqtt -/ctrl/limit_nonpersistent_absolute/ +inverter/ctrl/limit/0 600W ``` -with a payload `[0 .. 65535]` -Example: -```mqtt -inverter/ctrl/limit_nonpersistent_absolute/0 600 -``` +### Power Limit persistent +This feature was removed. The persisten limit should not be modified cyclic by a script because of potential wearout of the flash inside the inverter. ## Control via REST API diff --git a/scripts/getVersion.py b/scripts/getVersion.py index 4ecb714e..77c5816b 100644 --- a/scripts/getVersion.py +++ b/scripts/getVersion.py @@ -56,6 +56,11 @@ def readVersion(path, infile): src = path + ".pio/build/esp8266-release/firmware.bin" dst = path + "firmware/" + versionout os.rename(src, dst) + + versionout = version[:-1] + "_" + sha + "_esp8266_prometheus.bin" + src = path + ".pio/build/esp8266-release-prometheus/firmware.bin" + dst = path + "firmware/" + versionout + os.rename(src, dst) versionout = version[:-1] + "_" + sha + "_esp8285.bin" src = path + ".pio/build/esp8285-release/firmware.bin" @@ -68,6 +73,11 @@ def readVersion(path, infile): dst = path + "firmware/" + versionout os.rename(src, dst) + versionout = version[:-1] + "_" + sha + "_esp32_prometheus.bin" + src = path + ".pio/build/esp32-wroom32-release-prometheus/firmware.bin" + dst = path + "firmware/" + versionout + os.rename(src, dst) + # other ESP32 bin files src = path + ".pio/build/esp32-wroom32-release/" dst = path + "firmware/" diff --git a/src/CHANGES.md b/src/CHANGES.md index 27d64cd7..9ec5f85b 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -2,6 +2,36 @@ (starting from release version `0.5.66`) +## 0.5.100 +* fix add inverter `setup.html` #766 +* fix MQTT retained flag for total values #726 +* renamed buttons for import and export `setup.html` +* added serial message `settings saved` + +## 0.5.99 +* fix limit in [User_Manual.md](../User_Manual.md) +* changed `contrast` to `luminance` in `setup.html` +* try to fix SSD1306 display #759 +* only show necessary display pins depending on setting + +## 0.5.98 +* fix SH1106 rotation and turn off during night #756 +* removed MQTT subscription `sync_ntp`, `set_time` with a value of `0` does the same #696 +* simplified MQTT subscription for `limit`. Check [User_Manual.md](../User_Manual.md) for new syntax #696, #713 +* repaired inverter wise limit control +* fix upload settings #686 + +## 0.5.97 +* Attention: re-ordered display types, check your settings! #746 +* improved saving settings of display #747, #746 +* disabled contrast for Nokia display #746 +* added Prometheus as compile option #719, #615 +* update MQTT lib to v1.4.1 +* limit decimal places to 2 in `live` +* added `-DPIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48` to esp8266 debug build #657 +* a `max-module-power` of `0` disables channel in live view `setup` +* merge MI improvements, get firmware information #753 + ## 0.5.96 * added Nokia display again for ESP8266 #764 * changed `var` / `VAr` to SI unit `var` #732 diff --git a/src/LICENSE b/src/LICENSE deleted file mode 100644 index 057d1565..00000000 --- a/src/LICENSE +++ /dev/null @@ -1,7 +0,0 @@ -License - -CC-CY-NC-SA 3.0 - -https://creativecommons.org/licenses/by-nc-sa/3.0/de - -This project is for non-commercial use only! diff --git a/src/app.cpp b/src/app.cpp index d65dbe1d..a69d73a1 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -1,6 +1,6 @@ //----------------------------------------------------------------------------- // 2023 Ahoy, https://ahoydtu.de -// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/ +// Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed //----------------------------------------------------------------------------- #include "app.h" @@ -78,7 +78,7 @@ void app::setup() { // Plugins if (mConfig->plugin.display.type != 0) - mDisplay.setup(&mConfig->plugin.display, &mSys, &mTimestamp, 0xff, mVersion); + mDisplay.setup(&mConfig->plugin.display, &mSys, &mTimestamp, mVersion); mPubSerial.setup(mConfig, &mSys, &mTimestamp); diff --git a/src/app.h b/src/app.h index b68dc0c4..a792ffe8 100644 --- a/src/app.h +++ b/src/app.h @@ -1,6 +1,6 @@ //----------------------------------------------------------------------------- // 2023 Ahoy, https://ahoydtu.de -// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/ +// Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed //----------------------------------------------------------------------------- #ifndef __APP_H__ @@ -68,9 +68,9 @@ class app : public IApp, public ah::Scheduler { return Scheduler::getTimestamp(); } - bool saveSettings() { - mShowRebootRequest = true; - return mSettings.saveSettings(); + bool saveSettings(bool stopFs = false) { + mShowRebootRequest = true; // only message on index, no reboot + return mSettings.saveSettings(stopFs); } bool readSettings(const char *path) { @@ -210,6 +210,7 @@ class app : public IApp, public ah::Scheduler { onWifi(false); ah::Scheduler::resetTicker(); WiFi.disconnect(); + delay(200); ESP.restart(); } diff --git a/src/appInterface.h b/src/appInterface.h index 83a4f769..4c7d6042 100644 --- a/src/appInterface.h +++ b/src/appInterface.h @@ -1,6 +1,6 @@ //----------------------------------------------------------------------------- // 2022 Ahoy, https://ahoydtu.de -// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/ +// Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed //----------------------------------------------------------------------------- #ifndef __IAPP_H__ @@ -14,7 +14,7 @@ class IApp { public: virtual ~IApp() {} - virtual bool saveSettings() = 0; + virtual bool saveSettings(bool stopFs) = 0; virtual bool readSettings(const char *path) = 0; virtual bool eraseSettings(bool eraseWifi) = 0; virtual void setOnUpdate() = 0; diff --git a/src/config/settings.h b/src/config/settings.h index 0e118bde..77bc7a26 100644 --- a/src/config/settings.h +++ b/src/config/settings.h @@ -1,6 +1,6 @@ //----------------------------------------------------------------------------- // 2023 Ahoy, https://ahoydtu.de -// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/ +// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/4.0/deed //----------------------------------------------------------------------------- #ifndef __SETTINGS_H__ @@ -247,7 +247,7 @@ class settings { return mCfg.valid; } - bool saveSettings(void) { + bool saveSettings(bool stopFs = false) { DPRINTLN(DBG_DEBUG, F("save settings")); File fp = LittleFS.open("/settings.json", "w"); if(!fp) { @@ -273,6 +273,10 @@ class settings { } fp.close(); + DPRINTLN(DBG_INFO, F("settings saved")); + if(stopFs) + stop(); + return true; } @@ -280,7 +284,7 @@ class settings { if(true == eraseWifi) return LittleFS.format(); loadDefaults(!eraseWifi); - return saveSettings(); + return saveSettings(true); } private: @@ -347,12 +351,12 @@ class settings { mCfg.plugin.display.contrast = 60; mCfg.plugin.display.pxShift = true; mCfg.plugin.display.rot = 0; - mCfg.plugin.display.disp_data = DEF_PIN_OFF; // SDA - mCfg.plugin.display.disp_clk = DEF_PIN_OFF; // SCL - mCfg.plugin.display.disp_cs = DEF_PIN_OFF; + mCfg.plugin.display.disp_data = DEF_PIN_OFF; // SDA + mCfg.plugin.display.disp_clk = DEF_PIN_OFF; // SCL + mCfg.plugin.display.disp_cs = DEF_PIN_OFF; mCfg.plugin.display.disp_reset = DEF_PIN_OFF; - mCfg.plugin.display.disp_busy = DEF_PIN_OFF; - mCfg.plugin.display.disp_dc = DEF_PIN_OFF; + mCfg.plugin.display.disp_busy = DEF_PIN_OFF; + mCfg.plugin.display.disp_dc = DEF_PIN_OFF; } void jsonWifi(JsonObject obj, bool set = false) { @@ -403,6 +407,11 @@ class settings { mCfg.nrf.pinCe = obj[F("ce")]; mCfg.nrf.pinIrq = obj[F("irq")]; mCfg.nrf.amplifierPower = obj[F("pwr")]; + if((obj[F("cs")] == obj[F("ce")])) { + mCfg.nrf.pinCs = DEF_CS_PIN; + mCfg.nrf.pinCe = DEF_CE_PIN; + mCfg.nrf.pinIrq = DEF_IRQ_PIN; + } } } diff --git a/src/defines.h b/src/defines.h index f36c147f..b800aaa0 100644 --- a/src/defines.h +++ b/src/defines.h @@ -1,6 +1,6 @@ //----------------------------------------------------------------------------- // 2023 Ahoy, https://www.mikrocontroller.net/topic/525778 -// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/ +// Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed //----------------------------------------------------------------------------- #ifndef __DEFINES_H__ @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 5 -#define VERSION_PATCH 96 +#define VERSION_PATCH 100 //------------------------------------- typedef struct { diff --git a/src/hm/miPayload.h b/src/hm/miPayload.h index e4ae2bf7..c4fc2a2a 100644 --- a/src/hm/miPayload.h +++ b/src/hm/miPayload.h @@ -413,49 +413,49 @@ const byteAssign_t InfoAssignment[] = { DPRINTLN(DBG_INFO, F("process: compl. set of msgs detected")); iv->setValue(iv->getPosByChFld(0, FLD_YD, rec), rec, calcYieldDayCh0(iv,0)); iv->doCalculations(); - /*uint8_t payload[128]; - uint8_t payloadLen = 0; - memset(payload, 0, 128); - for (uint8_t i = 0; i < (mPayload[iv->id].maxPackId); i++) { - memcpy(&payload[payloadLen], mPayload[iv->id].data[i], (mPayload[iv->id].len[i])); - payloadLen += (mPayload[iv->id].len[i]); - yield(); - } - payloadLen -= 2; - if (mSerialDebug) { - DPRINT(DBG_INFO, F("Payload (") + String(payloadLen) + "): "); - mSys->Radio.dumpBuf(payload, payloadLen); - } - if (NULL == rec) { - DPRINTLN(DBG_ERROR, F("record is NULL!")); - } else if ((rec->pyldLen == payloadLen) || (0 == rec->pyldLen)) { - if (mPayload[iv->id].txId == (TX_REQ_INFO + ALL_FRAMES)) - mStat->rxSuccess++; - rec->ts = mPayload[iv->id].ts; - for (uint8_t i = 0; i < rec->length; i++) { - iv->addValue(i, payload, rec); - yield(); - } - iv->doCalculations(); - notify(mPayload[iv->id].txCmd); - if(AlarmData == mPayload[iv->id].txCmd) { - uint8_t i = 0; - uint16_t code; - uint32_t start, end; - while(1) { - code = iv->parseAlarmLog(i++, payload, payloadLen, &start, &end); - if(0 == code) - break; - if (NULL != mCbAlarm) - (mCbAlarm)(code, start, end); - yield(); - } - } - } else { - DPRINTLN(DBG_ERROR, F("plausibility check failed, expected ") + String(rec->pyldLen) + F(" bytes")); - mStat->rxFail++; - } - iv->setQueuedCmdFinished(); */ + //uint8_t payload[128]; + //uint8_t payloadLen = 0; + //memset(payload, 0, 128); + //for (uint8_t i = 0; i < (mPayload[iv->id].maxPackId); i++) { + // memcpy(&payload[payloadLen], mPayload[iv->id].data[i], (mPayload[iv->id].len[i])); + // payloadLen += (mPayload[iv->id].len[i]); + // yield(); + //} + //payloadLen -= 2; + //if (mSerialDebug) { + // DPRINT(DBG_INFO, F("Payload (") + String(payloadLen) + "): "); + // mSys->Radio.dumpBuf(payload, payloadLen); + //} + //if (NULL == rec) { + // DPRINTLN(DBG_ERROR, F("record is NULL!")); + //} else if ((rec->pyldLen == payloadLen) || (0 == rec->pyldLen)) { + // if (mPayload[iv->id].txId == (TX_REQ_INFO + ALL_FRAMES)) + // mStat->rxSuccess++; + // rec->ts = mPayload[iv->id].ts; + // for (uint8_t i = 0; i < rec->length; i++) { + // iv->addValue(i, payload, rec); + // yield(); + // } + // iv->doCalculations(); + // notify(mPayload[iv->id].txCmd); + // if(AlarmData == mPayload[iv->id].txCmd) { + // uint8_t i = 0; + // uint16_t code; + // uint32_t start, end; + // while(1) { + // code = iv->parseAlarmLog(i++, payload, payloadLen, &start, &end); + // if(0 == code) + // break; + // if (NULL != mCbAlarm) + // (mCbAlarm)(code, start, end); + // yield(); + // } + // } + //} else { + // DPRINTLN(DBG_ERROR, F("plausibility check failed, expected ") + String(rec->pyldLen) + F(" bytes")); + // mStat->rxFail++; + //} + //iv->setQueuedCmdFinished(); //}*/ } yield(); @@ -588,9 +588,9 @@ const byteAssign_t InfoAssignment[] = { if ( mPayload[iv->id].complete || //4ch device - iv->type != INV_TYPE_4CH //other devices + (iv->type != INV_TYPE_4CH //other devices && mPayload[iv->id].dataAB[CH0] - && mPayload[iv->id].stsAB[CH0] ) { + && mPayload[iv->id].stsAB[CH0])) { miComplete(iv); /*mPayload[iv->id].complete = true; // For 2 CH devices, this might be too short... DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") got all msgs")); @@ -657,7 +657,7 @@ const byteAssign_t InfoAssignment[] = { //uint8_t cmd = getQueuedCmd(); if(!*complete) { DPRINTLN(DBG_VERBOSE, F("incomlete, txCmd is 0x") + String(txCmd, HEX)); // + F("cmd is 0x") + String(cmd, HEX)); - if (txCmd == 0x09 || txCmd == 0x11 || txCmd >= 0x36 && txCmd <= 0x39 ) + if (txCmd == 0x09 || txCmd == 0x11 || (txCmd >= 0x36 && txCmd <= 0x39)) return false; } diff --git a/src/main.cpp b/src/main.cpp index c585d0f2..af10abce 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,6 @@ //----------------------------------------------------------------------------- -// 2022 Ahoy, https://www.mikrocontroller.net/topic/525778 -// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/ +// 2023 Ahoy, https://ahoydtu.de +// Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed //----------------------------------------------------------------------------- #include "utils/dbg.h" diff --git a/src/platformio.ini b/src/platformio.ini index e52cf3fb..6d3f8d23 100644 --- a/src/platformio.ini +++ b/src/platformio.ini @@ -20,12 +20,12 @@ upload_speed = 921600 ;build_flags = ; ;;;;; Possible Debug options ;;;;;; ; https://docs.platformio.org/en/latest/platforms/espressif8266.html#debug-level - ;-DDEBUG_ESP_PORT=Serial + ;-DDEBUG_ESP_PORT=Serial ;-DDEBUG_ESP_CORE - ;-DDEBUG_ESP_WIFI - ;-DDEBUG_ESP_HTTP_CLIENT - ;-DDEBUG_ESP_HTTP_SERVER - ;-DDEBUG_ESP_OOM + ;-DDEBUG_ESP_WIFI + ;-DDEBUG_ESP_HTTP_CLIENT + ;-DDEBUG_ESP_HTTP_SERVER + ;-DDEBUG_ESP_OOM monitor_speed = 115200 @@ -35,18 +35,18 @@ extra_scripts = lib_deps = https://github.com/yubox-node-org/ESPAsyncWebServer - nrf24/RF24 - paulstoffregen/Time - https://github.com/bertmelis/espMqttClient#v1.3.3 - bblanchon/ArduinoJson + nrf24/RF24 + paulstoffregen/Time + https://github.com/bertmelis/espMqttClient#v1.4.1 + bblanchon/ArduinoJson https://github.com/JChristensen/Timezone olikraus/U8g2 zinggjm/GxEPD2@^1.5.0 - ;esp8266/DNSServer - ;esp8266/EEPROM - ;esp8266/ESP8266WiFi - ;esp8266/SPI - ;esp8266/Ticker + ;esp8266/DNSServer + ;esp8266/EEPROM + ;esp8266/ESP8266WiFi + ;esp8266/SPI + ;esp8266/Ticker [env:esp8266-release] @@ -55,8 +55,20 @@ board = esp12e board_build.f_cpu = 80000000L build_flags = -D RELEASE monitor_filters = - ;default ; Remove typical terminal control codes from input - ;time ; Add timestamp with milliseconds for each new line + ;default ; Remove typical terminal control codes from input + ;time ; Add timestamp with milliseconds for each new line + ;log2file ; Log data to a file “platformio-device-monitor-*.log” located in the current working directory + esp8266_exception_decoder + + +[env:esp8266-release-prometheus] +platform = espressif8266 +board = esp12e +board_build.f_cpu = 80000000L +build_flags = -D RELEASE -DENABLE_PROMETHEUS_EP +monitor_filters = + ;default ; Remove typical terminal control codes from input + ;time ; Add timestamp with milliseconds for each new line ;log2file ; Log data to a file “platformio-device-monitor-*.log” located in the current working directory esp8266_exception_decoder @@ -64,11 +76,11 @@ monitor_filters = platform = espressif8266 board = esp12e board_build.f_cpu = 80000000L -build_flags = -DDEBUG_LEVEL=DBG_DEBUG -DDEBUG_ESP_CORE -DDEBUG_ESP_WIFI -DDEBUG_ESP_HTTP_CLIENT -DDEBUG_ESP_HTTP_SERVER -DDEBUG_ESP_OOM -DDEBUG_ESP_PORT=Serial +build_flags = -DDEBUG_LEVEL=DBG_DEBUG -DDEBUG_ESP_CORE -DDEBUG_ESP_WIFI -DDEBUG_ESP_HTTP_CLIENT -DDEBUG_ESP_HTTP_SERVER -DDEBUG_ESP_OOM -DDEBUG_ESP_PORT=Serial -DPIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48 build_type = debug monitor_filters = - ;default ; Remove typical terminal control codes from input - time ; Add timestamp with milliseconds for each new line + ;default ; Remove typical terminal control codes from input + time ; Add timestamp with milliseconds for each new line log2file ; Log data to a file “platformio-device-monitor-*.log” located in the current working directory [env:esp8285-release] @@ -78,8 +90,8 @@ board_build.ldscript = eagle.flash.1m64.ld board_build.f_cpu = 80000000L build_flags = -D RELEASE monitor_filters = - ;default ; Remove typical terminal control codes from input - time ; Add timestamp with milliseconds for each new line + ;default ; Remove typical terminal control codes from input + time ; Add timestamp with milliseconds for each new line ;log2file ; Log data to a file “platformio-device-monitor-*.log” located in the current working directory [env:esp8285-debug] @@ -90,8 +102,8 @@ board_build.f_cpu = 80000000L build_flags = -DDEBUG_LEVEL=DBG_DEBUG -DDEBUG_ESP_CORE -DDEBUG_ESP_WIFI -DDEBUG_ESP_HTTP_CLIENT -DDEBUG_ESP_HTTP_SERVER -DDEBUG_ESP_OOM -DDEBUG_ESP_PORT=Serial build_type = debug monitor_filters = - ;default ; Remove typical terminal control codes from input - time ; Add timestamp with milliseconds for each new line + ;default ; Remove typical terminal control codes from input + time ; Add timestamp with milliseconds for each new line log2file ; Log data to a file “platformio-device-monitor-*.log” located in the current working directory [env:esp32-wroom32-release] @@ -100,8 +112,19 @@ board = lolin_d32 build_flags = -D RELEASE -std=gnu++14 build_unflags = -std=gnu++11 monitor_filters = - ;default ; Remove typical terminal control codes from input - ;time ; Add timestamp with milliseconds for each new line + ;default ; Remove typical terminal control codes from input + ;time ; Add timestamp with milliseconds for each new line + ;log2file ; Log data to a file “platformio-device-monitor-*.log” located in the current working directory + esp32_exception_decoder + +[env:esp32-wroom32-release-prometheus] +platform = espressif32 +board = lolin_d32 +build_flags = -D RELEASE -std=gnu++14 -DENABLE_PROMETHEUS_EP +build_unflags = -std=gnu++11 +monitor_filters = + ;default ; Remove typical terminal control codes from input + ;time ; Add timestamp with milliseconds for each new line ;log2file ; Log data to a file “platformio-device-monitor-*.log” located in the current working directory esp32_exception_decoder @@ -112,6 +135,6 @@ build_flags = -DDEBUG_LEVEL=DBG_DEBUG -DDEBUG_ESP_CORE -DDEBUG_ESP_WIFI -DDEBUG_ build_unflags = -std=gnu++11 build_type = debug monitor_filters = - ;default ; Remove typical terminal control codes from input - time ; Add timestamp with milliseconds for each new line + ;default ; Remove typical terminal control codes from input + time ; Add timestamp with milliseconds for each new line log2file ; Log data to a file “platformio-device-monitor-*.log” located in the current working directory diff --git a/src/plugins/Display/Display.h b/src/plugins/Display/Display.h index 5b572219..6e492e44 100644 --- a/src/plugins/Display/Display.h +++ b/src/plugins/Display/Display.h @@ -14,7 +14,7 @@ class Display { public: Display() {} - void setup(display_t *cfg, HMSYSTEM *sys, uint32_t *utcTs, uint8_t disp_reset, const char *version) { + void setup(display_t *cfg, HMSYSTEM *sys, uint32_t *utcTs, const char *version) { mCfg = cfg; mSys = sys; mUtcTs = utcTs; @@ -27,7 +27,7 @@ class Display { if ((1 < mCfg->type) && (mCfg->type < 10)) { mMono.config(mCfg->pwrSaveAtIvOffline, mCfg->pxShift, mCfg->contrast); - mMono.init(mCfg->type, mCfg->rot, mCfg->disp_cs, mCfg->disp_dc, mCfg->disp_reset, mCfg->disp_clk, mCfg->disp_data, mUtcTs, mVersion); + mMono.init(mCfg->type, mCfg->rot, mCfg->disp_cs, mCfg->disp_dc, 0xff, mCfg->disp_clk, mCfg->disp_data, mUtcTs, mVersion); } else if (mCfg->type >= 10) { #if defined(ESP32) mRefreshCycle = 0; @@ -42,7 +42,7 @@ class Display { } void tickerSecond() { - loop(); + mMono.loop(); if (mNewPayload || ((++mLoopCnt % 10) == 0)) { mNewPayload = false; mLoopCnt = 0; diff --git a/src/plugins/Display/Display_Mono.cpp b/src/plugins/Display/Display_Mono.cpp index 57d3cf6b..5af864f6 100644 --- a/src/plugins/Display/Display_Mono.cpp +++ b/src/plugins/Display/Display_Mono.cpp @@ -22,24 +22,26 @@ DisplayMono::DisplayMono() { _dispY = 0; mTimeout = DISP_DEFAULT_TIMEOUT; // interval at which to power save (milliseconds) mUtcTs = NULL; + mType = 0; } -void DisplayMono::init(uint8_t type, uint8_t rot, uint8_t cs, uint8_t dc, uint8_t reset, uint8_t clock, uint8_t data, uint32_t *utcTs, const char* version) { +void DisplayMono::init(uint8_t type, uint8_t rotation, uint8_t cs, uint8_t dc, uint8_t reset, uint8_t clock, uint8_t data, uint32_t *utcTs, const char* version) { if ((0 < type) && (type < 4)) { - u8g2_cb_t *rot = (u8g2_cb_t *)((rot != 0x00) ? U8G2_R2 : U8G2_R0); + u8g2_cb_t *rot = (u8g2_cb_t *)((rotation != 0x00) ? U8G2_R2 : U8G2_R0); + mType = type; switch(type) { case 1: - mDisplay = new U8G2_PCD8544_84X48_F_4W_SW_SPI(rot, clock, data, cs, dc, reset); - break; - case 2: mDisplay = new U8G2_SSD1306_128X64_NONAME_F_HW_I2C(rot, reset, clock, data); break; default: - case 3: + case 2: mDisplay = new U8G2_SH1106_128X64_NONAME_F_HW_I2C(rot, reset, clock, data); break; + case 3: + mDisplay = new U8G2_PCD8544_84X48_F_4W_SW_SPI(rot, clock, data, cs, dc, reset); + break; } mUtcTs = utcTs; @@ -50,7 +52,8 @@ void DisplayMono::init(uint8_t type, uint8_t rot, uint8_t cs, uint8_t dc, uint8_ calcLineHeights(); mDisplay->clearBuffer(); - mDisplay->setContrast(mLuminance); + if (3 != mType) + mDisplay->setContrast(mLuminance); printText("AHOY!", 0, 35); printText("ahoydtu.de", 2, 20); printText(version, 3, 46); @@ -76,7 +79,8 @@ void DisplayMono::disp(float totalPower, float totalYieldDay, float totalYieldTo mDisplay->clearBuffer(); // set Contrast of the Display to raise the lifetime - mDisplay->setContrast(mLuminance); + if (3 != mType) + mDisplay->setContrast(mLuminance); if ((totalPower > 0) && (isprod > 0)) { mTimeout = DISP_DEFAULT_TIMEOUT; diff --git a/src/plugins/Display/Display_Mono.h b/src/plugins/Display/Display_Mono.h index 1b62328f..ad04c9f4 100644 --- a/src/plugins/Display/Display_Mono.h +++ b/src/plugins/Display/Display_Mono.h @@ -21,6 +21,7 @@ class DisplayMono { U8G2* mDisplay; + uint8_t mType; bool mEnPowerSafe, mEnScreenSaver; uint8_t mLuminance; diff --git a/src/publisher/pubMqtt.h b/src/publisher/pubMqtt.h index 4ec4c3f5..7922b2e8 100644 --- a/src/publisher/pubMqtt.h +++ b/src/publisher/pubMqtt.h @@ -1,6 +1,6 @@ //----------------------------------------------------------------------------- // 2023 Ahoy, https://ahoydtu.de -// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/ +// Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed //----------------------------------------------------------------------------- // https://bert.emelis.net/espMqttClient/ @@ -59,7 +59,7 @@ class PubMqtt { if((strlen(mCfgMqtt->user) > 0) && (strlen(mCfgMqtt->pwd) > 0)) mClient.setCredentials(mCfgMqtt->user, mCfgMqtt->pwd); - snprintf(mClientId, 26, "%s-", mDevName); + snprintf(mClientId, 24, "%s-", mDevName); uint8_t pos = strlen(mClientId); mClientId[pos++] = WiFi.macAddress().substring( 9, 10).c_str()[0]; mClientId[pos++] = WiFi.macAddress().substring(10, 11).c_str()[0]; @@ -312,13 +312,14 @@ class PubMqtt { tickerMinute(); publish(mLwtTopic, mqttStr[MQTT_STR_LWT_CONN], true, false); - subscribe(subscr[MQTT_SUBS_LMT_PERI_REL]); - subscribe(subscr[MQTT_SUBS_LMT_PERI_ABS]); - subscribe(subscr[MQTT_SUBS_LMT_NONPERI_REL]); - subscribe(subscr[MQTT_SUBS_LMT_NONPERI_ABS]); + char sub[20]; + for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { + snprintf(sub, 20, "ctrl/limit/%d", i); + subscribe(sub); + snprintf(sub, 20, "ctrl/restart/%d", i); + subscribe(sub); + } subscribe(subscr[MQTT_SUBS_SET_TIME]); - subscribe(subscr[MQTT_SUBS_SYNC_NTP]); - //subscribe("status/#"); } void onDisconnect(espMqttClientTypes::DisconnectReason reason) { @@ -358,11 +359,14 @@ class PubMqtt { DynamicJsonDocument json(128); JsonObject root = json.to(); + bool limitAbs = false; if(len > 0) { char *pyld = new char[len + 1]; strncpy(pyld, (const char*)payload, len); pyld[len] = '\0'; - root["val"] = atoi(pyld); + root[F("val")] = atoi(pyld); + if(pyld[len-1] == 'W') + limitAbs = true; delete[] pyld; } @@ -377,8 +381,17 @@ class PubMqtt { tmp[pos] = '\0'; switch(elm++) { case 1: root[F("path")] = String(tmp); break; - case 2: root[F("cmd")] = String(tmp); break; - case 3: root[F("id")] = atoi(tmp); break; + case 2: + if(strncmp("limit", tmp, 5) == 0) { + if(limitAbs) + root[F("cmd")] = F("limit_nonpersistent_absolute"); + else + root[F("cmd")] = F("limit_nonpersistent_relative"); + } + else + root[F("cmd")] = String(tmp); + break; + case 3: root[F("id")] = atoi(tmp); break; default: break; } if('\0' == p[pos]) @@ -569,8 +582,8 @@ class PubMqtt { if (sendTotals) { uint8_t fieldId; - bool retained = true; for (uint8_t i = 0; i < 4; i++) { + bool retained = true; switch (i) { default: case 0: @@ -622,7 +635,7 @@ class PubMqtt { // last will topic and payload must be available trough lifetime of 'espMqttClient' char mLwtTopic[MQTT_TOPIC_LEN+5]; const char *mDevName, *mVersion; - char mClientId[26]; // number of chars is limited to 23 up to v3.1 of MQTT + char mClientId[24]; // number of chars is limited to 23 up to v3.1 of MQTT }; #endif /*__PUB_MQTT_H__*/ diff --git a/src/publisher/pubMqttDefs.h b/src/publisher/pubMqttDefs.h index 64309b18..9633e2d4 100644 --- a/src/publisher/pubMqttDefs.h +++ b/src/publisher/pubMqttDefs.h @@ -1,6 +1,6 @@ //----------------------------------------------------------------------------- // 2023 Ahoy, https://ahoydtu.de -// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/ +// Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed //----------------------------------------------------------------------------- #ifndef __PUB_MQTT_DEFS_H__ @@ -84,21 +84,11 @@ const char* const subtopics[] PROGMEM = { }; enum { - MQTT_SUBS_LMT_PERI_REL, - MQTT_SUBS_LMT_PERI_ABS, - MQTT_SUBS_LMT_NONPERI_REL, - MQTT_SUBS_LMT_NONPERI_ABS, - MQTT_SUBS_SET_TIME, - MQTT_SUBS_SYNC_NTP + MQTT_SUBS_SET_TIME }; const char* const subscr[] PROGMEM = { - "ctrl/limit_persistent_relative", - "ctrl/limit_persistent_absolute", - "ctrl/limit_nonpersistent_relative", - "ctrl/limit_nonpersistent_absolute", - "setup/set_time", - "setup/sync_ntp" + "setup/set_time" }; #endif /*__PUB_MQTT_DEFS_H__*/ diff --git a/src/web/RestApi.h b/src/web/RestApi.h index e9479a0b..9b14e439 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -305,8 +305,8 @@ class RestApi { for(uint8_t j = 0; j < iv->channels; j ++) { obj2[F("ch_yield_cor")][j] = iv->config->yieldCor[j]; - obj2[F("ch_max_power")][j] = iv->config->chMaxPwr[j]; obj2[F("ch_name")][j] = iv->config->chName[j]; + obj2[F("ch_max_pwr")][j] = iv->config->chMaxPwr[j]; } } } @@ -344,6 +344,7 @@ class RestApi { // DC for(uint8_t j = 0; j < iv->channels; j ++) { obj[F("ch_name")][j+1] = iv->config->chName[j]; + obj[F("ch_max_pwr")][j+1] = iv->config->chMaxPwr[j]; JsonArray cur = ch.createNestedArray(); for (uint8_t fld = 0; fld < sizeof(dcList); fld++) { pos = (iv->getPosByChFld((j+1), dcList[fld], rec)); @@ -410,12 +411,12 @@ class RestApi { obj[F("disp_pxshift")] = (bool)mConfig->plugin.display.pxShift; obj[F("disp_rot")] = (uint8_t)mConfig->plugin.display.rot; obj[F("disp_cont")] = (uint8_t)mConfig->plugin.display.contrast; - obj[F("disp_clk")] = mConfig->plugin.display.disp_clk; - obj[F("disp_data")] = mConfig->plugin.display.disp_data; - obj[F("disp_cs")] = mConfig->plugin.display.disp_cs; - obj[F("disp_dc")] = mConfig->plugin.display.disp_dc; - obj[F("disp_rst")] = mConfig->plugin.display.disp_reset; - obj[F("disp_bsy")] = mConfig->plugin.display.disp_busy; + obj[F("disp_clk")] = (mConfig->plugin.display.type == 0) ? DEF_PIN_OFF : mConfig->plugin.display.disp_clk; + obj[F("disp_data")] = (mConfig->plugin.display.type == 0) ? DEF_PIN_OFF : mConfig->plugin.display.disp_data; + obj[F("disp_cs")] = (mConfig->plugin.display.type == 0) ? DEF_PIN_OFF : mConfig->plugin.display.disp_cs; + obj[F("disp_dc")] = (mConfig->plugin.display.type == 0) ? DEF_PIN_OFF : mConfig->plugin.display.disp_dc; + obj[F("disp_rst")] = (mConfig->plugin.display.type == 0) ? DEF_PIN_OFF : mConfig->plugin.display.disp_reset; + obj[F("disp_bsy")] = (mConfig->plugin.display.type == 0) ? DEF_PIN_OFF : mConfig->plugin.display.disp_busy; } void getIndex(JsonObject obj) { diff --git a/src/web/html/includes/footer.html b/src/web/html/includes/footer.html index 5a2b705b..bbc4c6ce 100644 --- a/src/web/html/includes/footer.html +++ b/src/web/html/includes/footer.html @@ -10,7 +10,7 @@ diff --git a/src/web/html/setup.html b/src/web/html/setup.html index 53ad13fd..967cccd6 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -136,6 +136,10 @@
+
+

Note

+

A 'max module power' value of '0' disables the channel in 'live' view

+

General

@@ -261,11 +265,11 @@
-
Enable Screensaver (pixel shifting)
+
Enable Screensaver (pixel shifting, OLED only)
-
Contrast
+
Luminance

Pinout

@@ -275,25 +279,34 @@
Reboot device after successful save
-
+
- -
-
- ERASE SETTINGS (not WiFi) -
- Upload / Store JSON Settings -
- - -
-
- Download settings (JSON file) (only saved values, passwords will be removed!) -
+
+
+ ERASE SETTINGS (not WiFi) +
+ Import / Export JSON Settings +
+
Import
+
+
+ + +
+
+
+
+
Export
+
+ Export settings (JSON file) (only values, passwords will be removed!) +
+
+
+
{#HTML_FOOTER} @@ -355,7 +368,7 @@ document.getElementById("btnAdd").addEventListener("click", function() { if(highestId <= (maxInv-1)) { - ivHtml(JSON.parse('{"enabled":true,"name":"","serial":"","channels":4,"ch_max_power":[0,0,0,0],"ch_name":["","","",""],"ch_yield_cor":[0,0,0,0]}'), highestId); + ivHtml(JSON.parse('{"enabled":true,"name":"","serial":"","channels":4,"ch_max_pwr":[0,0,0,0],"ch_name":["","","",""],"ch_yield_cor":[0,0,0,0]}'), highestId); } }); @@ -499,7 +512,7 @@ iv.append(mlE("Name*", inp(id + "Name", obj["name"], 16, ["text"], null, "text", "[A-Za-z0-9./#$%&=+_-]+", "Invalid input"))); for(var j of [ - ["ModPwr", "ch_max_power", "Max Module Power (Wp)", 4, "[0-9]+"], + ["ModPwr", "ch_max_pwr", "Max Module Power (Wp)", 4, "[0-9]+"], ["ModName", "ch_name", "Module Name", 15, null], ["YieldCor", "ch_yield_cor", "Yield Total Correction [kWh]", 8, "[0-9-]+"]]) { @@ -634,12 +647,12 @@ document.getElementsByName(i)[0].checked = obj[i]; var e = document.getElementById("dispPins"); - pins = [['clock', 'disp_clk'], ['data', 'disp_data'], ['cs', 'disp_cs'], ['dc', 'disp_dc'], ['reset', 'disp_rst'], ['busy', 'disp_bsy']]; + var pins = [['clock', 'disp_clk'], ['data', 'disp_data'], ['cs', 'disp_cs'], ['dc', 'disp_dc'], ['reset', 'disp_rst']]; + if("ESP32" == type) + pins.push(['busy', 'disp_bsy']); for(p of pins) { - if(("ESP8266" == type) && p[0] == "busy") - break; e.append( - ml("div", {class: "row mb-3"}, [ + ml("div", {class: "row mb-3", id: "row_" + p[1]}, [ ml("div", {class: "col-12 col-sm-3 my-2"}, p[0].toUpperCase()), ml("div", {class: "col-12 col-sm-9"}, sel(p[1], ("ESP8266" == type) ? esp8266pins : esp32pins, obj[p[1]]) @@ -648,15 +661,19 @@ ); } - var opts = [[0, "None"], [1, "Nokia5110"], [2, "SSD1306 0.96\""], [3, "SH1106 1.3\""]]; + var opts = [[0, "None"], [1, "SSD1306 0.96\""], [2, "SH1106 1.3\""], [3, "Nokia5110"]]; if("ESP32" == type) opts.push([10, "ePaper"]); + var dispType = sel("disp_typ", opts, obj["disp_typ"]); document.getElementById("dispType").append( ml("div", {class: "row mb-3"}, [ ml("div", {class: "col-12 col-sm-3 my-2"}, "Type"), - ml("div", {class: "col-12 col-sm-9"}, sel("disp_typ", opts, obj["disp_typ"])) + ml("div", {class: "col-12 col-sm-9"}, dispType) ]) ); + dispType.addEventListener('change', (e) => { + hideDispPins(pins, e.target.value) + }); opts = [[0, "0°"], [2, "180°"]]; if("ESP32" == type) { @@ -671,6 +688,27 @@ ); document.getElementsByName("disp_cont")[0].value = obj["disp_cont"]; + hideDispPins(pins, obj.disp_typ); + } + + function hideDispPins(pins, dispType) { + if(0 == dispType) { + for(p of pins) { + document.getElementById("row_" + p[1]).classList.add("hide"); + } + } else if(2 >= dispType) { + for(var i = 0; i < pins.length; i++) { + var cl = document.getElementById("row_" + pins[i][1]).classList; + if(i < 2) + cl.remove("hide"); + else + cl.add("hide"); + } + } else { + for(p of pins) { + document.getElementById("row_" + p[1]).classList.remove("hide"); + } + } } function parse(root) { diff --git a/src/web/html/visualization.html b/src/web/html/visualization.html index 44764a49..de5b0069 100644 --- a/src/web/html/visualization.html +++ b/src/web/html/visualization.html @@ -34,7 +34,7 @@ return ml("div", {class: "col-6 col-sm-4 a-c"}, [ ml("div", {class: "row"}, ml("div", {class: "col"}, [ - ml("span", {class: "fs-5 fs-md-4"}, String(val)), + ml("span", {class: "fs-5 fs-md-4"}, String(Math.round(val * 100) / 100)), ml("span", {class: "fs-6 fs-md-7 mx-1"}, unit) ])), ml("div", {class: "row"}, @@ -49,7 +49,7 @@ return ml("div", {class: "col-6 col-sm-4 col-md-3 mb-2"}, [ ml("div", {class: "row"}, ml("div", {class: "col"}, [ - ml("span", {class: "fs-6"}, String(val)), + ml("span", {class: "fs-6"}, String(Math.round(val * 100) / 100)), ml("span", {class: "fs-8 mx-1"}, unit) ])), ml("div", {class: "row"}, @@ -94,7 +94,7 @@ total[3] += obj.ch[0][8]; // P_DC total[4] += obj.ch[0][10]; // Q_AC var t = span(" ° C"); - return ml("div", {class: "row"}, + return ml("div", {class: "row mt-2"}, ml("div", {class: "col"}, [ ml("div", {class: "p-2 iv-h"}, ml("div", {class: "row"}, [ @@ -128,7 +128,7 @@ return ml("div", {class: "col-12 col-sm-6 col-md-12 mb-2"}, [ ml("div", {class: "row"}, ml("div", {class: "col"}, [ - ml("span", {class: "fs-6 fs-md-7"}, String(val)), + ml("span", {class: "fs-6 fs-md-7"}, String(Math.round(val * 100) / 100)), ml("span", {class: "fs-8 mx-2"}, unit) ])), ml("div", {class: "row"}, @@ -182,7 +182,8 @@ var name = obj.ch_name[i]; if(name.length == 0) name = "CHANNEL " + i; - chn.push(ch(name, obj.ch[i])); + if(obj.ch_max_pwr[i] > 0) // show channel only if max mod pwr + chn.push(ch(name, obj.ch[i])); } mIvHtml.push( ml("div", {}, [ diff --git a/src/web/web.h b/src/web/web.h index 15b22eb0..098ed7ed 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -1,6 +1,6 @@ //----------------------------------------------------------------------------- // 2022 Ahoy, https://www.mikrocontroller.net/topic/525778 -// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/ +// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/4.0/deed //----------------------------------------------------------------------------- #ifndef __WEB_H__ @@ -170,11 +170,15 @@ class Web { if (!fp) mUploadFail = true; else { + char pwd[PWD_LEN]; + strncpy(pwd, mConfig->sys.stationPwd, PWD_LEN); // backup WiFi PWD if (!mApp->readSettings("tmp.json")) { mUploadFail = true; DPRINTLN(DBG_ERROR, F("upload JSON error!")); - } else - mApp->saveSettings(); + } else { + strncpy(mConfig->sys.stationPwd, pwd, PWD_LEN); // restore WiFi PWD + mApp->saveSettings(true); + } } DPRINTLN(DBG_INFO, F("upload finished!")); } @@ -414,10 +418,8 @@ class Web { refresh = 120; } request->send(200, F("text/html; charset=UTF-8"), F("Factory Reset") + content + F("")); - if (refresh == 10) { - delay(1000); - ESP.restart(); - } + if (refresh == 10) + onReboot(request); } void onSetup(AsyncWebServerRequest *request) { @@ -582,15 +584,15 @@ class Web { mConfig->plugin.display.pxShift = (request->arg("disp_pxshift") == "on"); mConfig->plugin.display.rot = request->arg("disp_rot").toInt(); mConfig->plugin.display.type = request->arg("disp_typ").toInt(); - mConfig->plugin.display.contrast = request->arg("disp_cont").toInt(); - mConfig->plugin.display.disp_data = request->arg("disp_data").toInt(); - mConfig->plugin.display.disp_clk = request->arg("disp_clk").toInt(); - mConfig->plugin.display.disp_cs = request->arg("disp_cs").toInt(); - mConfig->plugin.display.disp_reset = request->arg("disp_rst").toInt(); - mConfig->plugin.display.disp_busy = request->arg("disp_bsy").toInt(); - mConfig->plugin.display.disp_dc = request->arg("disp_dc").toInt(); + mConfig->plugin.display.contrast = (mConfig->plugin.display.type == 0) ? 60 : request->arg("disp_cont").toInt(); + mConfig->plugin.display.disp_data = (mConfig->plugin.display.type == 0) ? DEF_PIN_OFF : request->arg("disp_data").toInt(); + mConfig->plugin.display.disp_clk = (mConfig->plugin.display.type == 0) ? DEF_PIN_OFF : request->arg("disp_clk").toInt(); + mConfig->plugin.display.disp_cs = (mConfig->plugin.display.type < 4) ? DEF_PIN_OFF : request->arg("disp_cs").toInt(); + mConfig->plugin.display.disp_reset = (mConfig->plugin.display.type < 4) ? DEF_PIN_OFF : request->arg("disp_rst").toInt(); + mConfig->plugin.display.disp_dc = (mConfig->plugin.display.type < 4) ? DEF_PIN_OFF : request->arg("disp_dc").toInt(); + mConfig->plugin.display.disp_busy = (mConfig->plugin.display.type < 10) ? DEF_PIN_OFF : request->arg("disp_bsy").toInt(); - mApp->saveSettings(); + mApp->saveSettings((request->arg("reboot") == "on")); if (request->arg("reboot") == "on") onReboot(request); @@ -618,71 +620,6 @@ class Web { request->send(response); } - /*void showWebApi(AsyncWebServerRequest *request) { - // TODO: remove - DPRINTLN(DBG_VERBOSE, F("web::showWebApi")); - DPRINTLN(DBG_DEBUG, request->arg("plain")); - const size_t capacity = 200; // Use arduinojson.org/assistant to compute the capacity. - DynamicJsonDocument response(capacity); - - // Parse JSON object - deserializeJson(response, request->arg("plain")); - // ToDo: error handling for payload - uint8_t iv_id = response["inverter"]; - uint8_t cmd = response["cmd"]; - Inverter<> *iv = mSys->getInverterByPos(iv_id); - if (NULL != iv) { - if (response["tx_request"] == (uint8_t)TX_REQ_INFO) { - // if the AlarmData is requested set the Alarm Index to the requested one - if (cmd == AlarmData || cmd == AlarmUpdate) { - // set the AlarmMesIndex for the request from user input - iv->alarmMesIndex = response["payload"]; - } - DPRINTLN(DBG_INFO, F("Will make tx-request 0x15 with subcmd ") + String(cmd) + F(" and payload ") + String((uint16_t) response["payload"])); - // process payload from web request corresponding to the cmd - iv->enqueCommand(cmd); - } - - - if (response["tx_request"] == (uint8_t)TX_REQ_DEVCONTROL) { - if (response["cmd"] == (uint8_t)ActivePowerContr) { - uint16_t webapiPayload = response["payload"]; - uint16_t webapiPayload2 = response["payload2"]; - if (webapiPayload > 0 && webapiPayload < 10000) { - iv->devControlCmd = ActivePowerContr; - iv->powerLimit[0] = webapiPayload; - if (webapiPayload2 > 0) - iv->powerLimit[1] = webapiPayload2; // dev option, no sanity check - else // if not set, set it to 0x0000 default - iv->powerLimit[1] = AbsolutNonPersistent; // payload will be seted temporary in Watt absolut - if (iv->powerLimit[1] & 0x0001) - DPRINTLN(DBG_INFO, F("Power limit for inverter ") + String(iv->id) + F(" set to ") + String(iv->powerLimit[0]) + F("% via REST API")); - else - DPRINTLN(DBG_INFO, F("Power limit for inverter ") + String(iv->id) + F(" set to ") + String(iv->powerLimit[0]) + F("W via REST API")); - iv->devControlRequest = true; // queue it in the request loop - } - } - if (response["cmd"] == (uint8_t)TurnOff) { - iv->devControlCmd = TurnOff; - iv->devControlRequest = true; // queue it in the request loop - } - if (response["cmd"] == (uint8_t)TurnOn) { - iv->devControlCmd = TurnOn; - iv->devControlRequest = true; // queue it in the request loop - } - if (response["cmd"] == (uint8_t)CleanState_LockAndAlarm) { - iv->devControlCmd = CleanState_LockAndAlarm; - iv->devControlRequest = true; // queue it in the request loop - } - if (response["cmd"] == (uint8_t)Restart) { - iv->devControlCmd = Restart; - iv->devControlRequest = true; // queue it in the request loop - } - } - } - request->send(200, "text/json", "{success:true}"); - }*/ - void onDebug(AsyncWebServerRequest *request) { mApp->getSchedulerNames(); AsyncWebServerResponse *response = request->beginResponse(200, F("text/html; charset=UTF-8"), "ok");