diff --git a/.github/workflows/compile_development.yml b/.github/workflows/compile_development.yml index 223a7a39..9b3b68b3 100644 --- a/.github/workflows/compile_development.yml +++ b/.github/workflows/compile_development.yml @@ -24,9 +24,7 @@ jobs: matrix: variant: - opendtufusion - - opendtufusion-ethernet - opendtufusion-16MB - - opendtufusion-ethernet-16MB - esp8266 - esp8266-all - esp8266-minimal @@ -35,7 +33,6 @@ jobs: - esp32-wroom32 - esp32-wroom32-minimal - esp32-wroom32-prometheus - - esp32-wroom32-ethernet - esp32-s2-mini - esp32-c3-mini steps: @@ -95,16 +92,13 @@ jobs: matrix: variant: - opendtufusion-de - - opendtufusion-ethernet-de - opendtufusion-16MB-de - - opendtufusion-ethernet-16MB-de - esp8266-de - esp8266-all-de - esp8266-prometheus-de - esp8285-de - esp32-wroom32-de - esp32-wroom32-prometheus-de - - esp32-wroom32-ethernet-de - esp32-s2-mini-de - esp32-c3-mini-de steps: diff --git a/manual/factory_firmware.md b/manual/factory_firmware.md index a4025eea..047dd4b0 100644 --- a/manual/factory_firmware.md +++ b/manual/factory_firmware.md @@ -46,7 +46,7 @@ The upload should be finished within one minute. Reboot your ESP an check if all your settings are present. -## Keep updated with 'Mainline' +## Get updated with 'Mainline' From time to time a new version of AhoyDTU will be published. To get the changes into your already prepared factory binary generation environment you have to do only a few steps: diff --git a/src/CHANGES.md b/src/CHANGES.md index 133e145a..dccaa36a 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,27 @@ # Development Changes +## 0.8.135 - 2024-08-11 +* translated `/system` #1717 +* added default pin seetings for opendtufusion board +* fixed ethernet static IP +* fixed ethernet MAC address read back + +## 0.8.134 - 2024-08-10 +* combined Ethernet and WiFi variants - Ethernet is now always included, but needs to be enabled if needed +* improved statistic data in `/system` +* redesigned `/system` + +## 0.8.133 - 2024-08-10 +* Ethernet variants now support WiFi as fall back / configuration + +## 0.8.132 - 2024-08-09 +* fix boot loop once no ePaper is connected #1713, #1714 +* improved refresh routine of ePeper +* added default pin seetings for opendtufusion board + +## 0.8.131 - 2024-08-08 +* improved refresh routine of ePaper, full refresh each 12h #1107 #1706 + ## 0.8.130 - 2024-08-04 * fix message `ERR_DUPLICATE_INVERTER` #1705, #1700 * merge PR: Power limit command accelerated #1704 diff --git a/src/app.cpp b/src/app.cpp index accd0c87..c6a689ee 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -112,9 +112,7 @@ void app::setup() { mPubSerial.setup(mConfig, &mSys, &mTimestamp); - #if !defined(ETHERNET) //mImprov.setup(this, mConfig->sys.deviceName, mVersion); - #endif #if defined(ENABLE_SIMULATOR) mSimulator.setup(&mSys, &mTimestamp, 0); @@ -142,6 +140,10 @@ void app::loop(void) { if (mMqttEnabled && mNetworkConnected) mMqtt.loop(); #endif + + #if defined(PLUGIN_DISPLAY) + mDisplay.loop(); + #endif yield(); } @@ -174,9 +176,7 @@ void app::regularTickers(void) { everySec(std::bind(&DisplayType::tickerSecond, &mDisplay), "disp"); #endif every(std::bind(&PubSerialType::tick, &mPubSerial), 5, "uart"); - #if !defined(ETHERNET) //everySec([this]() { mImprov.tickSerial(); }, "impro"); - #endif #if defined(ENABLE_HISTORY) everySec(std::bind(&HistoryType::tickerSecond, &mHistory), "hist"); diff --git a/src/app.h b/src/app.h index 634696f2..d23f307e 100644 --- a/src/app.h +++ b/src/app.h @@ -45,8 +45,8 @@ #else #include "network/AhoyWifiEsp8266.h" #endif - #include "utils/improv.h" #endif /* defined(ETHERNET) */ +#include "utils/improv.h" #if defined(ENABLE_SIMULATOR) #include "hm/simulator.h" @@ -167,7 +167,6 @@ class app : public IApp, public ah::Scheduler { return mSaveReboot; } - #if !defined(ETHERNET) bool getAvailNetworks(JsonObject obj) override { return mNetwork->getAvailNetworks(obj, this); } @@ -183,12 +182,15 @@ class app : public IApp, public ah::Scheduler { return false; #endif } - #endif /* !defined(ETHERNET) */ String getIp(void) override { return mNetwork->getIp(); } + String getMac(void) override { + return mNetwork->getMac(); + } + bool isApActive(void) override { return mNetwork->isApActive(); } @@ -255,6 +257,12 @@ class app : public IApp, public ah::Scheduler { #endif } + #if defined(ETHERNET) + bool isWiredConnection() override { + return mNetwork->isWiredConnection(); + } + #endif + void lock(bool fromWeb) override { mProtection->lock(fromWeb); } @@ -433,9 +441,7 @@ class app : public IApp, public ah::Scheduler { #endif PubSerialType mPubSerial; - #if !defined(ETHERNET) //Improv mImprov; - #endif #ifdef ESP32 CmtRadio<> mCmtRadio; #endif diff --git a/src/appInterface.h b/src/appInterface.h index f2292ec8..d49f907e 100644 --- a/src/appInterface.h +++ b/src/appInterface.h @@ -28,12 +28,11 @@ class IApp { virtual void addOnce(ah::scdCb c, uint32_t timeout, const char *name) = 0; - #if !defined(ETHERNET) virtual bool getAvailNetworks(JsonObject obj) = 0; virtual void setupStation(void) = 0; virtual bool getWasInCh12to14(void) const = 0; - #endif /* defined(ETHERNET) */ virtual String getIp(void) = 0; + virtual String getMac(void) = 0; virtual bool isApActive(void) = 0; virtual uint32_t getUptime() = 0; @@ -59,6 +58,10 @@ class IApp { virtual uint32_t getMqttRxCnt() = 0; virtual uint32_t getMqttTxCnt() = 0; + #if defined(ETHERNET) + virtual bool isWiredConnection() = 0; + #endif + virtual void lock(bool fromWeb) = 0; virtual char *unlock(const char *clientIp, bool loginFromWeb) = 0; virtual void resetLockTimeout(void) = 0; diff --git a/src/config/settings.h b/src/config/settings.h index 41965998..0d8970d5 100644 --- a/src/config/settings.h +++ b/src/config/settings.h @@ -99,14 +99,13 @@ typedef struct { int8_t timezone; char apPwd[PWD_LEN]; -#if !defined(ETHERNET) // wifi char stationSsid[SSID_LEN]; char stationPwd[PWD_LEN]; bool isHidden; -#else + #if defined(ETHERNET) cfgEth_t eth; -#endif /* !defined(ETHERNET) */ + #endif cfgIp_t ip; } cfgSys_t; @@ -283,19 +282,7 @@ class settings { return mLastSaveSucceed; } - void getInfo(uint32_t *used, uint32_t *size) { - #if !defined(ESP32) - FSInfo info; - LittleFS.info(info); - *used = info.usedBytes; - *size = info.totalBytes; - DPRINTLN(DBG_INFO, F("-- FILESYSTEM INFO --")); - DPRINTLN(DBG_INFO, String(info.usedBytes) + F(" of ") + String(info.totalBytes) + F(" used")); - #else - DPRINTLN(DBG_WARN, F("not supported by ESP32")); - #endif - } bool readSettings(const char* path) { loadDefaults(); @@ -410,13 +397,11 @@ class settings { // restore temp settings if(keepWifi) memcpy(&mCfg.sys, &tmp, sizeof(cfgSys_t)); - #if !defined(ETHERNET) else { mCfg.sys.stationSsid[0] = '\0'; mCfg.sys.stationPwd[0] = '\0'; mCfg.sys.isHidden = false; } - #endif snprintf(mCfg.sys.apPwd, PWD_LEN, WIFI_AP_PWD); #if defined(ETHERNET) @@ -571,12 +556,10 @@ class settings { void jsonNetwork(JsonObject obj, bool set = false) { if(set) { char buf[16]; - #if !defined(ETHERNET) obj[F("ssid")] = mCfg.sys.stationSsid; obj[F("pwd")] = mCfg.sys.stationPwd; obj[F("ap_pwd")] = mCfg.sys.apPwd; obj[F("hidd")] = (bool) mCfg.sys.isHidden; - #endif /* !defined(ETHERNET) */ obj[F("dev")] = mCfg.sys.deviceName; obj[F("adm")] = mCfg.sys.adminPwd; obj[F("prot_mask")] = mCfg.sys.protectionMask; @@ -600,12 +583,10 @@ class settings { obj[F("rst")] = mCfg.sys.eth.pinRst; #endif } else { - #if !defined(ETHERNET) getChar(obj, F("ssid"), mCfg.sys.stationSsid, SSID_LEN); getChar(obj, F("pwd"), mCfg.sys.stationPwd, PWD_LEN); getChar(obj, F("ap_pwd"), mCfg.sys.apPwd, PWD_LEN); getVal(obj, F("hidd"), &mCfg.sys.isHidden); - #endif /* !defined(ETHERNET) */ getChar(obj, F("dev"), mCfg.sys.deviceName, DEVNAME_LEN); getChar(obj, F("adm"), mCfg.sys.adminPwd, PWD_LEN); getVal(obj, F("prot_mask"), &mCfg.sys.protectionMask); diff --git a/src/defines.h b/src/defines.h index 7324dea8..b1d7395d 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 130 +#define VERSION_PATCH 135 //------------------------------------- typedef struct { uint8_t ch; diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index f09fbe1d..026bf6d8 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -823,7 +823,8 @@ class Inverter { end = 0; for(; i < 10; i++) { - mAlarmNxtWrPos = (++mAlarmNxtWrPos) % 10; + ++mAlarmNxtWrPos; + mAlarmNxtWrPos = mAlarmNxtWrPos % 10; if(lastAlarm[mAlarmNxtWrPos].code == code && lastAlarm[mAlarmNxtWrPos].start == start) { // replace with same or update end time diff --git a/src/network/AhoyEthernet.h b/src/network/AhoyEthernet.h index 90255b26..f6564e1f 100644 --- a/src/network/AhoyEthernet.h +++ b/src/network/AhoyEthernet.h @@ -12,11 +12,20 @@ #include #include "AhoyEthernetSpi.h" #include "AhoyNetwork.h" +#include "AhoyWifiEsp32.h" + +class AhoyEthernet : public AhoyWifi { + private: + enum class Mode { + WIRED, + WIRELESS + }; -class AhoyEthernet : public AhoyNetwork { public: - void begin() override { + virtual void begin() override { + mMode = Mode::WIRELESS; mAp.enable(); + AhoyWifi::begin(); if(!mConfig->sys.eth.enabled) return; @@ -25,24 +34,66 @@ class AhoyEthernet : public AhoyNetwork { ETH.setHostname(mConfig->sys.deviceName); } - void OnEvent(WiFiEvent_t event) override { + virtual String getIp(void) override { + if(Mode::WIRELESS == mMode) + return AhoyWifi::getIp(); + else + return ETH.localIP().toString(); + } + + virtual String getMac(void) override { + if(Mode::WIRELESS == mMode) + return AhoyWifi::getMac(); + else + return mEthSpi.macAddress(); + } + + virtual bool isWiredConnection() override { + return (Mode::WIRED == mMode); + } + + private: + virtual void OnEvent(WiFiEvent_t event) override { switch(event) { case ARDUINO_EVENT_ETH_CONNECTED: + mMode = Mode::WIRED; // needed for static IP + [[fallthrough]]; + case SYSTEM_EVENT_STA_CONNECTED: + mWifiConnecting = false; if(NetworkState::CONNECTED != mStatus) { + if(ARDUINO_EVENT_ETH_CONNECTED == event) + WiFi.disconnect(); + mStatus = NetworkState::CONNECTED; DPRINTLN(DBG_INFO, F("Network connected")); setStaticIp(); } break; + case SYSTEM_EVENT_STA_GOT_IP: + mStatus = NetworkState::GOT_IP; + if(mAp.isEnabled()) + mAp.disable(); + + mMode = Mode::WIRELESS; + if(!mConnected) { + mConnected = true; + ah::welcome(WiFi.localIP().toString(), F("Station WiFi")); + MDNS.begin(mConfig->sys.deviceName); + mOnNetworkCB(true); + } + break; + case ARDUINO_EVENT_ETH_GOT_IP: mStatus = NetworkState::GOT_IP; + mMode = Mode::WIRED; if(!mConnected) { mAp.disable(); mConnected = true; - ah::welcome(ETH.localIP().toString(), F("Station")); + ah::welcome(ETH.localIP().toString(), F("Station Ethernet")); MDNS.begin(mConfig->sys.deviceName); mOnNetworkCB(true); + WiFi.disconnect(); } break; @@ -51,9 +102,25 @@ class AhoyEthernet : public AhoyNetwork { case ARDUINO_EVENT_ETH_DISCONNECTED: mStatus = NetworkState::DISCONNECTED; if(mConnected) { + mMode = Mode::WIRELESS; mConnected = false; mOnNetworkCB(false); - mAp.enable(); + MDNS.end(); + AhoyWifi::begin(); + } + break; + + case ARDUINO_EVENT_WIFI_STA_LOST_IP: + [[fallthrough]]; + case ARDUINO_EVENT_WIFI_STA_STOP: + [[fallthrough]]; + case SYSTEM_EVENT_STA_DISCONNECTED: + mStatus = NetworkState::DISCONNECTED; + if(mConnected && (Mode::WIRELESS == mMode)) { + mConnected = false; + mOnNetworkCB(false); + MDNS.end(); + AhoyWifi::begin(); } break; @@ -62,24 +129,19 @@ class AhoyEthernet : public AhoyNetwork { } } - void tickNetworkLoop() override { - if(mAp.isEnabled()) - mAp.tickLoop(); - } - - String getIp(void) override { - return ETH.localIP().toString(); - } - - private: void setStaticIp() override { setupIp([this](IPAddress ip, IPAddress gateway, IPAddress mask, IPAddress dns1, IPAddress dns2) -> bool { - return ETH.config(ip, gateway, mask, dns1, dns2); + if(Mode::WIRELESS == mMode) + return WiFi.config(ip, gateway, mask, dns1, dns2); + else + return ETH.config(ip, gateway, mask, dns1, dns2); }); } private: AhoyEthernetSpi mEthSpi; + Mode mMode; + }; #endif /*ETHERNET*/ diff --git a/src/network/AhoyEthernetSpi.h b/src/network/AhoyEthernetSpi.h index ab2eab9e..ec750592 100644 --- a/src/network/AhoyEthernetSpi.h +++ b/src/network/AhoyEthernetSpi.h @@ -116,10 +116,14 @@ class AhoyEthernetSpi { } String macAddress() { - uint8_t mac_addr[6] = {0, 0, 0, 0, 0, 0}; + uint8_t mac_addr[6]; esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, mac_addr); - char mac_addr_str[24]; - snprintf(mac_addr_str, sizeof(mac_addr_str), "%02X:%02X:%02X:%02X:%02X:%02X", mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]); + char mac_addr_str[19]; + for(uint8_t i = 0; i < 6; i++) { + snprintf(&mac_addr_str[i*3], sizeof(mac_addr_str), "%02X", mac_addr[i]); + mac_addr_str[i*3+2] = ':'; + } + mac_addr_str[17] = '\0'; return String(mac_addr_str); } diff --git a/src/network/AhoyNetwork.h b/src/network/AhoyNetwork.h index 7bc0bab2..e64a13b1 100644 --- a/src/network/AhoyNetwork.h +++ b/src/network/AhoyNetwork.h @@ -79,16 +79,20 @@ class AhoyNetwork { virtual void begin() = 0; virtual void tickNetworkLoop() = 0; virtual String getIp(void) = 0; + virtual String getMac(void) = 0; virtual bool getWasInCh12to14() { return false; } + virtual bool isWiredConnection() { + return false; + } + bool isApActive() { return mAp.isEnabled(); } - #if !defined(ETHERNET) bool getAvailNetworks(JsonObject obj, IApp *app) { if(!mScanActive) { app->addOnce([this]() {scan();}, 1, "scan"); @@ -122,7 +126,6 @@ class AhoyNetwork { } WiFi.scanNetworks(true, true); } - #endif protected: virtual void setStaticIp() = 0; @@ -173,7 +176,6 @@ class AhoyNetwork { } } - #if !defined(ETHERNET) void sortRSSI(int *sort, int n) { for (int i = 0; i < n; i++) sort[i] = i; @@ -182,7 +184,6 @@ class AhoyNetwork { if (WiFi.RSSI(sort[j]) > WiFi.RSSI(sort[i])) std::swap(sort[i], sort[j]); } - #endif private: void sendNTPpacket(void) { @@ -234,9 +235,7 @@ class AhoyNetwork { uint32_t *mUtcTimestamp = nullptr; bool mConnected = false; bool mScanActive = false; - #if !defined(ETHERNET) bool mWifiConnecting = false; - #endif OnNetworkCB mOnNetworkCB; OnTimeCB mOnTimeCB; diff --git a/src/network/AhoyWifiAp.h b/src/network/AhoyWifiAp.h index 669e8ec8..ed1ad3a3 100644 --- a/src/network/AhoyWifiAp.h +++ b/src/network/AhoyWifiAp.h @@ -36,11 +36,7 @@ class AhoyWifiAp { ah::welcome(mIp.toString(), String(F("Password: ") + String(mCfg->apPwd))); - #if defined(ETHERNET) - WiFi.mode(WIFI_AP); - #else WiFi.mode(WIFI_AP_STA); - #endif WiFi.softAPConfig(mIp, mIp, IPAddress(255, 255, 255, 0)); WiFi.softAP(WIFI_AP_SSID, mCfg->apPwd); @@ -60,12 +56,7 @@ class AhoyWifiAp { mDns.stop(); WiFi.softAPdisconnect(); - #if defined(ETHERNET) - WiFi.mode(WIFI_OFF); - #else - WiFi.scanDelete(); WiFi.mode(WIFI_STA); - #endif mEnabled = false; } diff --git a/src/network/AhoyWifiEsp32.h b/src/network/AhoyWifiEsp32.h index b718043a..70017518 100644 --- a/src/network/AhoyWifiEsp32.h +++ b/src/network/AhoyWifiEsp32.h @@ -6,7 +6,7 @@ #ifndef __AHOY_WIFI_ESP32_H__ #define __AHOY_WIFI_ESP32_H__ -#if defined(ESP32) && !defined(ETHERNET) +#if defined(ESP32) #include #include #include "AhoyNetwork.h" @@ -14,12 +14,13 @@ class AhoyWifi : public AhoyNetwork { public: - void begin() override { + virtual void begin() override { mAp.enable(); if(strlen(mConfig->sys.stationSsid) == 0) return; // no station wifi defined + WiFi.disconnect(); // clean up WiFi.setHostname(mConfig->sys.deviceName); #if !defined(AP_ONLY) @@ -35,7 +36,21 @@ class AhoyWifi : public AhoyNetwork { #endif } - void OnEvent(WiFiEvent_t event) override { + void tickNetworkLoop() override { + if(mAp.isEnabled()) + mAp.tickLoop(); + } + + virtual String getIp(void) override { + return WiFi.localIP().toString(); + } + + virtual String getMac(void) override { + return WiFi.macAddress(); + } + + private: + virtual void OnEvent(WiFiEvent_t event) override { switch(event) { case SYSTEM_EVENT_STA_CONNECTED: if(NetworkState::CONNECTED != mStatus) { @@ -77,22 +92,12 @@ class AhoyWifi : public AhoyNetwork { } } - void tickNetworkLoop() override { - if(mAp.isEnabled()) - mAp.tickLoop(); - } - - String getIp(void) override { - return WiFi.localIP().toString(); - } - - private: - void setStaticIp() override { + virtual void setStaticIp() override { setupIp([this](IPAddress ip, IPAddress gateway, IPAddress mask, IPAddress dns1, IPAddress dns2) -> bool { return WiFi.config(ip, gateway, mask, dns1, dns2); }); } }; -#endif /*ESP32 & !ETHERNET*/ +#endif /*ESP32*/ #endif /*__AHOY_WIFI_ESP32_H__*/ diff --git a/src/network/AhoyWifiEsp8266.h b/src/network/AhoyWifiEsp8266.h index b6ea65d2..c72f06b5 100644 --- a/src/network/AhoyWifiEsp8266.h +++ b/src/network/AhoyWifiEsp8266.h @@ -111,6 +111,10 @@ class AhoyWifi : public AhoyNetwork { return WiFi.localIP().toString(); } + String getMac(void) override { + return WiFi.macAddress(); + } + bool getWasInCh12to14() override { return mWasInCh12to14; } diff --git a/src/platformio.ini b/src/platformio.ini index 40bce86e..3156b206 100644 --- a/src/platformio.ini +++ b/src/platformio.ini @@ -27,7 +27,7 @@ extra_scripts = lib_deps = #https://github.com/esphome/ESPAsyncWebServer @ ^3.2.2 - https://github.com/mathieucarbou/ESPAsyncWebServer @ ^3.1.2 + https://github.com/mathieucarbou/ESPAsyncWebServer @ ^3.1.3 https://github.com/nRF24/RF24.git#v1.4.8 paulstoffregen/Time @ ^1.6.1 https://github.com/bertmelis/espMqttClient#v1.7.0 @@ -166,6 +166,24 @@ build_flags = ${env:esp32-wroom32-minimal.build_flags} -DENABLE_MQTT -DPLUGIN_DISPLAY -DENABLE_HISTORY + -DETHERNET + -DDEF_ETH_CS_PIN=15 + -DDEF_ETH_SCK_PIN=14 + -DDEF_ETH_MISO_PIN=12 + -DDEF_ETH_MOSI_PIN=13 + -DDEF_ETH_IRQ_PIN=4 + -DDEF_ETH_RST_PIN=255 + -DDEF_NRF_CS_PIN=5 + -DDEF_NRF_CE_PIN=17 + -DDEF_NRF_IRQ_PIN=16 + -DDEF_NRF_MISO_PIN=19 + -DDEF_NRF_MOSI_PIN=23 + -DDEF_NRF_SCLK_PIN=18 + -DDEF_CMT_CSB=27 + -DDEF_CMT_FCSB=26 + -DDEF_CMT_IRQ=34 + -DDEF_CMT_SDIO=14 + -DDEF_CMT_SCLK=12 monitor_filters = esp32_exception_decoder @@ -193,34 +211,6 @@ build_flags = ${env:esp32-wroom32-prometheus.build_flags} monitor_filters = esp32_exception_decoder -[env:esp32-wroom32-ethernet] -platform = espressif32 -board = lolin_d32 -build_flags = ${env:esp32-wroom32.build_flags} - -DETHERNET - -DDEF_ETH_CS_PIN=15 - -DDEF_ETH_SCK_PIN=14 - -DDEF_ETH_MISO_PIN=12 - -DDEF_ETH_MOSI_PIN=13 - -DDEF_ETH_IRQ_PIN=4 - -DDEF_ETH_RST_PIN=255 - -DDEF_NRF_CS_PIN=5 - -DDEF_NRF_CE_PIN=17 - -DDEF_NRF_IRQ_PIN=16 - -DDEF_NRF_MISO_PIN=19 - -DDEF_NRF_MOSI_PIN=23 - -DDEF_NRF_SCLK_PIN=18 -monitor_filters = - esp32_exception_decoder - -[env:esp32-wroom32-ethernet-de] -platform = espressif32 -board = lolin_d32 -build_flags = ${env:esp32-wroom32-ethernet.build_flags} - -DLANG_DE -monitor_filters = - esp32_exception_decoder - [env:esp32-s2-mini] platform = espressif32@6.7.0 board = lolin_s2_mini @@ -312,26 +302,6 @@ monitor_filters = platform = espressif32@6.7.0 board = esp32-s3-devkitc-1 upload_protocol = esp-builtin -build_flags = ${env:opendtufusion-minimal.build_flags} - -DENABLE_MQTT - -DPLUGIN_DISPLAY - -DENABLE_HISTORY -monitor_filters = - esp32_exception_decoder, colorize - -[env:opendtufusion-de] -platform = espressif32@6.7.0 -board = esp32-s3-devkitc-1 -upload_protocol = esp-builtin -build_flags = ${env:opendtufusion.build_flags} - -DLANG_DE -monitor_filters = - esp32_exception_decoder, colorize - -[env:opendtufusion-ethernet] -platform = espressif32@6.7.0 -board = esp32-s3-devkitc-1 -upload_protocol = esp-builtin build_flags = ${env:opendtufusion-minimal.build_flags} -DETHERNET -DENABLE_MQTT @@ -343,15 +313,14 @@ build_flags = ${env:opendtufusion-minimal.build_flags} -DDEF_ETH_MOSI_PIN=40 -DDEF_ETH_IRQ_PIN=44 -DDEF_ETH_RST_PIN=43 - -DDEF_ETH_ENABLED monitor_filters = esp32_exception_decoder, colorize -[env:opendtufusion-ethernet-de] +[env:opendtufusion-de] platform = espressif32@6.7.0 board = esp32-s3-devkitc-1 upload_protocol = esp-builtin -build_flags = ${env:opendtufusion-ethernet.build_flags} +build_flags = ${env:opendtufusion.build_flags} -DLANG_DE monitor_filters = esp32_exception_decoder, colorize @@ -373,21 +342,3 @@ build_flags = ${env:opendtufusion-16MB.build_flags} -DLANG_DE monitor_filters = esp32_exception_decoder, colorize - -[env:opendtufusion-ethernet-16MB] -platform = espressif32@6.7.0 -board = esp32-s3-devkitc-1 -board_upload.flash_size = 16MB -upload_protocol = esp-builtin -build_flags = ${env:opendtufusion-ethernet.build_flags} -monitor_filters = - esp32_exception_decoder, colorize - -[env:opendtufusion-ethernet-16MB-de] -platform = espressif32@6.7.0 -board = esp32-s3-devkitc-1 -upload_protocol = esp-builtin -build_flags = ${env:opendtufusion-ethernet-16MB.build_flags} - -DLANG_DE -monitor_filters = - esp32_exception_decoder, colorize diff --git a/src/plugins/Display/Display.h b/src/plugins/Display/Display.h index c818d217..1694fec6 100644 --- a/src/plugins/Display/Display.h +++ b/src/plugins/Display/Display.h @@ -72,6 +72,14 @@ class Display { } + void loop() { + #if defined(ESP32) && !defined(ETHERNET) + if ((nullptr != mCfg) && (DISP_TYPE_T10_EPAPER == mCfg->type)) { + mEpaper.refreshLoop(); + } + #endif + } + void payloadEventListener(uint8_t cmd) { mNewPayload = true; } @@ -190,7 +198,7 @@ class Display { mEpaper.loop((totalPower), totalYieldDay, totalYieldTotal, nrprod); mRefreshCycle++; - if (mRefreshCycle > 480) { + if (mRefreshCycle > 2880) { // 15 * 2280 = 44300s = 12h mEpaper.fullRefresh(); mRefreshCycle = 0; } diff --git a/src/plugins/Display/Display_ePaper.cpp b/src/plugins/Display/Display_ePaper.cpp index 86bb0d32..654627d2 100644 --- a/src/plugins/Display/Display_ePaper.cpp +++ b/src/plugins/Display/Display_ePaper.cpp @@ -26,25 +26,26 @@ void DisplayEPaper::init(uint8_t type, uint8_t _CS, uint8_t _DC, uint8_t _RST, u mRefreshState = RefreshStatus::LOGO; mSecondCnt = 0; + mLogoDisplayed = false; if (DISP_TYPE_T10_EPAPER == type) { - Serial.begin(115200); - -#if defined(SPI_HAL) - hal.init(_MOSI, _DC, _SCK, _CS, _RST, _BUSY); - _display = new GxEPD2_BW(GxEPD2_150_BN(&hal)); -#else - _display = new GxEPD2_BW(GxEPD2_150_BN(_CS, _DC, _RST, _BUSY)); - #if defined(USE_HSPI_FOR_EPD) + #if defined(SPI_HAL) + hal.init(_MOSI, _DC, _SCK, _CS, _RST, _BUSY); + _display = new GxEPD2_BW(GxEPD2_150_BN(&hal)); + #else + _display = new GxEPD2_BW(GxEPD2_150_BN(_CS, _DC, _RST, _BUSY)); + #if defined(USE_HSPI_FOR_EPD) hspi.begin(_SCK, _BUSY, _MOSI, _CS); _display->epd2.selectSPI(hspi, SPISettings(spiClk, MSBFIRST, SPI_MODE0)); - #elif defined(PLUGIN_DISPLAY) + #elif defined(PLUGIN_DISPLAY) _display->epd2.init(_SCK, _MOSI, 115200, true, 20, false); - #endif -#endif - _display->init(115200, true, 20, false); + #endif + #endif + _display->init(0, true, 20, false); _display->setRotation(mDisplayRotation); _display->setFullWindow(); + _display->setTextColor(GxEPD_BLACK); + _display->firstPage(); _version = version; } } @@ -58,7 +59,8 @@ void DisplayEPaper::config(uint8_t rotation, bool enPowerSave) { void DisplayEPaper::fullRefresh() { if(RefreshStatus::DONE != mRefreshState) return; - mSecondCnt = 2; + if(mLogoDisplayed) + return; // no refresh during logo display mRefreshState = RefreshStatus::BLACK; } @@ -66,40 +68,42 @@ void DisplayEPaper::fullRefresh() { void DisplayEPaper::refreshLoop() { switch(mRefreshState) { case RefreshStatus::LOGO: - _display->fillScreen(GxEPD_BLACK); - _display->drawBitmap(0, 0, logo, 200, 200, GxEPD_WHITE); - mSecondCnt = 2; - mNextRefreshState = RefreshStatus::PARTITIALS; - mRefreshState = RefreshStatus::WAIT; + _display->fillScreen(GxEPD_WHITE); + _display->drawInvertedBitmap(0, 0, logo, 200, 200, GxEPD_BLACK); + if(_display->nextPage()) + break; + mSecondCnt = 10; + _display->powerOff(); + mRefreshState = RefreshStatus::LOGO_WAIT; + break; + + case RefreshStatus::LOGO_WAIT: + if(0 != mSecondCnt) + break; + mRefreshState = RefreshStatus::WHITE; + _display->firstPage(); break; case RefreshStatus::BLACK: _display->fillScreen(GxEPD_BLACK); - mNextRefreshState = RefreshStatus::WHITE; - mRefreshState = RefreshStatus::WAIT; + if(_display->nextPage()) + break; + mRefreshState = RefreshStatus::WHITE; + _display->firstPage(); break; case RefreshStatus::WHITE: - if(0 != mSecondCnt) - break; _display->fillScreen(GxEPD_WHITE); - mNextRefreshState = RefreshStatus::PARTITIALS; - mRefreshState = RefreshStatus::WAIT; - break; - - case RefreshStatus::WAIT: - if(!_display->nextPage()) - mRefreshState = mNextRefreshState; + if(_display->nextPage()) + break; + mRefreshState = RefreshStatus::PARTITIALS; + _display->firstPage(); break; case RefreshStatus::PARTITIALS: - if(0 != mSecondCnt) - break; headlineIP(); versionFooter(); - mSecondCnt = 4; // display Logo time during boot up - mNextRefreshState = RefreshStatus::DONE; - mRefreshState = RefreshStatus::WAIT; + mRefreshState = RefreshStatus::DONE; break; default: // RefreshStatus::DONE @@ -219,7 +223,12 @@ void DisplayEPaper::actualPowerPaged(float totalPower, float totalYieldDay, floa if ((totalPower == 0) && (mEnPowerSave)) { _display->fillRect(0, mHeadFootPadding, 200, 200, GxEPD_BLACK); _display->drawBitmap(0, 0, logo, 200, 200, GxEPD_WHITE); + mLogoDisplayed = true; } else { + if(mLogoDisplayed) { + mLogoDisplayed = false; + fullRefresh(); + } _display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh); x = ((_display->width() - tbw) / 2) - tbx; _display->setCursor(x, mHeadFootPadding + tbh + 10); @@ -306,8 +315,9 @@ void DisplayEPaper::loop(float totalPower, float totalYieldDay, float totalYield //*************************************************************************** void DisplayEPaper::tickerSecond() { - if(mSecondCnt != 0) - mSecondCnt--; - refreshLoop(); + if(RefreshStatus::LOGO_WAIT == mRefreshState) { + if(mSecondCnt > 0) + mSecondCnt--; + } } #endif // ESP32 diff --git a/src/plugins/Display/Display_ePaper.h b/src/plugins/Display/Display_ePaper.h index 4fbb0959..2106c492 100644 --- a/src/plugins/Display/Display_ePaper.h +++ b/src/plugins/Display/Display_ePaper.h @@ -48,9 +48,9 @@ class DisplayEPaper { DONE, BLACK, WHITE, - WAIT, PARTITIALS, - LOGO + LOGO, + LOGO_WAIT }; uint8_t mDisplayRotation; @@ -62,8 +62,10 @@ class DisplayEPaper { uint32_t* mUtcTs; bool mEnPowerSave; const char* _version; - RefreshStatus mRefreshState, mNextRefreshState; + RefreshStatus mRefreshState; + uint8_t mSecondCnt; + bool mLogoDisplayed; #if defined(SPI_HAL) epdHal hal; #endif diff --git a/src/web/RestApi.h b/src/web/RestApi.h index 9d2d9644..9163839e 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -81,6 +81,12 @@ class RestApi { #ifndef ESP32 mHeapFreeBlk = ESP.getMaxFreeBlockSize(); mHeapFrag = ESP.getHeapFragmentation(); + #else + mHeapFreeBlk = heap_caps_get_largest_free_block(MALLOC_CAP_DEFAULT); + if(mHeapFree > 0) + mHeapFrag = 100 - ((mHeapFreeBlk * 100) / mHeapFree); + else + mHeapFrag = 0; #endif #if defined(ESP32) @@ -105,10 +111,8 @@ class RestApi { else if(path == "inverter/list") getInverterList(root); else if(path == "index") getIndex(request, root); else if(path == "setup") getSetup(request, root); - #if !defined(ETHERNET) else if(path == "setup/networks") getNetworks(root); else if(path == "setup/getip") getIp(root); - #endif /* !defined(ETHERNET) */ else if(path == "live") getLive(request,root); #if defined(ENABLE_HISTORY) else if (path == "powerHistory") getPowerHistory(request, root, HistoryStorageType::POWER); @@ -297,10 +301,8 @@ class RestApi { ep[F("generic")] = url + F("generic"); ep[F("index")] = url + F("index"); ep[F("setup")] = url + F("setup"); - #if !defined(ETHERNET) ep[F("setup/networks")] = url + F("setup/networks"); ep[F("setup/getip")] = url + F("setup/getip"); - #endif /* !defined(ETHERNET) */ ep[F("system")] = url + F("system"); ep[F("live")] = url + F("live"); #if defined(ENABLE_HISTORY) @@ -387,9 +389,7 @@ class RestApi { void getGeneric(AsyncWebServerRequest *request, JsonObject obj) { mApp->resetLockTimeout(); - #if !defined(ETHERNET) obj[F("wifi_rssi")] = (WiFi.status() != WL_CONNECTED) ? 0 : WiFi.RSSI(); - #endif obj[F("ts_uptime")] = mApp->getUptime(); obj[F("ts_now")] = mApp->getTimestamp(); obj[F("version")] = String(mApp->getVersion()); @@ -413,13 +413,6 @@ class RestApi { } void getSysInfo(AsyncWebServerRequest *request, JsonObject obj) { - obj[F("ap_pwd")] = mConfig->sys.apPwd; - #if !defined(ETHERNET) - obj[F("ssid")] = mConfig->sys.stationSsid; - obj[F("hidd")] = mConfig->sys.isHidden; - obj[F("mac")] = WiFi.macAddress(); - obj[F("wifi_channel")] = WiFi.channel(); - #endif /* !defined(ETHERNET) */ obj[F("device_name")] = mConfig->sys.deviceName; obj[F("dark_mode")] = (bool)mConfig->sys.darkMode; obj[F("sched_reboot")] = (bool)mConfig->sys.schedReboot; @@ -427,42 +420,15 @@ class RestApi { obj[F("pwd_set")] = (strlen(mConfig->sys.adminPwd) > 0); obj[F("prot_mask")] = mConfig->sys.protectionMask; - obj[F("sdk")] = ESP.getSdkVersion(); - obj[F("cpu_freq")] = ESP.getCpuFreqMHz(); - obj[F("heap_free")] = mHeapFree; - obj[F("sketch_total")] = ESP.getFreeSketchSpace(); - obj[F("sketch_used")] = ESP.getSketchSize() / 1024; // in kb - getGeneric(request, obj); - + getGeneric(request, obj.createNestedObject(F("generic"))); + getChipInfo(obj.createNestedObject(F("chip"))); getRadioNrf(obj.createNestedObject(F("radioNrf"))); + getMqttInfo(obj.createNestedObject(F("mqtt"))); + getNetworkInfo(obj.createNestedObject(F("network"))); + getMemoryInfo(obj.createNestedObject(F("memory"))); #if defined(ESP32) getRadioCmtInfo(obj.createNestedObject(F("radioCmt"))); #endif - getMqttInfo(obj.createNestedObject(F("mqtt"))); - - #if defined(ESP32) - obj[F("chip_revision")] = ESP.getChipRevision(); - obj[F("chip_model")] = ESP.getChipModel(); - obj[F("chip_cores")] = ESP.getChipCores(); - obj[F("heap_total")] = ESP.getHeapSize(); - //obj[F("core_version")] = F("n/a"); - //obj[F("flash_size")] = F("n/a"); - //obj[F("heap_frag")] = F("n/a"); - //obj[F("max_free_blk")] = F("n/a"); - //obj[F("reboot_reason")] = F("n/a"); - #else - //obj[F("heap_total")] = F("n/a"); - //obj[F("chip_revision")] = F("n/a"); - //obj[F("chip_model")] = F("n/a"); - //obj[F("chip_cores")] = F("n/a"); - obj[F("heap_frag")] = mHeapFrag; - obj[F("max_free_blk")] = mHeapFreeBlk; - obj[F("core_version")] = ESP.getCoreVersion(); - obj[F("flash_size")] = ESP.getFlashChipRealSize() / 1024; // in kb - obj[F("reboot_reason")] = ESP.getResetReason(); - #endif - //obj[F("littlefs_total")] = LittleFS.totalBytes(); - //obj[F("littlefs_used")] = LittleFS.usedBytes(); /*uint8_t max; mApp->getSchedulerInfo(&max); @@ -834,6 +800,104 @@ class RestApi { } #endif + void getNetworkInfo(JsonObject obj) { + #if defined(ETHERNET) + bool isWired = mApp->isWiredConnection(); + if(!isWired) + obj[F("wifi_channel")] = WiFi.channel(); + + obj[F("wired")] = isWired; + #else + obj[F("wired")] = false; + obj[F("wifi_channel")] = WiFi.channel(); + #endif + + obj[F("ap_pwd")] = mConfig->sys.apPwd; + obj[F("ssid")] = mConfig->sys.stationSsid; + obj[F("hidd")] = mConfig->sys.isHidden; + obj[F("mac")] = mApp->getMac(); + obj[F("ip")] = mApp->getIp(); + } + + void getChipInfo(JsonObject obj) { + obj[F("cpu_freq")] = ESP.getCpuFreqMHz(); + obj[F("sdk")] = ESP.getSdkVersion(); + #if defined(ESP32) + obj[F("revision")] = ESP.getChipRevision(); + obj[F("model")] = ESP.getChipModel(); + obj[F("cores")] = ESP.getChipCores(); + + switch (esp_reset_reason()) { + default: + [[fallthrough]]; + case ESP_RST_UNKNOWN: + obj[F("reboot_reason")] = F("Unknown"); + break; + case ESP_RST_POWERON: + obj[F("reboot_reason")] = F("Power on"); + break; + case ESP_RST_EXT: + obj[F("reboot_reason")] = F("External"); + break; + case ESP_RST_SW: + obj[F("reboot_reason")] = F("Software"); + break; + case ESP_RST_PANIC: + obj[F("reboot_reason")] = F("Panic"); + break; + case ESP_RST_INT_WDT: + obj[F("reboot_reason")] = F("Interrupt Watchdog"); + break; + case ESP_RST_TASK_WDT: + obj[F("reboot_reason")] = F("Task Watchdog"); + break; + case ESP_RST_WDT: + obj[F("reboot_reason")] = F("Watchdog"); + break; + case ESP_RST_DEEPSLEEP: + obj[F("reboot_reason")] = F("Deepsleep"); + break; + case ESP_RST_BROWNOUT: + obj[F("reboot_reason")] = F("Brownout"); + break; + case ESP_RST_SDIO: + obj[F("reboot_reason")] = F("SDIO"); + break; + } + #else + obj[F("core_version")] = ESP.getCoreVersion(); + obj[F("reboot_reason")] = ESP.getResetReason(); + #endif + } + + void getMemoryInfo(JsonObject obj) { + obj[F("heap_frag")] = mHeapFrag; + obj[F("heap_max_free_blk")] = mHeapFreeBlk; + obj[F("heap_free")] = mHeapFree; + + obj[F("par_size_app0")] = ESP.getFreeSketchSpace(); + obj[F("par_used_app0")] = ESP.getSketchSize(); + + #if defined(ESP32) + obj[F("heap_total")] = ESP.getHeapSize(); + + const esp_partition_t *partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_COREDUMP, "coredump"); + if (partition != NULL) + obj[F("flash_size")] = partition->address + partition->size; + + obj[F("par_size_spiffs")] = LittleFS.totalBytes(); + obj[F("par_used_spiffs")] = LittleFS.usedBytes(); + #else + obj[F("flash_size")] = ESP.getFlashChipRealSize(); + + FSInfo info; + LittleFS.info(info); + obj[F("par_used_spiffs")] = info.usedBytes; + obj[F("par_size_spiffs")] = info.totalBytes; + obj[F("heap_total")] = 24*1014; // FIXME: don't know correct value + #endif + } + void getRadioNrf(JsonObject obj) { obj[F("en")] = (bool) mConfig->nrf.enabled; if(mConfig->nrf.enabled) { @@ -921,11 +985,9 @@ class RestApi { warn.add(F(REBOOT_ESP_APPLY_CHANGES)); if(0 == mApp->getTimestamp()) warn.add(F(TIME_NOT_SET)); - #if !defined(ETHERNET) - #if !defined(ESP32) - if(mApp->getWasInCh12to14()) - warn.add(F(WAS_IN_CH_12_TO_14)); - #endif + #if !defined(ESP32) + if(mApp->getWasInCh12to14()) + warn.add(F(WAS_IN_CH_12_TO_14)); #endif } @@ -949,12 +1011,10 @@ class RestApi { getDisplay(obj.createNestedObject(F("display"))); } - #if !defined(ETHERNET) void getNetworks(JsonObject obj) { obj[F("success")] = mApp->getAvailNetworks(obj); obj[F("ip")] = mApp->getIp(); } - #endif /* !defined(ETHERNET) */ void getIp(JsonObject obj) { obj[F("ip")] = mApp->getIp(); @@ -1099,14 +1159,13 @@ class RestApi { mTimezoneOffset = jsonIn[F("val")]; else if(F("discovery_cfg") == jsonIn[F("cmd")]) mApp->setMqttDiscoveryFlag(); // for homeassistant - #if !defined(ETHERNET) else if(F("save_wifi") == jsonIn[F("cmd")]) { snprintf(mConfig->sys.stationSsid, SSID_LEN, "%s", jsonIn[F("ssid")].as()); snprintf(mConfig->sys.stationPwd, PWD_LEN, "%s", jsonIn[F("pwd")].as()); mApp->saveSettings(false); // without reboot mApp->setupStation(); } - #else + #if defined(ETHERNET) else if(F("save_eth") == jsonIn[F("cmd")]) { mConfig->sys.eth.enabled = jsonIn[F("en")].as(); mConfig->sys.eth.pinCs = jsonIn[F("cs")].as(); @@ -1117,7 +1176,7 @@ class RestApi { mConfig->sys.eth.pinRst = jsonIn[F("reset")].as(); mApp->saveSettings(true); } - #endif /* !defined(ETHERNET */ + #endif else if(F("save_iv") == jsonIn[F("cmd")]) { Inverter<> *iv; diff --git a/src/web/html/api.js b/src/web/html/api.js index 4930ce17..12ab239b 100644 --- a/src/web/html/api.js +++ b/src/web/html/api.js @@ -244,6 +244,10 @@ function badge(success, text, second="error") { return ml("span", {class: "badge badge-" + ((success) ? "success" : second)}, text); } +function progress(val) { + return ml("div", {class: "progress"}, ml("div", {class: "progress-bar", style: "width: " + val + "%"}, null)) +} + function tabChange(id) { var els = document.getElementsByClassName("nav-link"); [].forEach.call(els, function(e) { diff --git a/src/web/html/setup.html b/src/web/html/setup.html index 4fade8f5..63b700bf 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -56,8 +56,6 @@
{#AP_PWD}
- -
SSID
@@ -73,7 +71,6 @@
{#PASSWORD}
-
{#STATIC_IP} @@ -460,24 +457,24 @@ [1, "GPIO1"], [2, "GPIO2"], [3, "GPIO3"], - [4, "GPIO4"], - [5, "GPIO5"], - [6, "GPIO6"], + [4, "GPIO4 (CMT CSB)"], + [5, "GPIO5 (CMT SDIO)"], + [6, "GPIO6 (CMT SCLK)"], [7, "GPIO7"], - [8, "GPIO8"], - [9, "GPIO9"], - [10, "GPIO10"], - [11, "GPIO11"], - [12, "GPIO12"], - [13, "GPIO13"], - [14, "GPIO14"], + [8, "GPIO8 (CMT GPIO3)"], + [9, "GPIO9 (DATA display)"], + [10, "GPIO10 (SCK display)"], + [11, "GPIO11 (CS display)"], + [12, "GPIO12 (DC display)"], + [13, "GPIO13 (RST display)"], + [14, "GPIO14 (BUSY display)"], [15, "GPIO15"], [16, "GPIO16"], [17, "GPIO17"], [18, "GPIO18"], [19, "GPIO19 ({#PIN_DONT_USE} - USB-)"], [20, "GPIO20 ({#PIN_DONT_USE} - USB+)"], - [21, "GPIO21"], + [21, "GPIO21 (CMT FCSB)"], [26, "GPIO26 (PSRAM - {#PIN_NOT_AVAIL})"], [27, "GPIO27 (FLASH - {#PIN_NOT_AVAIL})"], [28, "GPIO28 (FLASH - {#PIN_NOT_AVAIL})"], @@ -487,20 +484,20 @@ [32, "GPIO32 (FLASH - {#PIN_NOT_AVAIL})"], [33, "GPIO33 (not exposed on S3-WROOM modules)"], [34, "GPIO34 (not exposed on S3-WROOM modules)"], - [35, "GPIO35"], - [36, "GPIO36"], - [37, "GPIO37"], - [38, "GPIO38"], - [39, "GPIO39"], - [40, "GPIO40"], - [41, "GPIO41"], - [42, "GPIO42"], - [43, "GPIO43"], - [44, "GPIO44"], + [35, "GPIO35 (MOSI NRF24)"], + [36, "GPIO36 (SCK NRF24)"], + [37, "GPIO37 (CSN NRF24)"], + [38, "GPIO38 (CE NRF24)"], + [39, "GPIO39 (SCK ETH)"], + [40, "GPIO40 (MOSI ETH)"], + [41, "GPIO41 (MISO ETH)"], + [42, "GPIO42 (CS ETH)"], + [43, "GPIO43 (RST ETH)"], + [44, "GPIO44 (INT ETH)"], [45, "GPIO45 ({#PIN_DONT_USE} - STRAPPING PIN)"], [46, "GPIO46 ({#PIN_DONT_USE} - STRAPPING PIN)"], - [47, "GPIO47"], - [48, "GPIO48"], + [47, "GPIO47 (IRQ NRF24)"], + [48, "GPIO48 (MISO NRF24)"], ]; /*ENDIF_ESP32-S3*/ /*IF_ESP32-C3*/ @@ -685,14 +682,10 @@ } function parseSys(obj) { - /*IF_ETHERNET*/ - for(var i of [["device", "device_name"], ["ap_pwd", "ap_pwd"]]) - document.getElementsByName(i[0])[0].value = obj[i[1]]; - /*ELSE*/ for(var i of [["device", "device_name"], ["ssid", "ssid"], ["ap_pwd", "ap_pwd"]]) document.getElementsByName(i[0])[0].value = obj[i[1]]; document.getElementsByName("hidd")[0].checked = obj["hidd"]; - /*ENDIF_ETHERNET*/ + document.getElementsByName("darkMode")[0].checked = obj["dark_mode"]; document.getElementsByName("schedReboot")[0].checked = obj["sched_reboot"]; e = document.getElementsByName("adminpwd")[0]; diff --git a/src/web/html/style.css b/src/web/html/style.css index cda2df23..6f05ea77 100644 --- a/src/web/html/style.css +++ b/src/web/html/style.css @@ -859,3 +859,16 @@ ul { height: 100%; overflow: auto; } + +.progress { + display: flex; + height: 1rem; + overflow: hidden; + background-color: #e9ecef; + border-radius: .25rem; +} + +.progress-bar { + display: flex; + background-color: var(--primary); +} diff --git a/src/web/html/system.html b/src/web/html/system.html index ec21f8bd..477b3a7e 100644 --- a/src/web/html/system.html +++ b/src/web/html/system.html @@ -8,7 +8,7 @@ {#HTML_NAV}
-
+
@@ -21,17 +21,31 @@ parseTitle(obj) } + function parseUptime(up) { + var days = parseInt(up / 86400) % 365 + var hrs = parseInt(up / 3600) % 24 + var min = parseInt(up / 60) % 60 + var sec = up % 60 + var str = days + " day" + if(1 != days) + str += "s" + str += ", " + ("0"+hrs).substr(-2) + ":" + + ("0"+min).substr(-2) + ":" + + ("0"+sec).substr(-2) + + return ml("span", {}, str) + } + function parseSysInfo(obj) { - const data = ["sdk", "cpu_freq", "chip_revision", "device_name", - "chip_model", "chip_cores", "esp_type", "mac", "wifi_rssi", "wifi_channel", "ts_uptime", - "flash_size", "sketch_used", "heap_total", "heap_free", "heap_frag", - "max_free_blk", "version", "modules", "env", "core_version", "reboot_reason"]; - - lines = []; - for (const [key, value] of Object.entries(obj)) { - if(!data.includes(key) || (typeof value == 'undefined')) continue; - lines.push(tr(key.replace('_', ' '), value)); - } + lines = [ + tr("{#DEVICE_NAME}", obj.device_name), + tr("{#UPTIME}", parseUptime(obj.generic.ts_uptime)), + tr("{#REBOOT_REASON}", obj.chip.reboot_reason), + tr("{#ENVIRONMENT}", obj.generic.env + " ({#BUILD_OPTIONS}: " + obj.generic.modules + ")"), + tr("Version", obj.generic.version + " - " + obj.generic.build), + tr("Chip", "CPU: " + obj.chip.cpu_freq + "MHz, " + obj.chip.cores + " Core(s)"), + tr("Chip Model", obj.chip.model) + ] document.getElementById("info").append( headline("System Information"), @@ -47,9 +61,9 @@ function irqBadge(state) { switch(state) { - case 0: return badge(false, "{#UNKNOWN}", "warning"); break; - case 1: return badge(true, "{#TRUE}"); break; - default: return badge(false, "{#FALSE}"); break; + case 0: return badge(false, "unknown", "warning"); break; + case 1: return badge(true, "true"); break; + default: return badge(false, "false"); break; } } @@ -59,15 +73,15 @@ if(obj.radioNrf.en) { lines = [ tr("NRF24L01", badge(obj.radioNrf.isconnected, ((obj.radioNrf.isconnected) ? "" : "{#NOT} ") + "{#CONNECTED}")), - tr("{#IRQ_WORKING}", irqBadge(obj.radioNrf.irqOk)), - tr("{#NRF24_DATA_RATE}", dr[obj.radioNrf.dataRate] + "bps"), - tr("DTU Radio ID", obj.radioNrf.sn) + tr("{#INTR_PIN_WORKING}", irqBadge(obj.radioNrf.irqOk)), + tr("NRF24 {#DATA_RATE}", dr[obj.radioNrf.dataRate] + "bps"), + tr("DTU {#RADIO} ID", obj.radioNrf.sn) ]; } else - lines = [tr("NRF24L01", badge(false, "{#NOT_ENABLED}"))]; + lines = [tr("NRF24L01", badge(false, "{#NOT} {#ENABLED}"))]; document.getElementById("info").append( - headline("{#NRF24_RADIO}"), + headline("{#RADIO} NRF24"), ml("table", {class: "table"}, ml("tbody", {}, lines) ) @@ -77,14 +91,14 @@ if(obj.radioCmt.en) { cmt = [ tr("CMT2300A", badge(obj.radioCmt.isconnected, ((obj.radioCmt.isconnected) ? "" : "{#NOT} ") + "{#CONNECTED}")), - tr("{#IRQ_WORKING}", irqBadge(obj.radioCmt.irqOk)), - tr("DTU Radio ID", obj.radioCmt.sn) + tr("{#INTR_PIN_WORKING}", irqBadge(obj.radioCmt.irqOk)), + tr("DTU {#RADIO} ID", obj.radioCmt.sn) ]; } else - cmt = [tr("CMT2300A", badge(false, "{#NOT_ENABLED}"))]; + cmt = [tr("CMT2300A", badge(false, "{#NOT} {#ENABLED}"))]; document.getElementById("info").append( - headline("{#CMT_RADIO}"), + headline("{#RADIO} CMT"), ml("table", {class: "table"}, ml("tbody", {}, cmt) ) @@ -92,16 +106,32 @@ /*ENDIF_ESP32*/ } + function parseNetwork(obj, gen) { + lines = [ + tr("{#CONNECTION}", ((obj.wired) ? "{#WIRED}" : "{#WIFI} (SSID: " + obj.ssid + ", RSSI: " + gen.wifi_rssi + ", CH: " + obj.wifi_channel + ")")), + tr("Hostname", gen.host), + tr("IP {#ADDRESS}", obj.ip), + tr("MAC {#ADDRESS}", obj.mac) + ] + + document.getElementById("info").append( + headline("{#NETWORK}"), + ml("table", {class: "table"}, + ml("tbody", {}, lines) + ) + ); + } + function parseMqtt(obj) { if(obj.enabled) { lines = [ - tr("{#CONNECTED}", badge(obj.connected, ((obj.connected) ? "{#TRUE}" : "{#FALSE}"))), + tr("{#CONNECTED}", badge(obj.connected, ((obj.connected) ? "true" : "false"))), tr("#TX", obj.tx_cnt), tr("#RX", obj.rx_cnt) - ]; + ] } else - lines = tr("{#ENABLED}", badge(false, "{#FALSE}")); + lines = tr("enabled", badge(false, "false")); document.getElementById("info").append( headline("MqTT"), @@ -111,17 +141,34 @@ ); } + function parseMemory(obj) { + lines = [ + tr("{#FLASH_SIZE}", obj.flash_size / 1024 / 1024 + "MB"), + tr("{#CONFIG_PARTITION} (" + Math.round(obj.par_used_spiffs / 1024) + "kB of " + obj.par_size_spiffs / 1024 + "kB)", progress(obj.par_used_spiffs / obj.par_size_spiffs * 100)), + tr("{#FIRMWARE_PARTITION} (" + Math.round(obj.par_used_app0 / 1024) + "kB of " + obj.par_size_app0 / 1024 + "kB)", progress(obj.par_used_app0 / obj.par_size_app0 * 100)), + tr("Heap (" + Math.round(obj.heap_free / 1024) + "kB of " + Math.round(obj.heap_total / 1024) + "kB)", progress(obj.heap_free / obj.heap_total * 100)), + tr("Heap {#MAX_FREE_BLOCK}", Math.round(obj.heap_max_free_blk / 1024) + "kB (Fragmentation: " + obj.heap_frag + ")") + ] + + document.getElementById("info").append( + headline("{#MEMORY}"), + ml("table", {class: "table"}, + ml("tbody", {}, lines) + ) + ); + } + function parseIndex(obj) { if(obj.ts_sunrise > 0) { document.getElementById("info").append( - headline("{#SUN}"), + headline("Sun"), ml("table", {class: "table"}, ml("tbody", {}, [ tr("{#SUNRISE}", new Date(obj.ts_sunrise * 1000).toLocaleString('de-DE')), tr("{#SUNSET}", new Date(obj.ts_sunset * 1000).toLocaleString('de-DE')), tr("{#COMMUNICATION_START}", new Date((obj.ts_sunrise + obj.ts_offsSr) * 1000).toLocaleString('de-DE')), tr("{#COMMUNICATION_STOP}", new Date((obj.ts_sunset + obj.ts_offsSs) * 1000).toLocaleString('de-DE')), - tr("{#NIGHT_BEHAVE}", badge(obj.disNightComm, ((obj.disNightComm) ? "{#NOT}" : "") + " {#COMMUNICATING}", "warning")) + tr("{#NIGHT_BEHAVIOR}", badge(obj.disNightComm, ((obj.disNightComm) ? "{#NOT}" : "") + " {#COMMUNICATING}", "warning")) ]) ) ); @@ -138,10 +185,12 @@ meta.content = obj.refresh + "; URL=" + obj.refresh_url; document.getElementsByTagName('head')[0].appendChild(meta); } else if(null != obj.system) { - parseRadio(obj.system); - parseMqtt(obj.system.mqtt); - parseSysInfo(obj.system); - getAjax('/api/index', parseIndex); + parseRadio(obj.system) + parseNetwork(obj.system.network, obj.system.generic) + parseMqtt(obj.system.mqtt) + parseMemory(obj.system.memory) + parseSysInfo(obj.system) + getAjax('/api/index', parseIndex) } document.getElementById("html").innerHTML = obj.html; } diff --git a/src/web/html/wizard.html b/src/web/html/wizard.html index 98333c12..199f66db 100644 --- a/src/web/html/wizard.html +++ b/src/web/html/wizard.html @@ -210,8 +210,8 @@ ml("div", {class: "row mt-5"}, ml("div", {class: "col a-c"}, ml("a", {onclick: () => {redirect()}}, "{#STOP_WIZARD}"))) ]) } - /*ELSE*/ - function step1() { + /*ENDIF_ETHERNET*/ + function step1Wifi() { return ml("div", {}, [ ml("div", {class: "row my-5"}, ml("div", {class: "col"}, ml("span", {class: "fs-1"}, "{#WELCOME}"))), ml("div", {class: "row"}, ml("div", {class: "col"}, ml("span", {class: "fs-5"}, "{#NETWORK_SETUP}"))), @@ -222,7 +222,6 @@ ml("div", {class: "row mt-5"}, ml("div", {class: "col a-c"}, ml("a", {onclick: () => {redirect()}}, "{#STOP_WIZARD}"))) ]) } - /*ENDIF_ETHERNET*/ function checkWifi() { c.replaceChildren( @@ -258,19 +257,18 @@ } getAjax("/api/setup", ((o) => {}), "POST", JSON.stringify(o)); } - /*ELSE*/ + /*ENDIF_ETHERNET*/ function saveWifi() { var ssid = document.getElementById("net").value; if(-1 == ssid) ssid = document.getElementById("man").value; getAjax("/api/setup", ((o) => {if(!o.error) checkWifi()}), "POST", JSON.stringify({cmd: "save_wifi", ssid: ssid, pwd: document.getElementById("pwd").value})); } - /*ENDIF_ETHERNET*/ function init() { /*IF_ETHERNET*/ getAjax("/api/setup", ((o) => c.append(step1(o.eth)))); - /*ELSE*/ + /*ENDIF_ETHERNET*/ function nets(obj) { clearInterval(v) v = setInterval(() => {getAjax('/api/setup/networks', nets)}, 4000) @@ -293,9 +291,8 @@ redirIp = "http://" + obj.ip + "/index" } - c.append(step1()) + c.append(step1Wifi()) getAjax('/api/setup/networks', nets) - /*ENDIF_ETHERNET*/ } diff --git a/src/web/lang.json b/src/web/lang.json index 6f1b7c03..179c3e4e 100644 --- a/src/web/lang.json +++ b/src/web/lang.json @@ -907,6 +907,151 @@ "token": "COMMUNICATING", "en": "communicating", "de": "aktiv" + }, + { + "token": "NETWORK", + "en": "Network", + "de": "Netzwerk" + }, + { + "token": "CONNECTION_TYPE", + "en": "connection", + "de": "Verbindung" + }, + { + "token": "WIRED", + "en": "ethernet cable", + "de": "Netzwerkkabel" + }, + { + "token": "WIFI", + "en": "WiFi", + "de": "WiFi" + }, + { + "token": "DEVICE_NAME", + "en": "Device name", + "de": "Gerätename" + }, + { + "token": "UPTIME", + "en": "Uptime", + "de": "Laufzeit" + }, + { + "token": "REBOOT_REASON", + "en": "Reboot reason", + "de": "Grund des Neustarts" + }, + { + "token": "ENVIRONMENT", + "en": "Environment", + "de": "Umgebung" + }, + { + "token": "BUILD_OPTIONS", + "en": "build options", + "de": "Module" + }, + { + "token": "ADDRESS", + "en": "Address", + "de": "Adresse" + }, + { + "token": "NETWORK", + "en": "Network", + "de": "Netzwerk" + }, + { + "token": "MEMORY", + "en": "Memory", + "de": "Speicher" + }, + { + "token": "CONFIG_PARTITION", + "en": "Config Partition", + "de": "Konfiguration" + }, + { + "token": "FIRMWARE_PARTITION", + "en": "Firmware Partition", + "de": "Firmware" + }, + { + "token": "INTR_PIN_WORKING", + "en": "Interrupt Pin working", + "de": "Interrupt Pin funktioniert" + }, + { + "token": "DATA_RATE", + "en": "Data Rate", + "de": "Datenrate" + }, + { + "token": "RADIO", + "en": "Radio", + "de": "Funkmodul" + }, + { + "token": "NOT", + "en": "not", + "de": "nicht" + }, + { + "token": "CONNECTED", + "en": "connected", + "de": "verbunden" + }, + { + "token": "ENABLED", + "en": "enabled", + "de": "aktiviert" + }, + { + "token": "CONNECTION", + "en": "connection", + "de": "Verbindung" + }, + { + "token": "FLASH_SIZE", + "en": "Flash size", + "de": "Speichergröße" + }, + { + "token": "MAX_FREE_BLOCK", + "en": "max free block", + "de": "maximale freie Blockgröße" + }, + { + "token": "SUNRISE", + "en": "sunrise", + "de": "Sonnenaufgang" + }, + { + "token": "SUNSET", + "en": "sunset", + "de": "Sonnenuntergang" + }, + { + "token": "COMMUNICATION_START", + "en": "Communication start", + "de": "Start der Kommunikation" + }, + { + "token": "COMMUNICATION_STOP", + "en": "Communication stop", + "de": "Ende der Kommunikation" + }, + { + "token": "NIGHT_BEHAVIOR", + "en": "Night behavior", + "de": "Verhalten bei Nacht" + }, + { + "token": "COMMUNICATING", + "en": "communicating", + "de": "kommunizierend" } ] }, diff --git a/src/web/web.h b/src/web/web.h index f44cc524..8001bb6e 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -162,18 +162,14 @@ class Web { mUploadFp.write(data, len); if (final) { mUploadFp.close(); - #if !defined(ETHERNET) char pwd[PWD_LEN]; strncpy(pwd, mConfig->sys.stationPwd, PWD_LEN); // backup WiFi PWD - #endif if (!mApp->readSettings("/tmp.json")) { mUploadFail = true; DPRINTLN(DBG_ERROR, F("upload JSON error!")); } else { LittleFS.remove("/tmp.json"); - #if !defined(ETHERNET) strncpy(mConfig->sys.stationPwd, pwd, PWD_LEN); // restore WiFi PWD - #endif for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { if((mConfig->inst.iv[i].serial.u64 != 0) && (mConfig->inst.iv[i].serial.u64 < 138999999999)) { // hexadecimal mConfig->inst.iv[i].serial.u64 = ah::Serial2u64(String(mConfig->inst.iv[i].serial.u64).c_str()); @@ -322,10 +318,18 @@ class Web { } void onIndex(AsyncWebServerRequest *request, bool checkAp = true) { + #if !defined(ETHERNET) if(mApp->isApActive() && checkAp) { onWizard(request); return; } + #else + // show wizard only if ethernet is not configured + if(mApp->isApActive() && checkAp && !mConfig->sys.eth.enabled) { + onWizard(request); + return; + } + #endif getPage(request, PROT_MASK_INDEX, index_html, index_html_len); } @@ -432,6 +436,13 @@ class Web { } void onWizard(AsyncWebServerRequest *request) { + #if defined(ETHERNET) + if(mConfig->sys.eth.enabled) { + getPage(request, PROT_MASK_INDEX, index_html, index_html_len); + return; + } + #endif + AsyncWebServerResponse *response = request->beginResponse(200, F("text/html; charset=UTF-8"), wizard_html, wizard_html_len); response->addHeader(F("Content-Encoding"), "gzip"); response->addHeader(F("content-type"), "text/html; charset=UTF-8"); @@ -449,13 +460,12 @@ class Web { char buf[20] = {0}; // general - #if !defined(ETHERNET) if (request->arg("ssid") != "") request->arg("ssid").toCharArray(mConfig->sys.stationSsid, SSID_LEN); if (request->arg("pwd") != "{PWD}") request->arg("pwd").toCharArray(mConfig->sys.stationPwd, PWD_LEN); mConfig->sys.isHidden = (request->arg("hidd") == "on"); - #endif /* !defined(ETHERNET) */ + if (request->arg("ap_pwd") != "") request->arg("ap_pwd").toCharArray(mConfig->sys.apPwd, PWD_LEN); if (request->arg("device") != "")