Browse Source

Merge branch 'lumapu:development03' into development03

pull/1541/head
geronet1 9 months ago
committed by GitHub
parent
commit
5ff2984afd
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 6
      .github/ISSUE_TEMPLATE/report.yaml
  2. 1
      .gitignore
  3. 2
      scripts/applyPatches.py
  4. 11
      scripts/convertHtml.py
  5. 2
      scripts/htmlPreprocessorDefines.py
  6. 2
      src/.gitignore
  7. 32
      src/CHANGES.md
  8. 67
      src/app.cpp
  9. 29
      src/app.h
  10. 5
      src/appInterface.h
  11. 2
      src/config/config.h
  12. 15
      src/config/settings.h
  13. 62
      src/defines.h
  14. 71
      src/hm/NrfRadio.h
  15. 2
      src/hm/Radio.h
  16. 35
      src/hm/hmDefines.h
  17. 2
      src/hm/hmInverter.h
  18. 10
      src/hms/CmtRadio.h
  19. 8
      src/hms/cmt2300a.h
  20. 20
      src/network/AhoyNetwork.h
  21. 11
      src/network/AhoyWifiAp.h
  22. 22
      src/network/AhoyWifiEsp32.h
  23. 6
      src/network/AhoyWifiEsp8266.h
  24. 35
      src/platformio.ini
  25. 10
      src/plugins/Display/Display.h
  26. 2
      src/plugins/Display/Display_ePaper.cpp
  27. 11
      src/publisher/pubMqtt.h
  28. 2
      src/publisher/pubMqttIvData.h
  29. 8
      src/utils/improv.h
  30. 24
      src/web/RestApi.h
  31. 4
      src/web/html/history.html
  32. 50
      src/web/html/setup.html
  33. 27
      src/web/html/wizard.html
  34. 24
      src/web/lang.json
  35. 11
      src/web/web.h

6
.github/ISSUE_TEMPLATE/report.yaml

@ -12,7 +12,7 @@ body:
Wir lesen auch gerne Deutsch, bitte fülle die u.a. Fragen aus damit wir Dir bestmöglich helfen können Danke! Wir lesen auch gerne Deutsch, bitte fülle die u.a. Fragen aus damit wir Dir bestmöglich helfen können Danke!
Bitte unser FAQ als Hilfestellung prüfen: https://ahoydtu.de/faq Bitte unser FAQ als Hilfestellung prüfen: https://ahoydtu.de/faq
Please read, copy & fill in the template from our Posting Guide lines into your Support Forum post. Please read, then copy & fill in the template from our Posting Guide lines into your Support Forum post.
We do enjoy the english language, but we need a couple of things to best support you in your goal, please fill in all / most of the details given below. Thanks! We do enjoy the english language, but we need a couple of things to best support you in your goal, please fill in all / most of the details given below. Thanks!
Check our FAQ: https://ahoydtu.de/faq Check our FAQ: https://ahoydtu.de/faq
- type: markdown - type: markdown
@ -35,7 +35,7 @@ body:
label: Assembly label: Assembly
description: description:
options: options:
- I did the assebly by myself - I did the assembly by myself
- the DTU was already assembled - the DTU was already assembled
validations: validations:
required: true required: true
@ -84,7 +84,7 @@ body:
label: Connection picture label: Connection picture
description: description:
options: options:
- label: I will attach/upload an Image of my wiring - label: I will attach/upload an image of my wiring
validations: validations:
required: true required: true
- type: markdown - type: markdown

1
.gitignore

@ -15,3 +15,4 @@ src/web/html/tmp/*
src/output.map src/output.map
/.venv /.venv
/scripts/__pycache__/htmlPreprocessorDefines.cpython-311.pyc

2
scripts/applyPatches.py

@ -31,5 +31,5 @@ applyPatch("ESPAsyncWebServer-esphome", "../patches/AsyncWeb_Prometheus.patch")
if env['PIOENV'][:13] == "opendtufusion": if env['PIOENV'][:13] == "opendtufusion":
applyPatch("GxEPD2", "../patches/GxEPD2_SW_SPI.patch") applyPatch("GxEPD2", "../patches/GxEPD2_SW_SPI.patch")
if (env['PIOENV'][:13] == "opendtufusion"): # or (env['PIOENV'][:13] == "esp32-wroom32"): if (env['PIOENV'][:13] == "opendtufusion") or (env['PIOENV'][:5] == "esp32"):
applyPatch("RF24", "../patches/RF24_Hal.patch") applyPatch("RF24", "../patches/RF24_Hal.patch")

11
scripts/convertHtml.py

@ -27,11 +27,22 @@ def getFlagsOfEnv(env):
elif len(flags[i]) > 0: elif len(flags[i]) > 0:
build_flags = build_flags + [flags[i]] build_flags = build_flags + [flags[i]]
def parseDefinesH():
global build_flags
pattern = r'^\s*#\s*define\s+(\w+)'
with open("defines.h", "r") as f:
for line in f:
match = re.match(pattern, line)
if match:
build_flags += [match.group(1)]
def get_build_flags(): def get_build_flags():
getFlagsOfEnv("env:" + env['PIOENV']) getFlagsOfEnv("env:" + env['PIOENV'])
config = configparser.ConfigParser() config = configparser.ConfigParser()
config.read('platformio.ini') config.read('platformio.ini')
parseDefinesH()
# translate board # translate board
board = config["env:" + env['PIOENV']]['board'] board = config["env:" + env['PIOENV']]['board']

2
scripts/htmlPreprocessorDefines.py

@ -35,6 +35,6 @@ def check(inp, lst, pattern):
return out return out
def conv(inp, lst): def conv(inp, lst):
print(lst) #print(lst)
out = check(inp, lst, r'\/\*(?:IF_|ELS|ENDIF_)([A-Z0-9\-_]+)?\*\/') out = check(inp, lst, r'\/\*(?:IF_|ELS|ENDIF_)([A-Z0-9\-_]+)?\*\/')
return check(out, lst, r'\<\!\-\-(?:IF_|ELS|ENDIF_)([A-Z0-9\-_]+)?\-\-\>') return check(out, lst, r'\<\!\-\-(?:IF_|ELS|ENDIF_)([A-Z0-9\-_]+)?\-\-\>')

2
src/.gitignore

@ -3,3 +3,5 @@
.vscode/c_cpp_properties.json .vscode/c_cpp_properties.json
.vscode/launch.json .vscode/launch.json
.vscode/ipch .vscode/ipch
scripts/__pycache__/*
*.pyc

32
src/CHANGES.md

@ -1,5 +1,37 @@
# Development Changes # Development Changes
## 0.8.107 - 2024-04-08
* fix boot loop on `reboot on midnight` feature #1542, #1599, #1566, #1571
* fix German translation #1569
* improved `Wizard`
## 0.8.106 - 2024-04-05
* fix bootloop with CMT and NRF on ESP32 #1566 #1562
* possible fix of #1553
* change MqTT return value of power limit acknowledge from `boolean` to `float`. The value returned is the same as it was set to confirm reception (not the read back value)
## 0.8.105 - 2024-04-05
* cleanup of `defines.h`
* fix compile of esp32-minimal
## 0.8.104 - 2024-04-04
* fix reboot on inverter save (ESP32) #1559
* fix NRF and Ethernet #1506
## 0.8.103 - 2024-04-02
* merge PR: fix: get refresh property from object #1552
* merge PR: fix typos and spelling in Github Issue template #1550
* merge PR: shorten last cmt waiting time #1549
* fix cppcheck warnings
* changed MqTT retained flags of some topics
## 0.8.102 - 2024-04-01
* fix NTP for `opendtufusion` #1542
* fix scan WiFi in AP mode
* fix MDNS #1538
* improved Wizard
* improved MqTT on devcontrol e.g. set power limit
## 0.8.101 - 2024-03-28 ## 0.8.101 - 2024-03-28
* updated converter scripts to include all enabled features again (redundant scan of build flags) #1534 * updated converter scripts to include all enabled features again (redundant scan of build flags) #1534

67
src/app.cpp

@ -45,9 +45,7 @@ void app::setup() {
esp_task_wdt_reset(); esp_task_wdt_reset();
if(mConfig->nrf.enabled) { mNrfRadio.setup(&mConfig->serial.debug, &mConfig->serial.privacyLog, &mConfig->serial.printWholeTrace, &mConfig->nrf);
mNrfRadio.setup(&mConfig->serial.debug, &mConfig->serial.privacyLog, &mConfig->serial.printWholeTrace, mConfig->nrf.pinIrq, mConfig->nrf.pinCe, mConfig->nrf.pinCs, mConfig->nrf.pinSclk, mConfig->nrf.pinMosi, mConfig->nrf.pinMiso);
}
#if defined(ESP32) #if defined(ESP32)
if(mConfig->cmt.enabled) { if(mConfig->cmt.enabled) {
mCmtRadio.setup(&mConfig->serial.debug, &mConfig->serial.privacyLog, &mConfig->serial.printWholeTrace, mConfig->cmt.pinSclk, mConfig->cmt.pinSdio, mConfig->cmt.pinCsb, mConfig->cmt.pinFcsb, mConfig->sys.region); mCmtRadio.setup(&mConfig->serial.debug, &mConfig->serial.privacyLog, &mConfig->serial.printWholeTrace, mConfig->cmt.pinSclk, mConfig->cmt.pinSdio, mConfig->cmt.pinCsb, mConfig->cmt.pinFcsb, mConfig->sys.region);
@ -56,13 +54,12 @@ void app::setup() {
#ifdef ETHERNET #ifdef ETHERNET
delay(1000); delay(1000);
mNetwork = (AhoyNetwork*) new AhoyEthernet(); mNetwork = static_cast<AhoyNetwork*>(new AhoyEthernet());
#else #else
mNetwork = (AhoyNetwork*) new AhoyWifi(); mNetwork = static_cast<AhoyNetwork*>(new AhoyWifi());
#endif // ETHERNET #endif // ETHERNET
mNetwork->setup(mConfig, &mTimestamp, [this](bool gotIp) { this->onNetwork(gotIp); }, [this](bool gotTime) { this->onNtpUpdate(gotTime); }); mNetwork->setup(mConfig, &mTimestamp, [this](bool gotIp) { this->onNetwork(gotIp); }, [this](bool gotTime) { this->onNtpUpdate(gotTime); });
mNetwork->begin(); mNetwork->begin();
everySec(std::bind(&AhoyNetwork::tickNetworkLoop, mNetwork), "net");
esp_task_wdt_reset(); esp_task_wdt_reset();
@ -142,7 +139,6 @@ void app::setup() {
void app::loop(void) { void app::loop(void) {
esp_task_wdt_reset(); esp_task_wdt_reset();
if(mConfig->nrf.enabled)
mNrfRadio.loop(); mNrfRadio.loop();
#if defined(ESP32) #if defined(ESP32)
@ -166,7 +162,7 @@ void app::onNetwork(bool gotIp) {
ah::Scheduler::resetTicker(); ah::Scheduler::resetTicker();
regularTickers(); //reinstall regular tickers regularTickers(); //reinstall regular tickers
every(std::bind(&app::tickSend, this), mConfig->inst.sendInterval, "tSend"); every(std::bind(&app::tickSend, this), mConfig->inst.sendInterval, "tSend");
mMqttReconnect = true; mTickerInstallOnce = true;
mSunrise = 0; // needs to be set to 0, to reinstall sunrise and ivComm tickers! mSunrise = 0; // needs to be set to 0, to reinstall sunrise and ivComm tickers!
once(std::bind(&app::tickNtpUpdate, this), 2, "ntp2"); once(std::bind(&app::tickNtpUpdate, this), 2, "ntp2");
} }
@ -176,6 +172,7 @@ void app::regularTickers(void) {
DPRINTLN(DBG_DEBUG, F("regularTickers")); DPRINTLN(DBG_DEBUG, F("regularTickers"));
everySec(std::bind(&WebType::tickSecond, &mWeb), "webSc"); everySec(std::bind(&WebType::tickSecond, &mWeb), "webSc");
everySec([this]() { mProtection->tickSecond(); }, "prot"); everySec([this]() { mProtection->tickSecond(); }, "prot");
everySec([this]() {mNetwork->tickNetworkLoop(); }, "net");
// Plugins // Plugins
#if defined(PLUGIN_DISPLAY) #if defined(PLUGIN_DISPLAY)
@ -203,40 +200,37 @@ void app::onNtpUpdate(bool gotTime) {
mCalculatedTimezoneOffset = (int8_t)((mConfig->sun.lon >= 0 ? mConfig->sun.lon + 7.5 : mConfig->sun.lon - 7.5) / 15) * 3600; mCalculatedTimezoneOffset = (int8_t)((mConfig->sun.lon >= 0 ? mConfig->sun.lon + 7.5 : mConfig->sun.lon - 7.5) / 15) * 3600;
tickCalcSunrise(); tickCalcSunrise();
} }
}
//----------------------------------------------------------------------------- if (mTickerInstallOnce) {
void app::updateNtp(void) { mTickerInstallOnce = false;
#if defined(ENABLE_MQTT) #if defined(ENABLE_MQTT)
if (mMqttReconnect && mMqttEnabled) { if (mMqttEnabled) {
mMqtt.tickerSecond(); mMqtt.tickerSecond();
everySec(std::bind(&PubMqttType::tickerSecond, &mMqtt), "mqttS"); everySec(std::bind(&PubMqttType::tickerSecond, &mMqtt), "mqttS");
everyMin(std::bind(&PubMqttType::tickerMinute, &mMqtt), "mqttM"); everyMin(std::bind(&PubMqttType::tickerMinute, &mMqtt), "mqttM");
} }
#endif /*ENABLE_MQTT*/ #endif /*ENABLE_MQTT*/
// only install schedulers once even if NTP wasn't successful in first loop
if (mMqttReconnect) { // @TODO: mMqttReconnect is variable which scope has changed
if (mConfig->inst.rstValsNotAvail) if (mConfig->inst.rstValsNotAvail)
everyMin(std::bind(&app::tickMinute, this), "tMin"); everyMin(std::bind(&app::tickMinute, this), "tMin");
if(mNtpReceived) {
uint32_t localTime = gTimezone.toLocal(mTimestamp); uint32_t localTime = gTimezone.toLocal(mTimestamp);
uint32_t midTrig = gTimezone.toUTC(localTime - (localTime % 86400) + 86400); // next midnight local time uint32_t midTrig = gTimezone.toUTC(localTime - (localTime % 86400) + 86400); // next midnight local time
onceAt(std::bind(&app::tickMidnight, this), midTrig, "midNi"); onceAt(std::bind(&app::tickMidnight, this), midTrig, "midNi");
if (mConfig->sys.schedReboot) { if (mConfig->sys.schedReboot) {
uint32_t rebootTrig = gTimezone.toUTC(localTime - (localTime % 86400) + 86410); // reboot 10 secs after midnght uint32_t rebootTrig = gTimezone.toUTC(localTime - (localTime % 86400) + 86410); // reboot 10 secs after midnght
if (rebootTrig <= mTimestamp) { //necessary for times other than midnight to prevent reboot loop
rebootTrig += 86400;
}
onceAt(std::bind(&app::tickReboot, this), rebootTrig, "midRe"); onceAt(std::bind(&app::tickReboot, this), rebootTrig, "midRe");
} }
} }
}
}
//-----------------------------------------------------------------------------
void app::updateNtp(void) {
if(mNtpReceived) if(mNtpReceived)
onNtpUpdate(true); onNtpUpdate(true);
mMqttReconnect = false;
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -252,8 +246,6 @@ void app::tickNtpUpdate(void) {
updateNtp(); updateNtp();
mMqttReconnect = false;
once(std::bind(&app::tickNtpUpdate, this), nxtTrig, "ntp"); once(std::bind(&app::tickNtpUpdate, this), nxtTrig, "ntp");
} }
@ -403,19 +395,35 @@ void app::tickSend(void) {
for (uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { for (uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) {
Inverter<> *iv = mSys.getInverterByPos(i); Inverter<> *iv = mSys.getInverterByPos(i);
if(!sendIv(iv))
notAvail = false;
}
if(mAllIvNotAvail != notAvail)
once(std::bind(&app::notAvailChanged, this), 1, "avail");
mAllIvNotAvail = notAvail;
updateLed();
}
//-----------------------------------------------------------------------------
bool app::sendIv(Inverter<> *iv) {
if(NULL == iv) if(NULL == iv)
continue; return true;
if(!iv->config->enabled)
return true;
if(iv->config->enabled) {
if(!iv->commEnabled) { if(!iv->commEnabled) {
DPRINT_IVID(DBG_INFO, iv->id); DPRINT_IVID(DBG_INFO, iv->id);
DBGPRINTLN(F("no communication to the inverter (night time)")); DBGPRINTLN(F("no communication to the inverter (night time)"));
continue; return true;
} }
if(!iv->radio->isChipConnected()) if(!iv->radio->isChipConnected())
continue; return true;
bool notAvail = true;
if(InverterStatus::OFF != iv->status) if(InverterStatus::OFF != iv->status)
notAvail = false; notAvail = false;
@ -425,14 +433,8 @@ void app::tickSend(void) {
else else
mCommunication.add(iv, cmd); mCommunication.add(iv, cmd);
}); });
}
}
if(mAllIvNotAvail != notAvail) return notAvail;
once(std::bind(&app::notAvailChanged, this), 1, "avail");
mAllIvNotAvail = notAvail;
updateLed();
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -541,6 +543,7 @@ void app::resetSystem(void) {
mNetworkConnected = false; mNetworkConnected = false;
mNtpReceived = false; mNtpReceived = false;
mTickerInstallOnce = false;
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------

29
src/app.h

@ -17,9 +17,9 @@
#include "defines.h" #include "defines.h"
#include "appInterface.h" #include "appInterface.h"
#include "hm/hmSystem.h" #include "hm/hmSystem.h"
#include "hm/hmRadio.h" #include "hm/NrfRadio.h"
#if defined(ESP32) #if defined(ESP32)
#include "hms/hmsRadio.h" #include "hms/CmtRadio.h"
#endif #endif
#if defined(ENABLE_MQTT) #if defined(ENABLE_MQTT)
#include "publisher/pubMqtt.h" #include "publisher/pubMqtt.h"
@ -167,10 +167,6 @@ class app : public IApp, public ah::Scheduler {
} }
#if !defined(ETHERNET) #if !defined(ETHERNET)
void scanAvailNetworks() override {
mNetwork->scanAvailNetworks();
}
bool getAvailNetworks(JsonObject obj) override { bool getAvailNetworks(JsonObject obj) override {
return mNetwork->getAvailNetworks(obj); return mNetwork->getAvailNetworks(obj);
} }
@ -179,10 +175,6 @@ class app : public IApp, public ah::Scheduler {
mNetwork->begin(); mNetwork->begin();
} }
/*void setStopApAllowedMode(bool allowed) override {
mWifi.setStopApAllowedMode(allowed);
}*/
bool getWasInCh12to14(void) const override { bool getWasInCh12to14(void) const override {
#if defined(ESP8266) #if defined(ESP8266)
return mNetwork->getWasInCh12to14(); return mNetwork->getWasInCh12to14();
@ -196,6 +188,10 @@ class app : public IApp, public ah::Scheduler {
return mNetwork->getIp(); return mNetwork->getIp();
} }
bool isApActive(void) override {
return mNetwork->isApActive();
}
void setRebootFlag() override { void setRebootFlag() override {
once(std::bind(&app::tickReboot, this), 3, "rboot"); once(std::bind(&app::tickReboot, this), 3, "rboot");
} }
@ -394,8 +390,10 @@ class app : public IApp, public ah::Scheduler {
bool mNtpReceived = false; bool mNtpReceived = false;
void updateNtp(void); void updateNtp(void);
void triggerTickSend() override { void triggerTickSend(uint8_t id) override {
once(std::bind(&app::tickSend, this), 0, "tSend"); once([this, id]() {
sendIv(mSys.getInverterByPos(id));
}, 0, "devct");
} }
void tickCalcSunrise(void); void tickCalcSunrise(void);
@ -404,18 +402,19 @@ class app : public IApp, public ah::Scheduler {
void tickSunrise(void); void tickSunrise(void);
void tickComm(void); void tickComm(void);
void tickSend(void); void tickSend(void);
bool sendIv(Inverter<> *iv);
void tickMinute(void); void tickMinute(void);
void tickZeroValues(void); void tickZeroValues(void);
void tickMidnight(void); void tickMidnight(void);
void notAvailChanged(void); void notAvailChanged(void);
HmSystemType mSys; HmSystemType mSys;
HmRadio<> mNrfRadio; NrfRadio<> mNrfRadio;
Communication mCommunication; Communication mCommunication;
bool mShowRebootRequest = false; bool mShowRebootRequest = false;
AhoyNetwork *mNetwork; AhoyNetwork *mNetwork = nullptr;
WebType mWeb; WebType mWeb;
RestApiType mApi; RestApiType mApi;
Protection *mProtection = nullptr; Protection *mProtection = nullptr;
@ -448,7 +447,7 @@ class app : public IApp, public ah::Scheduler {
#if defined(ENABLE_MQTT) #if defined(ENABLE_MQTT)
PubMqttType mMqtt; PubMqttType mMqtt;
#endif /*ENABLE_MQTT*/ #endif /*ENABLE_MQTT*/
bool mMqttReconnect = false; bool mTickerInstallOnce = false;
bool mMqttEnabled = false; bool mMqttEnabled = false;
// sun // sun

5
src/appInterface.h

@ -26,13 +26,12 @@ class IApp {
virtual const char *getVersionModules() = 0; virtual const char *getVersionModules() = 0;
#if !defined(ETHERNET) #if !defined(ETHERNET)
virtual void scanAvailNetworks() = 0;
virtual bool getAvailNetworks(JsonObject obj) = 0; virtual bool getAvailNetworks(JsonObject obj) = 0;
virtual void setupStation(void) = 0; virtual void setupStation(void) = 0;
//virtual void setStopApAllowedMode(bool allowed) = 0;
virtual bool getWasInCh12to14(void) const = 0; virtual bool getWasInCh12to14(void) const = 0;
#endif /* defined(ETHERNET) */ #endif /* defined(ETHERNET) */
virtual String getIp(void) = 0; virtual String getIp(void) = 0;
virtual bool isApActive(void) = 0;
virtual uint32_t getUptime() = 0; virtual uint32_t getUptime() = 0;
virtual uint32_t getTimestamp() = 0; virtual uint32_t getTimestamp() = 0;
@ -44,7 +43,7 @@ class IApp {
virtual void getSchedulerInfo(uint8_t *max) = 0; virtual void getSchedulerInfo(uint8_t *max) = 0;
virtual void getSchedulerNames() = 0; virtual void getSchedulerNames() = 0;
virtual void triggerTickSend() = 0; virtual void triggerTickSend(uint8_t id) = 0;
virtual bool getRebootRequestState() = 0; virtual bool getRebootRequestState() = 0;
virtual bool getSettingsValid() = 0; virtual bool getSettingsValid() = 0;

2
src/config/config.h

@ -145,7 +145,7 @@
#ifndef DEF_MOTION_SENSOR_PIN #ifndef DEF_MOTION_SENSOR_PIN
#define DEF_MOTION_SENSOR_PIN DEF_PIN_OFF #define DEF_MOTION_SENSOR_PIN DEF_PIN_OFF
#endif #endif
#else #else // ESP8266
#ifndef DEF_NRF_CS_PIN #ifndef DEF_NRF_CS_PIN
#define DEF_NRF_CS_PIN 15 #define DEF_NRF_CS_PIN 15
#endif #endif

15
src/config/settings.h

@ -33,7 +33,6 @@
#define CONFIG_VERSION 11 #define CONFIG_VERSION 11
#define PROT_MASK_INDEX 0x0001 #define PROT_MASK_INDEX 0x0001
#define PROT_MASK_LIVE 0x0002 #define PROT_MASK_LIVE 0x0002
#define PROT_MASK_SERIAL 0x0004 #define PROT_MASK_SERIAL 0x0004
@ -55,6 +54,20 @@
#define DEF_PROT_MQTT 0x0000 #define DEF_PROT_MQTT 0x0000
#define SSID_LEN 32
#define PWD_LEN 64
#define DEVNAME_LEN 16
#define NTP_ADDR_LEN 32 // DNS Name
#define MQTT_ADDR_LEN 64 // DNS Name
#define MQTT_CLIENTID_LEN 22 // number of chars is limited to 23 up to v3.1 of MQTT
#define MQTT_USER_LEN 65 // there is another byte necessary for \0
#define MQTT_PWD_LEN 65
#define MQTT_TOPIC_LEN 65
#define MQTT_MAX_PACKET_SIZE 384
typedef struct { typedef struct {
uint8_t ip[4]; // ip address uint8_t ip[4]; // ip address
uint8_t mask[4]; // sub mask uint8_t mask[4]; // sub mask

62
src/defines.h

@ -13,7 +13,7 @@
//------------------------------------- //-------------------------------------
#define VERSION_MAJOR 0 #define VERSION_MAJOR 0
#define VERSION_MINOR 8 #define VERSION_MINOR 8
#define VERSION_PATCH 101 #define VERSION_PATCH 107
//------------------------------------- //-------------------------------------
typedef struct { typedef struct {
uint8_t ch; uint8_t ch;
@ -23,41 +23,6 @@ typedef struct {
uint16_t millis; uint16_t millis;
} packet_t; } packet_t;
typedef enum {
InverterDevInform_Simple = 0, // 0x00
InverterDevInform_All = 1, // 0x01
GridOnProFilePara = 2, // 0x02
HardWareConfig = 3, // 0x03
SimpleCalibrationPara = 4, // 0x04
SystemConfigPara = 5, // 0x05
RealTimeRunData_Debug = 11, // 0x0b
RealTimeRunData_Reality = 12, // 0x0c
RealTimeRunData_A_Phase = 13, // 0x0d
RealTimeRunData_B_Phase = 14, // 0x0e
RealTimeRunData_C_Phase = 15, // 0x0f
AlarmData = 17, // 0x11, Alarm data - all unsent alarms
AlarmUpdate = 18, // 0x12, Alarm data - all pending alarms
RecordData = 19, // 0x13
InternalData = 20, // 0x14
GetLossRate = 21, // 0x15
GetSelfCheckState = 30, // 0x1e
InitDataState = 0xff
} InfoCmdType;
typedef enum {
TurnOn = 0, // 0x00
TurnOff = 1, // 0x01
Restart = 2, // 0x02
Lock = 3, // 0x03
Unlock = 4, // 0x04
ActivePowerContr = 11, // 0x0b
ReactivePowerContr = 12, // 0x0c
PFSet = 13, // 0x0d
CleanState_LockAndAlarm = 20, // 0x14
SelfInspection = 40, // 0x28, self-inspection of grid-connected protection files
Init = 0xff
} DevControlCmdType;
typedef enum { typedef enum {
AbsolutNonPersistent = 0UL, // 0x0000 AbsolutNonPersistent = 0UL, // 0x0000
RelativNonPersistent = 1UL, // 0x0001 RelativNonPersistent = 1UL, // 0x0001
@ -70,13 +35,6 @@ union serial_u {
uint8_t b[8]; uint8_t b[8];
}; };
#define MIN_SERIAL_INTERVAL 2 // 5
#define MIN_SEND_INTERVAL 15
#define MIN_MQTT_INTERVAL 60
enum {MQTT_STATUS_OFFLINE = 0, MQTT_STATUS_PARTIAL, MQTT_STATUS_ONLINE};
enum { enum {
DISP_TYPE_T0_NONE = 0, DISP_TYPE_T0_NONE = 0,
DISP_TYPE_T1_SSD1306_128X64 = 1, DISP_TYPE_T1_SSD1306_128X64 = 1,
@ -88,24 +46,6 @@ enum {
DISP_TYPE_T10_EPAPER = 10 DISP_TYPE_T10_EPAPER = 10
}; };
//-------------------------------------
// EEPROM
//-------------------------------------
#define SSID_LEN 32
#define PWD_LEN 64
#define DEVNAME_LEN 16
#define NTP_ADDR_LEN 32 // DNS Name
#define MQTT_ADDR_LEN 64 // DNS Name
#define MQTT_CLIENTID_LEN 22 // number of chars is limited to 23 up to v3.1 of MQTT
#define MQTT_USER_LEN 65 // there is another byte necessary for \0
#define MQTT_PWD_LEN 65
#define MQTT_TOPIC_LEN 65
#define MQTT_MAX_PACKET_SIZE 384
typedef struct { typedef struct {
uint32_t rxFail; uint32_t rxFail;
uint32_t rxFailNoAnswer; uint32_t rxFailNoAnswer;

71
src/hm/hmRadio.h → src/hm/NrfRadio.h

@ -8,9 +8,10 @@
#include <RF24.h> #include <RF24.h>
#include "SPI.h" #include "SPI.h"
#include "radio.h" #include "Radio.h"
#include "../config/config.h" #include "../config/config.h"
#if defined(CONFIG_IDF_TARGET_ESP32S3) && defined(SPI_HAL) #include "../config/settings.h"
#if defined(SPI_HAL)
#include "nrfHal.h" #include "nrfHal.h"
#endif #endif
@ -28,24 +29,30 @@ const char* const rf24AmpPowerNames[] = {"MIN", "LOW", "HIGH", "MAX"};
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// HM Radio class // HM Radio class
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
template <uint8_t IRQ_PIN = DEF_NRF_IRQ_PIN, uint8_t CE_PIN = DEF_NRF_CE_PIN, uint8_t CS_PIN = DEF_NRF_CS_PIN, uint8_t AMP_PWR = RF24_PA_LOW, uint8_t SCLK_PIN = DEF_NRF_SCLK_PIN, uint8_t MOSI_PIN = DEF_NRF_MOSI_PIN, uint8_t MISO_PIN = DEF_NRF_MISO_PIN, uint32_t DTU_SN = 0x81001765> template <uint32_t DTU_SN = 0x81001765>
class HmRadio : public Radio { class NrfRadio : public Radio {
public: public:
HmRadio() { NrfRadio() {
mDtuSn = DTU_SN; mDtuSn = DTU_SN;
mIrqRcvd = false; mIrqRcvd = false;
#if defined(CONFIG_IDF_TARGET_ESP32S3) && defined(SPI_HAL) #if defined(SPI_HAL)
//mNrf24.reset(new RF24()); //mNrf24.reset(new RF24());
#else #else
mNrf24.reset(new RF24(CE_PIN, CS_PIN, SPI_SPEED)); mNrf24.reset(new RF24(DEF_NRF_CE_PIN, DEF_NRF_CS_PIN, SPI_SPEED));
#endif #endif
} }
~HmRadio() {} ~NrfRadio() {}
void setup(bool *serialDebug, bool *privacyMode, bool *printWholeTrace, uint8_t irq = IRQ_PIN, uint8_t ce = CE_PIN, uint8_t cs = CS_PIN, uint8_t sclk = SCLK_PIN, uint8_t mosi = MOSI_PIN, uint8_t miso = MISO_PIN) { void setup(bool *serialDebug, bool *privacyMode, bool *printWholeTrace, cfgNrf24_t *cfg) {
DPRINTLN(DBG_VERBOSE, F("hmRadio.h:setup")); DPRINTLN(DBG_VERBOSE, F("NrfRadio::setup"));
pinMode(irq, INPUT_PULLUP); mCfg = cfg;
//uint8_t irq = IRQ_PIN, uint8_t ce = CE_PIN, uint8_t cs = CS_PIN, uint8_t sclk = SCLK_PIN, uint8_t mosi = MOSI_PIN, uint8_t miso = MISO_PIN
if(!mCfg->enabled)
return;
pinMode(mCfg->pinIrq, INPUT_PULLUP);
mSerialDebug = serialDebug; mSerialDebug = serialDebug;
mPrivacyMode = privacyMode; mPrivacyMode = privacyMode;
@ -55,8 +62,8 @@ class HmRadio : public Radio {
mDtuRadioId = ((uint64_t)(((mDtuSn >> 24) & 0xFF) | ((mDtuSn >> 8) & 0xFF00) | ((mDtuSn << 8) & 0xFF0000) | ((mDtuSn << 24) & 0xFF000000)) << 8) | 0x01; mDtuRadioId = ((uint64_t)(((mDtuSn >> 24) & 0xFF) | ((mDtuSn >> 8) & 0xFF00) | ((mDtuSn << 8) & 0xFF0000) | ((mDtuSn << 24) & 0xFF000000)) << 8) | 0x01;
#ifdef ESP32 #ifdef ESP32
#if defined(CONFIG_IDF_TARGET_ESP32S3) && defined(SPI_HAL) #if defined(SPI_HAL)
mNrfHal.init(mosi, miso, sclk, cs, ce, SPI_SPEED); mNrfHal.init(mCfg->pinMosi, mCfg->pinMiso, mCfg->pinSclk, mCfg->pinCs, mCfg->pinCe, SPI_SPEED);
mNrf24.reset(new RF24(&mNrfHal)); mNrf24.reset(new RF24(&mNrfHal));
#else #else
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 #if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
@ -64,7 +71,7 @@ class HmRadio : public Radio {
#else #else
mSpi.reset(new SPIClass(VSPI)); mSpi.reset(new SPIClass(VSPI));
#endif #endif
mSpi->begin(sclk, miso, mosi, cs); mSpi->begin(mCfg->pinSclk, mCfg->pinMiso, mCfg->pinMosi, mCfg->pinCs);
#endif #endif
#else #else
//the old ESP82xx cannot freely place their SPI pins //the old ESP82xx cannot freely place their SPI pins
@ -72,10 +79,10 @@ class HmRadio : public Radio {
mSpi->begin(); mSpi->begin();
#endif #endif
#if defined(CONFIG_IDF_TARGET_ESP32S3) && defined(SPI_HAL) #if defined(SPI_HAL)
mNrf24->begin(); mNrf24->begin();
#else #else
mNrf24->begin(mSpi.get(), ce, cs); mNrf24->begin(mSpi.get(), mCfg->pinCe, mCfg->pinCs);
#endif #endif
mNrf24->setRetries(3, 15); // wait 3*250 = 750us, 16 * 250us -> 4000us = 4ms mNrf24->setRetries(3, 15); // wait 3*250 = 750us, 16 * 250us -> 4000us = 4ms
@ -99,21 +106,24 @@ class HmRadio : public Radio {
} }
// returns true if communication is active // returns true if communication is active
bool loop(void) override { void loop(void) {
if(!mCfg->enabled)
return;
if (!mIrqRcvd && !mNRFisInRX) if (!mIrqRcvd && !mNRFisInRX)
return false; // first quick check => nothing to do at all here return; // first quick check => nothing to do at all here
if(NULL == mLastIv) // prevent reading on NULL object! if(NULL == mLastIv) // prevent reading on NULL object!
return false; return;
if(!mIrqRcvd) { // no news from nRF, check timers if(!mIrqRcvd) { // no news from nRF, check timers
if ((millis() - mTimeslotStart) < innerLoopTimeout) if ((millis() - mTimeslotStart) < innerLoopTimeout)
return true; // nothing to do, still waiting return; // nothing to do, still waiting
if (mRadioWaitTime.isTimeout()) { // timeout reached! if (mRadioWaitTime.isTimeout()) { // timeout reached!
mNRFisInRX = false; mNRFisInRX = false;
rx_ready = false; rx_ready = false;
return false; return;
} }
// otherwise switch to next RX channel // otherwise switch to next RX channel
@ -132,7 +142,7 @@ class HmRadio : public Radio {
mNrf24->setChannel(mRfChLst[tempRxChIdx]); mNrf24->setChannel(mRfChLst[tempRxChIdx]);
isRxInit = false; isRxInit = false;
return true; // communicating, but changed RX channel return; // communicating, but changed RX channel
} else { } else {
// here we got news from the nRF // here we got news from the nRF
mIrqRcvd = false; mIrqRcvd = false;
@ -145,7 +155,7 @@ class HmRadio : public Radio {
if(mNRFisInRX) { if(mNRFisInRX) {
DPRINTLN(DBG_WARN, F("unexpected tx irq!")); DPRINTLN(DBG_WARN, F("unexpected tx irq!"));
return false; return;
} }
mNRFisInRX = true; mNRFisInRX = true;
@ -181,18 +191,23 @@ class HmRadio : public Radio {
} }
} }
rx_ready = false; // reset rx_ready = false; // reset
return mNRFisInRX; return;
} }
} }
return false; return;
} }
bool isChipConnected(void) const override { bool isChipConnected(void) const override {
if(!mCfg->enabled)
return false;
return mNrf24->isChipConnected(); return mNrf24->isChipConnected();
} }
void sendControlPacket(Inverter<> *iv, uint8_t cmd, uint16_t *data, bool isRetransmit) override { void sendControlPacket(Inverter<> *iv, uint8_t cmd, uint16_t *data, bool isRetransmit) override {
if(!mCfg->enabled)
return;
DPRINT_IVID(DBG_INFO, iv->id); DPRINT_IVID(DBG_INFO, iv->id);
DBGPRINT(F("sendControlPacket cmd: ")); DBGPRINT(F("sendControlPacket cmd: "));
DBGHEXLN(cmd); DBGHEXLN(cmd);
@ -279,12 +294,13 @@ class HmRadio : public Radio {
} }
uint8_t getDataRate(void) const { uint8_t getDataRate(void) const {
if(!mNrf24->isChipConnected()) if(!isChipConnected())
return 3; // unknown return 3; // unknown
return mNrf24->getDataRate(); return mNrf24->getDataRate();
} }
bool isPVariant(void) const { bool isPVariant(void) const {
if(!isChipConnected())
return mNrf24->isPVariant(); return mNrf24->isPVariant();
} }
@ -413,6 +429,7 @@ class HmRadio : public Radio {
} }
uint64_t mDtuRadioId = 0ULL; uint64_t mDtuRadioId = 0ULL;
cfgNrf24_t *mCfg = nullptr;
const uint8_t mRfChLst[RF_CHANNELS] = {03, 23, 40, 61, 75}; // channel List:2403, 2423, 2440, 2461, 2475MHz const uint8_t mRfChLst[RF_CHANNELS] = {03, 23, 40, 61, 75}; // channel List:2403, 2423, 2440, 2461, 2475MHz
uint8_t mTxChIdx = 0; uint8_t mTxChIdx = 0;
uint8_t mRxChIdx = 0; uint8_t mRxChIdx = 0;
@ -432,7 +449,7 @@ class HmRadio : public Radio {
std::unique_ptr<SPIClass> mSpi; std::unique_ptr<SPIClass> mSpi;
std::unique_ptr<RF24> mNrf24; std::unique_ptr<RF24> mNrf24;
#if defined(CONFIG_IDF_TARGET_ESP32S3) && defined(SPI_HAL) #if defined(SPI_HAL)
nrfHal mNrfHal; nrfHal mNrfHal;
#endif #endif
Inverter<> *mLastIv = NULL; Inverter<> *mLastIv = NULL;

2
src/hm/radio.h → src/hm/Radio.h

@ -33,7 +33,7 @@ class Radio {
virtual uint16_t getBaseFreqMhz() { return 0; } virtual uint16_t getBaseFreqMhz() { return 0; }
virtual uint16_t getBootFreqMhz() { return 0; } virtual uint16_t getBootFreqMhz() { return 0; }
virtual std::pair<uint16_t,uint16_t> getFreqRangeMhz(void) { return std::make_pair(0, 0); } virtual std::pair<uint16_t,uint16_t> getFreqRangeMhz(void) { return std::make_pair(0, 0); }
virtual bool loop(void) = 0; virtual void loop(void) = 0;
Radio() : mTxBuf{} {} Radio() : mTxBuf{} {}

35
src/hm/hmDefines.h

@ -9,6 +9,41 @@
#include "../utils/dbg.h" #include "../utils/dbg.h"
#include <cstdint> #include <cstdint>
typedef enum {
InverterDevInform_Simple = 0, // 0x00
InverterDevInform_All = 1, // 0x01
GridOnProFilePara = 2, // 0x02
HardWareConfig = 3, // 0x03
SimpleCalibrationPara = 4, // 0x04
SystemConfigPara = 5, // 0x05
RealTimeRunData_Debug = 11, // 0x0b
RealTimeRunData_Reality = 12, // 0x0c
RealTimeRunData_A_Phase = 13, // 0x0d
RealTimeRunData_B_Phase = 14, // 0x0e
RealTimeRunData_C_Phase = 15, // 0x0f
AlarmData = 17, // 0x11, Alarm data - all unsent alarms
AlarmUpdate = 18, // 0x12, Alarm data - all pending alarms
RecordData = 19, // 0x13
InternalData = 20, // 0x14
GetLossRate = 21, // 0x15
GetSelfCheckState = 30, // 0x1e
InitDataState = 0xff
} InfoCmdType;
typedef enum {
TurnOn = 0, // 0x00
TurnOff = 1, // 0x01
Restart = 2, // 0x02
Lock = 3, // 0x03
Unlock = 4, // 0x04
ActivePowerContr = 11, // 0x0b
ReactivePowerContr = 12, // 0x0c
PFSet = 13, // 0x0d
CleanState_LockAndAlarm = 20, // 0x14
SelfInspection = 40, // 0x28, self-inspection of grid-connected protection files
Init = 0xff
} DevControlCmdType;
// inverter generations // inverter generations
enum {IV_MI = 0, IV_HM, IV_HMS, IV_HMT, IV_UNKNOWN}; enum {IV_MI = 0, IV_HM, IV_HMS, IV_HMT, IV_UNKNOWN};
const char* const generationNames[] = {"MI", "HM", "HMS", "HMT", "UNKNOWN"}; const char* const generationNames[] = {"MI", "HM", "HMS", "HMT", "UNKNOWN"};

2
src/hm/hmInverter.h

@ -22,7 +22,7 @@
#include <functional> #include <functional>
#include "../config/settings.h" #include "../config/settings.h"
#include "radio.h" #include "Radio.h"
/** /**
* For values which are of interest and not transmitted by the inverter can be * For values which are of interest and not transmitted by the inverter can be
* calculated automatically. * calculated automatically.

10
src/hms/hmsRadio.h → src/hms/CmtRadio.h

@ -7,7 +7,7 @@
#define __HMS_RADIO_H__ #define __HMS_RADIO_H__
#include "cmt2300a.h" #include "cmt2300a.h"
#include "../hm/radio.h" #include "../hm/Radio.h"
//#define CMT_SWITCH_CHANNEL_CYCLE 5 //#define CMT_SWITCH_CHANNEL_CYCLE 5
@ -24,16 +24,16 @@ class CmtRadio : public Radio {
mTxBuf.fill(0); mTxBuf.fill(0);
} }
bool loop() override { void loop() override {
mCmt.loop(); mCmt.loop();
if((!mIrqRcvd) && (!mRqstGetRx)) if((!mIrqRcvd) && (!mRqstGetRx))
return false; return;
getRx(); getRx();
if(CmtStatus::SUCCESS == mCmt.goRx()) { if(CmtStatus::SUCCESS == mCmt.goRx()) {
mIrqRcvd = false; mIrqRcvd = false;
mRqstGetRx = false; mRqstGetRx = false;
} }
return false; return;
} }
bool isChipConnected(void) const override { bool isChipConnected(void) const override {
@ -183,7 +183,7 @@ class CmtRadio : public Radio {
if(p.packet[9] > ALL_FRAMES) { // indicates last frame if(p.packet[9] > ALL_FRAMES) { // indicates last frame
setExpectedFrames(p.packet[9] - ALL_FRAMES); setExpectedFrames(p.packet[9] - ALL_FRAMES);
mRadioWaitTime.startTimeMonitor(DURATION_PAUSE_LASTFR); // let the inverter first get back to rx mode? mRadioWaitTime.startTimeMonitor(2); // let the inverter first get back to rx mode?
} }
} }

8
src/hms/cmt2300a.h

@ -6,7 +6,7 @@
#ifndef __CMT2300A_H__ #ifndef __CMT2300A_H__
#define __CMT2300A_H__ #define __CMT2300A_H__
#if defined(CONFIG_IDF_TARGET_ESP32S3) && defined(SPI_HAL) #if defined(SPI_HAL)
#include "cmtHal.h" #include "cmtHal.h"
#else #else
#include "esp32_3wSpi.h" #include "esp32_3wSpi.h"
@ -248,14 +248,12 @@ class Cmt2300a {
} }
CmtStatus tx(uint8_t buf[], uint8_t len) { CmtStatus tx(uint8_t buf[], uint8_t len) {
if(mTxPending)
return CmtStatus::ERR_TX_PENDING;
if(mInRxMode) { if(mInRxMode) {
mInRxMode = false; mInRxMode = false;
if(!cmtSwitchStatus(CMT2300A_GO_STBY, CMT2300A_STA_STBY)) if(!cmtSwitchStatus(CMT2300A_GO_STBY, CMT2300A_STA_STBY))
return CmtStatus::ERR_SWITCH_STATE; return CmtStatus::ERR_SWITCH_STATE;
} }
mTxPending = false; // safety
mSpi.writeReg(CMT2300A_CUS_INT1_CTL, CMT2300A_INT_SEL_TX_DONE); mSpi.writeReg(CMT2300A_CUS_INT1_CTL, CMT2300A_INT_SEL_TX_DONE);
@ -545,7 +543,7 @@ class Cmt2300a {
} }
private: private:
#if defined(CONFIG_IDF_TARGET_ESP32S3) && defined(SPI_HAL) #if defined(SPI_HAL)
cmtHal mSpi; cmtHal mSpi;
#else #else
esp32_3wSpi mSpi; esp32_3wSpi mSpi;

20
src/network/AhoyNetwork.h

@ -85,21 +85,26 @@ class AhoyNetwork {
return false; return false;
} }
bool isApActive() {
return mAp.isEnabled();
}
#if !defined(ETHERNET) #if !defined(ETHERNET)
void scanAvailNetworks(void) { bool getAvailNetworks(JsonObject obj) {
if(!mScanActive) { if(!mScanActive) {
mScanActive = true; mScanActive = true;
WiFi.scanNetworks(true); //if(NetworkState::GOT_IP != mStatus)
} // WiFi.disconnect();
WiFi.scanNetworks(true, true);
return false;
} }
bool getAvailNetworks(JsonObject obj) {
JsonArray nets = obj.createNestedArray(F("networks"));
int n = WiFi.scanComplete(); int n = WiFi.scanComplete();
if (n < 0) if (WIFI_SCAN_RUNNING == n)
return false; return false;
if(n > 0) { if(n > 0) {
JsonArray nets = obj.createNestedArray(F("networks"));
int sort[n]; int sort[n];
sortRSSI(&sort[0], n); sortRSSI(&sort[0], n);
for (int i = 0; i < n; ++i) { for (int i = 0; i < n; ++i) {
@ -174,7 +179,6 @@ class AhoyNetwork {
private: private:
void sendNTPpacket(void) { void sendNTPpacket(void) {
//DPRINTLN(DBG_VERBOSE, F("wifi::sendNTPpacket"));
uint8_t buf[NTP_PACKET_SIZE]; uint8_t buf[NTP_PACKET_SIZE];
memset(buf, 0, NTP_PACKET_SIZE); memset(buf, 0, NTP_PACKET_SIZE);

11
src/network/AhoyWifiAp.h

@ -22,6 +22,12 @@ class AhoyWifiAp {
void tickLoop() { void tickLoop() {
if(mEnabled) if(mEnabled)
mDns.processNextRequest(); mDns.processNextRequest();
if (WiFi.softAPgetStationNum() != mLast) {
mLast = WiFi.softAPgetStationNum();
if(mLast > 0)
DBGPRINTLN(F("AP client connected"));
}
} }
void enable() { void enable() {
@ -38,6 +44,7 @@ class AhoyWifiAp {
WiFi.softAPConfig(mIp, mIp, IPAddress(255, 255, 255, 0)); WiFi.softAPConfig(mIp, mIp, IPAddress(255, 255, 255, 0));
WiFi.softAP(WIFI_AP_SSID, mCfg->apPwd); WiFi.softAP(WIFI_AP_SSID, mCfg->apPwd);
mDns.setErrorReplyCode(DNSReplyCode::NoError);
mDns.start(53, "*", mIp); mDns.start(53, "*", mIp);
mEnabled = true; mEnabled = true;
@ -48,6 +55,9 @@ class AhoyWifiAp {
if(!mEnabled) if(!mEnabled)
return; return;
if(WiFi.softAPgetStationNum() > 0)
return;
mDns.stop(); mDns.stop();
WiFi.softAPdisconnect(); WiFi.softAPdisconnect();
#if defined(ETHERNET) #if defined(ETHERNET)
@ -68,6 +78,7 @@ class AhoyWifiAp {
DNSServer mDns; DNSServer mDns;
IPAddress mIp; IPAddress mIp;
bool mEnabled = false; bool mEnabled = false;
uint8_t mLast = 0;
}; };
#endif /*__AHOY_WIFI_AP_H__*/ #endif /*__AHOY_WIFI_AP_H__*/

22
src/network/AhoyWifiEsp32.h

@ -28,7 +28,7 @@ class AhoyWifi : public AhoyNetwork {
WiFi.setSortMethod(WIFI_CONNECT_AP_BY_SIGNAL); WiFi.setSortMethod(WIFI_CONNECT_AP_BY_SIGNAL);
WiFi.begin(mConfig->sys.stationSsid, mConfig->sys.stationPwd, WIFI_ALL_CHANNEL_SCAN); WiFi.begin(mConfig->sys.stationSsid, mConfig->sys.stationPwd, WIFI_ALL_CHANNEL_SCAN);
DBGPRINT(F("connect to network '")); Serial.flush(); DBGPRINT(F("connect to network '"));
DBGPRINT(mConfig->sys.stationSsid); DBGPRINT(mConfig->sys.stationSsid);
#endif #endif
} }
@ -43,10 +43,7 @@ class AhoyWifi : public AhoyNetwork {
mConnected = false; mConnected = false;
mOnNetworkCB(false); mOnNetworkCB(false);
mAp.enable(); mAp.enable();
} MDNS.end();
if (WiFi.softAPgetStationNum() > 0) {
DBGPRINTLN(F("AP client connected"));
} }
break; break;
@ -54,11 +51,14 @@ class AhoyWifi : public AhoyNetwork {
break; break;
case NetworkState::GOT_IP: case NetworkState::GOT_IP:
if(!mConnected) { if(mAp.isEnabled())
mAp.disable(); mAp.disable();
if(!mConnected) {
mConnected = true; mConnected = true;
ah::welcome(WiFi.localIP().toString(), F("Station")); ah::welcome(WiFi.localIP().toString(), F("Station"));
MDNS.begin(mConfig->sys.deviceName); MDNS.begin(mConfig->sys.deviceName);
//MDNS.addServiceTxt("http", "tcp", "path", "/");
mOnNetworkCB(true); mOnNetworkCB(true);
} }
break; break;
@ -68,16 +68,6 @@ class AhoyWifi : public AhoyNetwork {
String getIp(void) override { String getIp(void) override {
return WiFi.localIP().toString(); return WiFi.localIP().toString();
} }
private:
void sortRSSI(int *sort, int n) {
for (int i = 0; i < n; i++)
sort[i] = i;
for (int i = 0; i < n; i++)
for (int j = i + 1; j < n; j++)
if (WiFi.RSSI(sort[j]) > WiFi.RSSI(sort[i]))
std::swap(sort[i], sort[j]);
}
}; };
#endif /*ESP32 & !ETHERNET*/ #endif /*ESP32 & !ETHERNET*/

6
src/network/AhoyWifiEsp8266.h

@ -39,6 +39,7 @@ class AhoyWifi : public AhoyNetwork {
mConnected = false; mConnected = false;
mOnNetworkCB(false); mOnNetworkCB(false);
mAp.enable(); mAp.enable();
MDNS.end();
} }
if (WiFi.softAPgetStationNum() > 0) { if (WiFi.softAPgetStationNum() > 0) {
@ -93,9 +94,14 @@ class AhoyWifi : public AhoyNetwork {
mConnected = true; mConnected = true;
ah::welcome(WiFi.localIP().toString(), F("Station")); ah::welcome(WiFi.localIP().toString(), F("Station"));
MDNS.begin(mConfig->sys.deviceName); MDNS.begin(mConfig->sys.deviceName);
MDNSResponder::hMDNSService hRes = MDNS.addService(NULL, "http", "tcp", 80);
MDNS.addServiceTxt(hRes, "path", "/");
MDNS.announce();
mOnNetworkCB(true); mOnNetworkCB(true);
} }
MDNS.update();
if(WiFi.channel() > 11) if(WiFi.channel() > 11)
mWasInCh12to14 = true; mWasInCh12to14 = true;
break; break;

35
src/platformio.ini

@ -148,17 +148,18 @@ monitor_filters =
esp8266_exception_decoder esp8266_exception_decoder
[env:esp32-wroom32-minimal] [env:esp32-wroom32-minimal]
platform = espressif32@6.5.0 platform = espressif32@6.6.0
board = lolin_d32 board = lolin_d32
build_flags = ${env.build_flags} build_flags = ${env.build_flags}
-DUSE_HSPI_FOR_EPD -DSPI_HAL
monitor_filters = monitor_filters =
esp32_exception_decoder esp32_exception_decoder
[env:esp32-wroom32] [env:esp32-wroom32]
platform = espressif32@6.5.0 platform = espressif32@6.6.0
board = lolin_d32 board = lolin_d32
build_flags = ${env:esp32-wroom32-minimal.build_flags} build_flags = ${env:esp32-wroom32-minimal.build_flags}
-DUSE_HSPI_FOR_EPD
-DENABLE_MQTT -DENABLE_MQTT
-DPLUGIN_DISPLAY -DPLUGIN_DISPLAY
-DENABLE_HISTORY -DENABLE_HISTORY
@ -166,7 +167,7 @@ monitor_filters =
esp32_exception_decoder esp32_exception_decoder
[env:esp32-wroom32-de] [env:esp32-wroom32-de]
platform = espressif32@6.5.0 platform = espressif32@6.6.0
board = lolin_d32 board = lolin_d32
build_flags = ${env:esp32-wroom32.build_flags} build_flags = ${env:esp32-wroom32.build_flags}
-DLANG_DE -DLANG_DE
@ -174,7 +175,7 @@ monitor_filters =
esp32_exception_decoder esp32_exception_decoder
[env:esp32-wroom32-prometheus] [env:esp32-wroom32-prometheus]
platform = espressif32@6.5.0 platform = espressif32@6.6.0
board = lolin_d32 board = lolin_d32
build_flags = ${env:esp32-wroom32.build_flags} build_flags = ${env:esp32-wroom32.build_flags}
-DENABLE_PROMETHEUS_EP -DENABLE_PROMETHEUS_EP
@ -182,7 +183,7 @@ monitor_filters =
esp32_exception_decoder esp32_exception_decoder
[env:esp32-wroom32-prometheus-de] [env:esp32-wroom32-prometheus-de]
platform = espressif32@6.5.0 platform = espressif32@6.6.0
board = lolin_d32 board = lolin_d32
build_flags = ${env:esp32-wroom32-prometheus.build_flags} build_flags = ${env:esp32-wroom32-prometheus.build_flags}
-DLANG_DE -DLANG_DE
@ -199,7 +200,7 @@ build_flags = ${env:esp32-wroom32.build_flags}
-DDEF_ETH_MISO_PIN=12 -DDEF_ETH_MISO_PIN=12
-DDEF_ETH_MOSI_PIN=13 -DDEF_ETH_MOSI_PIN=13
-DDEF_ETH_IRQ_PIN=4 -DDEF_ETH_IRQ_PIN=4
-DDEF_ETH_RST_PIN=2 -DDEF_ETH_RST_PIN=255
-DDEF_NRF_CS_PIN=5 -DDEF_NRF_CS_PIN=5
-DDEF_NRF_CE_PIN=17 -DDEF_NRF_CE_PIN=17
-DDEF_NRF_IRQ_PIN=16 -DDEF_NRF_IRQ_PIN=16
@ -218,10 +219,11 @@ monitor_filters =
esp32_exception_decoder esp32_exception_decoder
[env:esp32-s2-mini] [env:esp32-s2-mini]
platform = espressif32@6.5.0 platform = espressif32@6.6.0
board = lolin_s2_mini board = lolin_s2_mini
build_flags = ${env.build_flags} build_flags = ${env.build_flags}
-DUSE_HSPI_FOR_EPD -DUSE_HSPI_FOR_EPD
-DSPI_HAL
-DENABLE_MQTT -DENABLE_MQTT
-DPLUGIN_DISPLAY -DPLUGIN_DISPLAY
-DENABLE_HISTORY -DENABLE_HISTORY
@ -240,7 +242,7 @@ monitor_filters =
esp32_exception_decoder esp32_exception_decoder
[env:esp32-s2-mini-de] [env:esp32-s2-mini-de]
platform = espressif32@6.5.0 platform = espressif32@6.6.0
board = lolin_s2_mini board = lolin_s2_mini
build_flags = ${env:esp32-s2-mini.build_flags} build_flags = ${env:esp32-s2-mini.build_flags}
-DLANG_DE -DLANG_DE
@ -248,10 +250,11 @@ monitor_filters =
esp32_exception_decoder esp32_exception_decoder
[env:esp32-c3-mini] [env:esp32-c3-mini]
platform = espressif32@6.5.0 platform = espressif32@6.6.0
board = lolin_c3_mini board = lolin_c3_mini
build_flags = ${env.build_flags} build_flags = ${env.build_flags}
-DUSE_HSPI_FOR_EPD -DUSE_HSPI_FOR_EPD
-DSPI_HAL
-DENABLE_MQTT -DENABLE_MQTT
-DPLUGIN_DISPLAY -DPLUGIN_DISPLAY
-DENABLE_HISTORY -DENABLE_HISTORY
@ -270,7 +273,7 @@ monitor_filters =
esp32_exception_decoder esp32_exception_decoder
[env:esp32-c3-mini-de] [env:esp32-c3-mini-de]
platform = espressif32@6.5.0 platform = espressif32@6.6.0
board = lolin_c3_mini board = lolin_c3_mini
build_flags = ${env:esp32-c3-mini.build_flags} build_flags = ${env:esp32-c3-mini.build_flags}
-DLANG_DE -DLANG_DE
@ -278,7 +281,7 @@ monitor_filters =
esp32_exception_decoder esp32_exception_decoder
[env:opendtufusion-minimal] [env:opendtufusion-minimal]
platform = espressif32@6.5.0 platform = espressif32@6.6.0
board = esp32-s3-devkitc-1 board = esp32-s3-devkitc-1
upload_protocol = esp-builtin upload_protocol = esp-builtin
build_flags = ${env.build_flags} build_flags = ${env.build_flags}
@ -303,7 +306,7 @@ monitor_filters =
esp32_exception_decoder, colorize esp32_exception_decoder, colorize
[env:opendtufusion] [env:opendtufusion]
platform = espressif32@6.5.0 platform = espressif32@6.6.0
board = esp32-s3-devkitc-1 board = esp32-s3-devkitc-1
upload_protocol = esp-builtin upload_protocol = esp-builtin
build_flags = ${env:opendtufusion-minimal.build_flags} build_flags = ${env:opendtufusion-minimal.build_flags}
@ -314,7 +317,7 @@ monitor_filters =
esp32_exception_decoder, colorize esp32_exception_decoder, colorize
[env:opendtufusion-de] [env:opendtufusion-de]
platform = espressif32@6.5.0 platform = espressif32@6.6.0
board = esp32-s3-devkitc-1 board = esp32-s3-devkitc-1
upload_protocol = esp-builtin upload_protocol = esp-builtin
build_flags = ${env:opendtufusion.build_flags} build_flags = ${env:opendtufusion.build_flags}
@ -323,7 +326,7 @@ monitor_filters =
esp32_exception_decoder, colorize esp32_exception_decoder, colorize
[env:opendtufusion-ethernet] [env:opendtufusion-ethernet]
platform = espressif32@6.5.0 platform = espressif32@6.6.0
board = esp32-s3-devkitc-1 board = esp32-s3-devkitc-1
upload_protocol = esp-builtin upload_protocol = esp-builtin
build_flags = ${env:opendtufusion-minimal.build_flags} build_flags = ${env:opendtufusion-minimal.build_flags}
@ -342,7 +345,7 @@ monitor_filters =
esp32_exception_decoder, colorize esp32_exception_decoder, colorize
[env:opendtufusion-ethernet-de] [env:opendtufusion-ethernet-de]
platform = espressif32@6.5.0 platform = espressif32@6.6.0
board = esp32-s3-devkitc-1 board = esp32-s3-devkitc-1
upload_protocol = esp-builtin upload_protocol = esp-builtin
build_flags = ${env:opendtufusion-ethernet.build_flags} build_flags = ${env:opendtufusion-ethernet.build_flags}

10
src/plugins/Display/Display.h

@ -7,7 +7,7 @@
#include <U8g2lib.h> #include <U8g2lib.h>
#include "../../hm/hmSystem.h" #include "../../hm/hmSystem.h"
#include "../../hm/hmRadio.h" #include "../../hm/NrfRadio.h"
#include "../../utils/helper.h" #include "../../utils/helper.h"
#include "../plugin_lang.h" #include "../plugin_lang.h"
#include "Display_Mono.h" #include "Display_Mono.h"
@ -25,9 +25,9 @@ class Display {
mMono = NULL; mMono = NULL;
} }
void setup(IApp *app, display_t *cfg, HMSYSTEM *sys, RADIO *hmradio, RADIO *hmsradio, uint32_t *utcTs) { void setup(IApp *app, display_t *cfg, HMSYSTEM *sys, RADIO *nrfRadio, RADIO *hmsradio, uint32_t *utcTs) {
mApp = app; mApp = app;
mHmRadio = hmradio; mNrfRadio = nrfRadio;
mHmsRadio = hmsradio; mHmsRadio = hmsradio;
mCfg = cfg; mCfg = cfg;
mSys = sys; mSys = sys;
@ -149,7 +149,7 @@ class Display {
mDisplayData.totalYieldDay = totalYieldDay; mDisplayData.totalYieldDay = totalYieldDay;
mDisplayData.totalYieldTotal = totalYieldTotal; mDisplayData.totalYieldTotal = totalYieldTotal;
bool nrf_en = mApp->getNrfEnabled(); bool nrf_en = mApp->getNrfEnabled();
bool nrf_ok = nrf_en && mHmRadio->isChipConnected(); bool nrf_ok = nrf_en && mNrfRadio->isChipConnected();
#if defined(ESP32) #if defined(ESP32)
bool cmt_en = mApp->getCmtEnabled(); bool cmt_en = mApp->getCmtEnabled();
bool cmt_ok = cmt_en && mHmsRadio->isChipConnected(); bool cmt_ok = cmt_en && mHmsRadio->isChipConnected();
@ -231,7 +231,7 @@ class Display {
uint32_t *mUtcTs = nullptr; uint32_t *mUtcTs = nullptr;
display_t *mCfg = nullptr; display_t *mCfg = nullptr;
HMSYSTEM *mSys = nullptr; HMSYSTEM *mSys = nullptr;
RADIO *mHmRadio = nullptr; RADIO *mNrfRadio = nullptr;
RADIO *mHmsRadio = nullptr; RADIO *mHmsRadio = nullptr;
uint16_t mRefreshCycle = 0; uint16_t mRefreshCycle = 0;

2
src/plugins/Display/Display_ePaper.cpp

@ -39,7 +39,7 @@ void DisplayEPaper::init(uint8_t type, uint8_t _CS, uint8_t _DC, uint8_t _RST, u
#if defined(ESP32) && defined(USE_HSPI_FOR_EPD) #if defined(ESP32) && defined(USE_HSPI_FOR_EPD)
hspi.begin(_SCK, _BUSY, _MOSI, _CS); hspi.begin(_SCK, _BUSY, _MOSI, _CS);
_display->epd2.selectSPI(hspi, SPISettings(spiClk, MSBFIRST, SPI_MODE0)); _display->epd2.selectSPI(hspi, SPISettings(spiClk, MSBFIRST, SPI_MODE0));
#elif defined(ESP32) #elif defined(ESP32) && defined(PLUGIN_DISPLAY)
_display->epd2.init(_SCK, _MOSI, 115200, true, 20, false); _display->epd2.init(_SCK, _MOSI, 115200, true, 20, false);
#endif #endif
_display->init(115200, true, 20, false); _display->init(115200, true, 20, false);

11
src/publisher/pubMqtt.h

@ -243,7 +243,8 @@ class PubMqtt {
void setPowerLimitAck(Inverter<> *iv) { void setPowerLimitAck(Inverter<> *iv) {
if (NULL != iv) { if (NULL != iv) {
snprintf(mSubTopic.data(), mSubTopic.size(), "%s/%s", iv->config->name, subtopics[MQTT_ACK_PWR_LMT]); snprintf(mSubTopic.data(), mSubTopic.size(), "%s/%s", iv->config->name, subtopics[MQTT_ACK_PWR_LMT]);
publish(mSubTopic.data(), "true", true, true, QOS_2); snprintf(mVal.data(), mVal.size(), "%.1f", iv->powerLimit[0]/10.0);
publish(mSubTopic.data(), mVal.data(), true, true, QOS_2);
} }
} }
@ -251,8 +252,8 @@ class PubMqtt {
void onConnect(bool sessionPreset) { void onConnect(bool sessionPreset) {
DPRINTLN(DBG_INFO, F("MQTT connected")); DPRINTLN(DBG_INFO, F("MQTT connected"));
publish(subtopics[MQTT_VERSION], mVersion, true); publish(subtopics[MQTT_VERSION], mVersion, false);
publish(subtopics[MQTT_DEVICE], mDevName, true); publish(subtopics[MQTT_DEVICE], mDevName, false);
publish(subtopics[MQTT_IP_ADDR], mApp->getIp().c_str(), true); publish(subtopics[MQTT_IP_ADDR], mApp->getIp().c_str(), true);
tickerMinute(); tickerMinute();
publish(mLwtTopic.data(), mqttStr[MQTT_STR_LWT_CONN], true, false); publish(mLwtTopic.data(), mqttStr[MQTT_STR_LWT_CONN], true, false);
@ -605,6 +606,10 @@ class PubMqtt {
mLastAnyAvail = anyAvail; mLastAnyAvail = anyAvail;
} }
private:
enum {MQTT_STATUS_OFFLINE = 0, MQTT_STATUS_PARTIAL, MQTT_STATUS_ONLINE};
private:
espMqttClient mClient; espMqttClient mClient;
cfgMqtt_t *mCfgMqtt = nullptr; cfgMqtt_t *mCfgMqtt = nullptr;
IApp *mApp; IApp *mApp;

2
src/publisher/pubMqttIvData.h

@ -188,7 +188,6 @@ class PubMqttIvData {
static_cast<int>(mIv->getChannelFieldValue(CH0, FLD_FW_BUILD_MONTH_DAY, rec)), static_cast<int>(mIv->getChannelFieldValue(CH0, FLD_FW_BUILD_MONTH_DAY, rec)),
static_cast<int>(mIv->getChannelFieldValue(CH0, FLD_FW_BUILD_HOUR_MINUTE, rec)), static_cast<int>(mIv->getChannelFieldValue(CH0, FLD_FW_BUILD_HOUR_MINUTE, rec)),
static_cast<int>(mIv->getChannelFieldValue(CH0, FLD_BOOTLOADER_VER, rec))); static_cast<int>(mIv->getChannelFieldValue(CH0, FLD_BOOTLOADER_VER, rec)));
retained = true;
} else if(InverterDevInform_Simple == mCmd) { } else if(InverterDevInform_Simple == mCmd) {
snprintf(mSubTopic.data(), mSubTopic.size(), "%s/hardware", mIv->config->name); snprintf(mSubTopic.data(), mSubTopic.size(), "%s/hardware", mIv->config->name);
snprintf(mVal.data(), mVal.size(), "{\"part\":%d,\"version\":\"%d\",\"grid_profile_code\":%d,\"grid_profile_version\":%d}", snprintf(mVal.data(), mVal.size(), "{\"part\":%d,\"version\":\"%d\",\"grid_profile_code\":%d,\"grid_profile_version\":%d}",
@ -196,7 +195,6 @@ class PubMqttIvData {
static_cast<int>(mIv->getChannelFieldValue(CH0, FLD_HW_VERSION, rec)), static_cast<int>(mIv->getChannelFieldValue(CH0, FLD_HW_VERSION, rec)),
static_cast<int>(mIv->getChannelFieldValue(CH0, FLD_GRID_PROFILE_CODE, rec)), static_cast<int>(mIv->getChannelFieldValue(CH0, FLD_GRID_PROFILE_CODE, rec)),
static_cast<int>(mIv->getChannelFieldValue(CH0, FLD_GRID_PROFILE_VERSION, rec))); static_cast<int>(mIv->getChannelFieldValue(CH0, FLD_GRID_PROFILE_VERSION, rec)));
retained = true;
} else { } else {
if (!mJson) { if (!mJson) {
snprintf(mSubTopic.data(), mSubTopic.size(), "%s/ch%d/%s", mIv->config->name, rec->assign[mPos].ch, fields[rec->assign[mPos].fieldId]); snprintf(mSubTopic.data(), mSubTopic.size(), "%s/ch%d/%s", mIv->config->name, rec->assign[mPos].ch, fields[rec->assign[mPos].fieldId]);

8
src/utils/improv.h

@ -147,10 +147,12 @@ class Improv {
} }
void getNetworks(void) { void getNetworks(void) {
if(!mScanRunning)
mApp->scanAvailNetworks();
JsonObject obj; JsonObject obj;
if(!mScanRunning) {
mApp->getAvailNetworks(obj);
return;
}
if(!mApp->getAvailNetworks(obj)) if(!mApp->getAvailNetworks(obj))
return; return;

24
src/web/RestApi.h

@ -40,7 +40,7 @@ class RestApi {
mApp = app; mApp = app;
mSrv = srv; mSrv = srv;
mSys = sys; mSys = sys;
mRadioNrf = (HmRadio<>*)mApp->getRadioObj(true); mRadioNrf = (NrfRadio<>*)mApp->getRadioObj(true);
#if defined(ESP32) #if defined(ESP32)
mRadioCmt = (CmtRadio<>*)mApp->getRadioObj(false); mRadioCmt = (CmtRadio<>*)mApp->getRadioObj(false);
#endif #endif
@ -100,7 +100,7 @@ class RestApi {
else if(path == "setup") getSetup(request, root); else if(path == "setup") getSetup(request, root);
#if !defined(ETHERNET) #if !defined(ETHERNET)
else if(path == "setup/networks") getNetworks(root); else if(path == "setup/networks") getNetworks(root);
else if(path == "setup/getip") getWifiIp(root); else if(path == "setup/getip") getIp(root);
#endif /* !defined(ETHERNET) */ #endif /* !defined(ETHERNET) */
else if(path == "live") getLive(request,root); else if(path == "live") getLive(request,root);
else if (path == "powerHistory") getPowerHistory(request, root); else if (path == "powerHistory") getPowerHistory(request, root);
@ -166,7 +166,7 @@ class RestApi {
#else #else
DynamicJsonDocument json(12000); // does this work? I have no ESP32 :-( DynamicJsonDocument json(12000); // does this work? I have no ESP32 :-(
#endif #endif
DeserializationError err = deserializeJson(json, (const char *)mTmpBuf, mTmpSize); DeserializationError err = deserializeJson(json, static_cast<const char *>(mTmpBuf, mTmpSize));
json.shrinkToFit(); json.shrinkToFit();
JsonObject obj = json.as<JsonObject>(); JsonObject obj = json.as<JsonObject>();
@ -893,13 +893,15 @@ class RestApi {
#if !defined(ETHERNET) #if !defined(ETHERNET)
void getNetworks(JsonObject obj) { void getNetworks(JsonObject obj) {
mApp->getAvailNetworks(obj); obj[F("success")] = mApp->getAvailNetworks(obj);
}
void getWifiIp(JsonObject obj) {
obj[F("ip")] = mApp->getIp(); obj[F("ip")] = mApp->getIp();
} }
#endif /* !defined(ETHERNET) */ #endif /* !defined(ETHERNET) */
void getIp(JsonObject obj) {
obj[F("ip")] = mApp->getIp();
}
void getLive(AsyncWebServerRequest *request, JsonObject obj) { void getLive(AsyncWebServerRequest *request, JsonObject obj) {
getGeneric(request, obj.createNestedObject(F("generic"))); getGeneric(request, obj.createNestedObject(F("generic")));
obj[F("refresh")] = mConfig->inst.sendInterval; obj[F("refresh")] = mConfig->inst.sendInterval;
@ -1012,7 +1014,7 @@ class RestApi {
accepted = iv->setDevControlRequest(ActivePowerContr); accepted = iv->setDevControlRequest(ActivePowerContr);
if(accepted) if(accepted)
mApp->triggerTickSend(); mApp->triggerTickSend(iv->id);
} else if(F("dev") == jsonIn[F("cmd")]) { } else if(F("dev") == jsonIn[F("cmd")]) {
DPRINTLN(DBG_INFO, F("dev cmd")); DPRINTLN(DBG_INFO, F("dev cmd"));
iv->setDevCommand(jsonIn[F("val")].as<int>()); iv->setDevCommand(jsonIn[F("val")].as<int>());
@ -1033,11 +1035,6 @@ class RestApi {
if(isProtected(jsonIn, jsonOut, clientIP)) if(isProtected(jsonIn, jsonOut, clientIP))
return false; return false;
#if !defined(ETHERNET)
if(F("scan_wifi") == jsonIn[F("cmd")])
mApp->scanAvailNetworks();
else
#endif /* !defined(ETHERNET) */
if(F("set_time") == jsonIn[F("cmd")]) if(F("set_time") == jsonIn[F("cmd")])
mApp->setTimestamp(jsonIn[F("val")]); mApp->setTimestamp(jsonIn[F("val")]);
else if(F("sync_ntp") == jsonIn[F("cmd")]) else if(F("sync_ntp") == jsonIn[F("cmd")])
@ -1051,7 +1048,6 @@ class RestApi {
snprintf(mConfig->sys.stationSsid, SSID_LEN, "%s", jsonIn[F("ssid")].as<const char*>()); 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*>()); snprintf(mConfig->sys.stationPwd, PWD_LEN, "%s", jsonIn[F("pwd")].as<const char*>());
mApp->saveSettings(false); // without reboot mApp->saveSettings(false); // without reboot
//mApp->setStopApAllowedMode(false);
mApp->setupStation(); mApp->setupStation();
} }
#else #else
@ -1119,7 +1115,7 @@ class RestApi {
private: private:
IApp *mApp = nullptr; IApp *mApp = nullptr;
HMSYSTEM *mSys = nullptr; HMSYSTEM *mSys = nullptr;
HmRadio<> *mRadioNrf = nullptr; NrfRadio<> *mRadioNrf = nullptr;
#if defined(ESP32) #if defined(ESP32)
CmtRadio<> *mRadioCmt = nullptr; CmtRadio<> *mRadioCmt = nullptr;
#endif #endif

4
src/web/html/history.html

@ -150,11 +150,11 @@
parseRssi(obj.generic) parseRssi(obj.generic)
window.setInterval("getAjax('/api/powerHistory', parsePowerHistory)", obj.refresh * 1000) window.setInterval("getAjax('/api/powerHistory', parsePowerHistory)", obj.refresh * 1000)
setTimeout(() => { setTimeout(() => {
window.setInterval("getAjax('/api/powerHistoryDay', parsePowerHistoryDay)", refresh * 1000) window.setInterval("getAjax('/api/powerHistoryDay', parsePowerHistoryDay)", obj.refresh * 1000)
}, 200) }, 200)
/*IF_ENABLE_HISTORY_YIELD_PER_DAY*/ /*IF_ENABLE_HISTORY_YIELD_PER_DAY*/
setTimeout(() => { setTimeout(() => {
window.setInterval("getAjax('/api/yieldDayHistory', parseYieldDayHistory)", refresh * 1000) window.setInterval("getAjax('/api/yieldDayHistory', parseYieldDayHistory)", obj.refresh * 1000)
}, 400) }, 400)
/*ENDIF_ENABLE_HISTORY_YIELD_PER_DAY*/ /*ENDIF_ENABLE_HISTORY_YIELD_PER_DAY*/
} }

50
src/web/html/setup.html

@ -52,28 +52,19 @@
<div class="s_content"> <div class="s_content">
<fieldset class="mb-2"> <fieldset class="mb-2">
<legend class="des">WiFi</legend> <legend class="des">WiFi</legend>
<div class="row mb-3"> <div class="row mb-3">
<div class="col-12 col-sm-3 my-2">{#AP_PWD}</div> <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 class="col-12 col-sm-9"><input type="text" name="ap_pwd" minlength="8" /></div>
</div> </div>
<div class="row mb-3"> <!--IF_ETHERNET-->
<div class="col-12 col-sm-3 my-2">{#SEARCH_NETWORKS}</div> <!--ELSE-->
<div class="col-12 col-sm-9"><input type="button" name="scanbtn" id="scanbtn" class="btn" value="{#BTN_SCAN}" onclick="scan()"/></div>
</div>
<div class="row mb-2 mb-sm-3"> <div class="row mb-2 mb-sm-3">
<div class="col-12 col-sm-3 my-2">{#AVAIL_NETWORKS}</div> <div class="col-12 col-sm-3 my-2">SSID</div>
<div class="col-12 col-sm-9"> <div class="col-12 col-sm-9">
<select name="networks" id="networks" onChange="selNet()"> <input type="text" name="ssid"/><br/>
<option value="-1" selected disabled hidden>{#NETWORK_NOT_SCANNED}</option> <a href="/wizard">{#SCAN_WIFI}</a>
</select>
</div> </div>
</div> </div>
<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"><input type="text" name="ssid"/></div>
</div>
<div class="row mb-2 mb-sm-3"> <div class="row mb-2 mb-sm-3">
<div class="col-12 col-sm-3">{#SSID_HIDDEN}</div> <div class="col-12 col-sm-3">{#SSID_HIDDEN}</div>
<div class="col-12 col-sm-9"><input type="checkbox" name="hidd"/></div> <div class="col-12 col-sm-9"><input type="checkbox" name="hidd"/></div>
@ -82,6 +73,7 @@
<div class="col-12 col-sm-3 my-2">{#PASSWORD}</div> <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 class="col-12 col-sm-9"><input type="password" name="pwd" value="{PWD}"/></div>
</div> </div>
<!--ENDIF_ETHERNET-->
</fieldset> </fieldset>
<fieldset class="mb-4"> <fieldset class="mb-4">
<legend class="des">{#STATIC_IP}</legend> <legend class="des">{#STATIC_IP}</legend>
@ -610,12 +602,6 @@
setTimeout(function() {getAjax('/api/index', apiCbNtp2)}, 2000) setTimeout(function() {getAjax('/api/index', apiCbNtp2)}, 2000)
} }
function scan() {
var obj = {cmd: "scan_wifi", token: "*"}
getAjax("/api/setup", apiCbWifi, "POST", JSON.stringify(obj));
setTimeout(function() {getAjax('/api/setup/networks', listNetworks)}, 5000);
}
function syncTime() { function syncTime() {
var obj = {cmd: "sync_ntp", token: "*"} var obj = {cmd: "sync_ntp", token: "*"}
getAjax("/api/setup", apiCbNtp, "POST", JSON.stringify(obj)) getAjax("/api/setup", apiCbNtp, "POST", JSON.stringify(obj))
@ -675,9 +661,14 @@
} }
function parseSys(obj) { 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"]]) for(var i of [["device", "device_name"], ["ssid", "ssid"], ["ap_pwd", "ap_pwd"]])
document.getElementsByName(i[0])[0].value = obj[i[1]]; document.getElementsByName(i[0])[0].value = obj[i[1]];
document.getElementsByName("hidd")[0].checked = obj["hidd"]; document.getElementsByName("hidd")[0].checked = obj["hidd"];
/*ENDIF_ETHERNET*/
document.getElementsByName("darkMode")[0].checked = obj["dark_mode"]; document.getElementsByName("darkMode")[0].checked = obj["dark_mode"];
document.getElementsByName("schedReboot")[0].checked = obj["sched_reboot"]; document.getElementsByName("schedReboot")[0].checked = obj["sched_reboot"];
e = document.getElementsByName("adminpwd")[0]; e = document.getElementsByName("adminpwd")[0];
@ -1312,25 +1303,6 @@
} }
} }
function listNetworks(root) {
var s = document.getElementById("networks");
selDelAllOpt(s);
if(root["networks"].length > 0) {
s.appendChild(opt("-1", "{#NETWORK_PLEASE_SELECT}"));
for(i = 0; i < root["networks"].length; i++) {
s.appendChild(opt(root["networks"][i]["ssid"], root["networks"][i]["ssid"] + " (" + root["networks"][i]["rssi"] + " dBm)"));
}
} else
s.appendChild(opt("-1", "{#NO_NETWORK_FOUND}"));
}
function selNet() {
var s = document.getElementById("networks");
var e = document.getElementsByName("ssid")[0];
if(-1 != s.value)
e.value = s.value;
}
getAjax("/api/setup", parse); getAjax("/api/setup", parse);
</script> </script>
</body> </body>

27
src/web/html/wizard.html

@ -4,7 +4,7 @@
<title>{#NAV_WIZARD}</title> <title>{#NAV_WIZARD}</title>
{#HTML_HEADER} {#HTML_HEADER}
</head> </head>
<body> <body onload="init()">
<div id="wrapper"> <div id="wrapper">
<div class="container d-flex aic jc"> <div class="container d-flex aic jc">
<div id="con"></div> <div id="con"></div>
@ -14,6 +14,7 @@
var v; var v;
var found = false; var found = false;
var c = document.getElementById("con"); var c = document.getElementById("con");
var redirIp = "http://192.168.4.1/index"
/*IF_ESP32*/ /*IF_ESP32*/
var pinList = [ var pinList = [
@ -206,7 +207,7 @@
]), ]),
...lst, ...lst,
ml("div", {class: "row my-4"}, ml("div", {class: "col a-r"}, ml("input", {type: "button", class:"btn", value: "{#BTN_REBOOT}", onclick: () => {saveEth()}}, null))), ml("div", {class: "row my-4"}, ml("div", {class: "col a-r"}, ml("input", {type: "button", class:"btn", value: "{#BTN_REBOOT}", onclick: () => {saveEth()}}, null))),
ml("div", {class: "row mt-5"}, ml("div", {class: "col a-c"}, ml("a", {href: "http://192.168.4.1/"}, "{#STOP_WIZARD}"))) ml("div", {class: "row mt-5"}, ml("div", {class: "col a-c"}, ml("a", {onclick: () => {redirect()}}, "{#STOP_WIZARD}")))
]) ])
} }
/*ELSE*/ /*ELSE*/
@ -218,7 +219,7 @@
sect("{#WIFI_MANUAL}", ml("input", {id: "man", type: "text"})), sect("{#WIFI_MANUAL}", ml("input", {id: "man", type: "text"})),
sect("{#WIFI_PASSWORD}", ml("input", {id: "pwd", type: "password"})), sect("{#WIFI_PASSWORD}", ml("input", {id: "pwd", type: "password"})),
ml("div", {class: "row my-4"}, ml("div", {class: "col a-r"}, ml("input", {type: "button", class:"btn", value: "{#BTN_NEXT}", onclick: () => {saveWifi()}}, null))), ml("div", {class: "row my-4"}, ml("div", {class: "col a-r"}, ml("input", {type: "button", class:"btn", value: "{#BTN_NEXT}", onclick: () => {saveWifi()}}, null))),
ml("div", {class: "row mt-5"}, ml("div", {class: "col a-c"}, ml("a", {href: "http://192.168.4.1/"}, "{#STOP_WIZARD}"))) ml("div", {class: "row mt-5"}, ml("div", {class: "col a-c"}, ml("a", {onclick: () => {redirect()}}, "{#STOP_WIZARD}")))
]) ])
} }
/*ENDIF_ETHERNET*/ /*ENDIF_ETHERNET*/
@ -229,13 +230,13 @@
ml("div", {class: "row"}, ml("div", {class: "col"}, ml("span", {class: "fs-5"}, "{#TEST_CONNECTION}"))), ml("div", {class: "row"}, ml("div", {class: "col"}, ml("span", {class: "fs-5"}, "{#TEST_CONNECTION}"))),
sect("{#TRY_TO_CONNECT}", ml("span", {id: "state"}, "{#CONNECTING}")), sect("{#TRY_TO_CONNECT}", ml("span", {id: "state"}, "{#CONNECTING}")),
ml("div", {class: "row my-4"}, ml("div", {class: "col a-r"}, ml("input", {type: "button", class:"btn hide", id: "btn", value: "{#BTN_FINISH}", onclick: () => {redirect()}}, null))), ml("div", {class: "row my-4"}, ml("div", {class: "col a-r"}, ml("input", {type: "button", class:"btn hide", id: "btn", value: "{#BTN_FINISH}", onclick: () => {redirect()}}, null))),
ml("div", {class: "row mt-5"}, ml("div", {class: "col a-c"}, ml("a", {href: "http://192.168.4.1/"}, "{#STOP_WIZARD}"))) ml("div", {class: "row mt-5"}, ml("div", {class: "col a-c"}, ml("a", {onclick: () => {redirect()}}, "{#STOP_WIZARD}")))
) )
v = setInterval(() => {getAjax('/api/setup/getip', printIp)}, 2500); v = setInterval(() => {getAjax('/api/setup/getip', printIp)}, 500);
} }
function redirect() { function redirect() {
window.location.replace("http://192.168.4.1/") window.location.replace(redirIp)
} }
function printIp(obj) { function printIp(obj) {
@ -266,10 +267,17 @@
} }
/*ENDIF_ETHERNET*/ /*ENDIF_ETHERNET*/
function init() {
/*IF_ETHERNET*/ /*IF_ETHERNET*/
getAjax("/api/setup", ((o) => c.append(step1(o.eth)))); getAjax("/api/setup", ((o) => c.append(step1(o.eth))));
/*ELSE*/ /*ELSE*/
function nets(obj) { function nets(obj) {
if(!obj.success)
return;
clearInterval(v)
v = setInterval(() => {getAjax('/api/setup/networks', nets)}, 5000)
var e = document.getElementById("net"); var e = document.getElementById("net");
if(obj.networks.length > 0) { if(obj.networks.length > 0) {
var a = [] var a = []
@ -280,13 +288,14 @@
} }
e.replaceChildren(...a) e.replaceChildren(...a)
} }
getAjax("/api/setup", ((o) => {}), "POST", JSON.stringify({cmd: "scan_wifi"}));
redirIp = obj.ip + "/index"
} }
getAjax("/api/setup", ((o) => {}), "POST", JSON.stringify({cmd: "scan_wifi"}));
c.append(step1()) c.append(step1())
v = setInterval(() => {getAjax('/api/setup/networks', nets)}, 2500); getAjax('/api/setup/networks', nets)
/*ENDIF_ETHERNET*/ /*ENDIF_ETHERNET*/
}
</script> </script>
</body> </body>

24
src/web/lang.json

@ -6,7 +6,7 @@
{ {
"token": "NAV_WIZARD", "token": "NAV_WIZARD",
"en": "Setup Wizard", "en": "Setup Wizard",
"de": "Daten" "de": "Einrichtungsassitent"
}, },
{ {
"token": "NAV_LIVE", "token": "NAV_LIVE",
@ -81,7 +81,7 @@
{ {
"token": "BTN_NEXT", "token": "BTN_NEXT",
"en": "next >>", "en": "next >>",
"de": "prüfen >>" "de": "speichern >>"
}, },
{ {
"token": "BTN_REBOOT", "token": "BTN_REBOOT",
@ -91,12 +91,12 @@
{ {
"token": "TEST_CONNECTION", "token": "TEST_CONNECTION",
"en": "Test Connection", "en": "Test Connection",
"de": "Verbindung wird überprüft" "de": "Verbindung wird &uuml;berpr&uuml;ft"
}, },
{ {
"token": "TRY_TO_CONNECT", "token": "TRY_TO_CONNECT",
"en": "AhoyDTU is trying to connect to your WiFi", "en": "AhoyDTU is trying to connect to your WiFi",
"de": "AhoyDTU versucht eine Verindung mit deinem Netzwerk herzustellen" "de": "AhoyDTU versucht eine Verbindung mit Deinem Netzwerk herzustellen"
}, },
{ {
"token": "CONNECTING", "token": "CONNECTING",
@ -259,19 +259,9 @@
"de": "Netzwerke suchen" "de": "Netzwerke suchen"
}, },
{ {
"token": "BTN_SCAN", "token": "SCAN_WIFI",
"en": "scan", "en": "scan for WiFi networks",
"de": "Suche starten" "de": "nach WiFi Netzwerken suchen"
},
{
"token": "AVAIL_NETWORKS",
"en": "Avail Networks",
"de": "Verf&uuml;gbare Netzwerke"
},
{
"token": "NETWORK_NOT_SCANNED",
"en": "not scanned",
"de": "nicht gesucht"
}, },
{ {
"token": "SSID_HIDDEN", "token": "SSID_HIDDEN",

11
src/web/web.h

@ -57,7 +57,8 @@ class Web {
mConfig = config; mConfig = config;
DPRINTLN(DBG_VERBOSE, F("app::setup-on")); DPRINTLN(DBG_VERBOSE, F("app::setup-on"));
mWeb.on("/", HTTP_GET, std::bind(&Web::onIndex, this, std::placeholders::_1)); mWeb.on("/", HTTP_GET, std::bind(&Web::onIndex, this, std::placeholders::_1, true));
mWeb.on("/index", HTTP_GET, std::bind(&Web::onIndex, this, std::placeholders::_1, false));
mWeb.on("/login", HTTP_ANY, std::bind(&Web::onLogin, this, std::placeholders::_1)); mWeb.on("/login", HTTP_ANY, std::bind(&Web::onLogin, this, std::placeholders::_1));
mWeb.on("/logout", HTTP_GET, std::bind(&Web::onLogout, this, std::placeholders::_1)); mWeb.on("/logout", HTTP_GET, std::bind(&Web::onLogout, this, std::placeholders::_1));
mWeb.on("/colors.css", HTTP_GET, std::bind(&Web::onColor, this, std::placeholders::_1)); mWeb.on("/colors.css", HTTP_GET, std::bind(&Web::onColor, this, std::placeholders::_1));
@ -75,6 +76,7 @@ class Web {
mWeb.on("/setup", HTTP_GET, std::bind(&Web::onSetup, this, std::placeholders::_1)); mWeb.on("/setup", HTTP_GET, std::bind(&Web::onSetup, this, std::placeholders::_1));
mWeb.on("/wizard", HTTP_GET, std::bind(&Web::onWizard, this, std::placeholders::_1)); mWeb.on("/wizard", HTTP_GET, std::bind(&Web::onWizard, this, std::placeholders::_1));
mWeb.on("/generate_204", HTTP_GET, std::bind(&Web::onWizard, this, std::placeholders::_1)); //Android captive portal
mWeb.on("/save", HTTP_POST, std::bind(&Web::showSave, this, std::placeholders::_1)); mWeb.on("/save", HTTP_POST, std::bind(&Web::showSave, this, std::placeholders::_1));
mWeb.on("/live", HTTP_ANY, std::bind(&Web::onLive, this, std::placeholders::_1)); mWeb.on("/live", HTTP_ANY, std::bind(&Web::onLive, this, std::placeholders::_1));
@ -319,7 +321,11 @@ class Web {
client->send("hello!", NULL, millis(), 1000); client->send("hello!", NULL, millis(), 1000);
} }
void onIndex(AsyncWebServerRequest *request) { void onIndex(AsyncWebServerRequest *request, bool checkAp = true) {
if(mApp->isApActive() && checkAp) {
onWizard(request);
return;
}
getPage(request, PROT_MASK_INDEX, index_html, index_html_len); getPage(request, PROT_MASK_INDEX, index_html, index_html_len);
} }
@ -402,6 +408,7 @@ class Web {
void showNotFound(AsyncWebServerRequest *request) { void showNotFound(AsyncWebServerRequest *request) {
checkProtection(request); checkProtection(request);
//DBGPRINTLN(request->url());
request->redirect("/wizard"); request->redirect("/wizard");
} }

Loading…
Cancel
Save