Browse Source

Merge branch 'development03' into feature/newAsyncWebserver

updated async web server library patch version
pull/1738/merge
lumapu 5 months ago
parent
commit
0d4ca524d8
  1. 6
      .github/workflows/compile_development.yml
  2. 2
      manual/factory_firmware.md
  3. 22
      src/CHANGES.md
  4. 8
      src/app.cpp
  5. 16
      src/app.h
  6. 7
      src/appInterface.h
  7. 23
      src/config/settings.h
  8. 2
      src/defines.h
  9. 3
      src/hm/hmInverter.h
  10. 94
      src/network/AhoyEthernet.h
  11. 10
      src/network/AhoyEthernetSpi.h
  12. 11
      src/network/AhoyNetwork.h
  13. 9
      src/network/AhoyWifiAp.h
  14. 35
      src/network/AhoyWifiEsp32.h
  15. 4
      src/network/AhoyWifiEsp8266.h
  16. 91
      src/platformio.ini
  17. 10
      src/plugins/Display/Display.h
  18. 84
      src/plugins/Display/Display_ePaper.cpp
  19. 8
      src/plugins/Display/Display_ePaper.h
  20. 169
      src/web/RestApi.h
  21. 4
      src/web/html/api.js
  22. 55
      src/web/html/setup.html
  23. 13
      src/web/html/style.css
  24. 113
      src/web/html/system.html
  25. 13
      src/web/html/wizard.html
  26. 145
      src/web/lang.json
  27. 22
      src/web/web.h

6
.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:

2
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:

22
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

8
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");

16
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

7
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;

23
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<bool>(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<uint16_t>(obj, F("prot_mask"), &mCfg.sys.protectionMask);

2
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;

3
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

94
src/network/AhoyEthernet.h

@ -12,11 +12,20 @@
#include <ETH.h>
#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*/

10
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);
}

11
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;

9
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;
}

35
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 <functional>
#include <AsyncUDP.h>
#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__*/

4
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;
}

91
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

10
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;
}

84
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, GxEPD2_150_BN::HEIGHT>(GxEPD2_150_BN(&hal));
#else
_display = new GxEPD2_BW<GxEPD2_150_BN, GxEPD2_150_BN::HEIGHT>(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, GxEPD2_150_BN::HEIGHT>(GxEPD2_150_BN(&hal));
#else
_display = new GxEPD2_BW<GxEPD2_150_BN, GxEPD2_150_BN::HEIGHT>(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

8
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

169
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<const char*>());
snprintf(mConfig->sys.stationPwd, PWD_LEN, "%s", jsonIn[F("pwd")].as<const char*>());
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<bool>();
mConfig->sys.eth.pinCs = jsonIn[F("cs")].as<uint8_t>();
@ -1117,7 +1176,7 @@ class RestApi {
mConfig->sys.eth.pinRst = jsonIn[F("reset")].as<uint8_t>();
mApp->saveSettings(true);
}
#endif /* !defined(ETHERNET */
#endif
else if(F("save_iv") == jsonIn[F("cmd")]) {
Inverter<> *iv;

4
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) {

55
src/web/html/setup.html

@ -56,8 +56,6 @@
<div class="col-12 col-sm-3 my-2">{#AP_PWD}</div>
<div class="col-12 col-sm-9"><input type="text" name="ap_pwd" minlength="8" /></div>
</div>
<!--IF_ETHERNET-->
<!--ELSE-->
<div class="row mb-2 mb-sm-3">
<div class="col-12 col-sm-3 my-2">SSID</div>
<div class="col-12 col-sm-9">
@ -73,7 +71,6 @@
<div class="col-12 col-sm-3 my-2">{#PASSWORD}</div>
<div class="col-12 col-sm-9"><input type="password" name="pwd" value="{PWD}"/></div>
</div>
<!--ENDIF_ETHERNET-->
</fieldset>
<fieldset class="mb-4">
<legend class="des">{#STATIC_IP}</legend>
@ -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];

13
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);
}

113
src/web/html/system.html

@ -8,7 +8,7 @@
{#HTML_NAV}
<div id="wrapper">
<div id="content">
<div id="info" class="col-sm-12 col-md-6 mt-3"></div>
<div id="info" class="col-sm-12 col-md-10 mt-3"></div>
<div id="html" class="mt-3 mb-3"></div>
</div>
</div>
@ -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;
}

13
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*/
}
</script>

145
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&auml;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&ouml;&szlig;e"
},
{
"token": "MAX_FREE_BLOCK",
"en": "max free block",
"de": "maximale freie Blockgr&ouml;&szlig;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"
}
]
},

22
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") != "")

Loading…
Cancel
Save