diff --git a/.github/ISSUE_TEMPLATE/report.yaml b/.github/ISSUE_TEMPLATE/report.yaml index 9a2824c4..19b71de2 100644 --- a/.github/ISSUE_TEMPLATE/report.yaml +++ b/.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! 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! Check our FAQ: https://ahoydtu.de/faq - type: markdown @@ -35,7 +35,7 @@ body: label: Assembly description: options: - - I did the assebly by myself + - I did the assembly by myself - the DTU was already assembled validations: required: true @@ -84,7 +84,7 @@ body: label: Connection picture description: options: - - label: I will attach/upload an Image of my wiring + - label: I will attach/upload an image of my wiring validations: required: true - type: markdown diff --git a/.gitignore b/.gitignore index 21ae2a57..b5c699cc 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ src/web/html/tmp/* src/output.map /.venv +/scripts/__pycache__/htmlPreprocessorDefines.cpython-311.pyc diff --git a/scripts/convertHtml.py b/scripts/convertHtml.py index ec16b5f3..026c28da 100644 --- a/scripts/convertHtml.py +++ b/scripts/convertHtml.py @@ -9,19 +9,29 @@ from pathlib import Path import subprocess import configparser Import("env") +build_flags = [] import htmlPreprocessorDefines as prepro - - -def get_build_flags(): +def getFlagsOfEnv(env): config = configparser.ConfigParser() config.read('platformio.ini') global build_flags - build_flags = config["env:" + env['PIOENV']]['build_flags'].split('\n') + flags = config[env]['build_flags'].split('\n') - for i in range(len(build_flags)): - build_flags[i] = build_flags[i][2:] + for i in range(len(flags)): + if flags[i][:2] == "-D" or flags[i][:2] == "${": + flags[i] = flags[i][2:] + if flags[i][-13:-1] == ".build_flags": + getFlagsOfEnv(flags[i].split(".build_flags")[0]) + elif len(flags[i]) > 0: + build_flags = build_flags + [flags[i]] + + +def get_build_flags(): + getFlagsOfEnv("env:" + env['PIOENV']) + config = configparser.ConfigParser() + config.read('platformio.ini') # translate board board = config["env:" + env['PIOENV']]['board'] diff --git a/src/.gitignore b/src/.gitignore index 89cc49cb..30f1d1ca 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -3,3 +3,5 @@ .vscode/c_cpp_properties.json .vscode/launch.json .vscode/ipch +scripts/__pycache__/* +*.pyc diff --git a/src/CHANGES.md b/src/CHANGES.md index af1ecd86..73c5c5d4 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,33 @@ # Development Changes +## 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 +* updated converter scripts to include all enabled features again (redundant scan of build flags) #1534 + +## 0.8.100 - 2024-03-27 +* fix captions in `/history #1532 +* fix get NTP time #1529 #1530 +* fix translation #1516 + +## 0.8.99 - 2024-03-27 +* fix compilation of all environments + +## 0.8.98 - 2024-03-24 +* new network routines + ## 0.8.97 - 2024-03-22 * add support for newest generation of inverters with A-F in their serial number * fix NTP and sunrise / sunset diff --git a/src/app.cpp b/src/app.cpp index 4e3595d1..ae78b0cf 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -57,17 +57,15 @@ void app::setup() { 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); } #endif + #ifdef ETHERNET delay(1000); - mEth.setup(mConfig, &mTimestamp, [this](bool gotIp) { this->onNetwork(gotIp); }, [this](bool gotTime) { this->onNtpUpdate(gotTime); }); + mNetwork = static_cast(new AhoyEthernet()); + #else + mNetwork = static_cast(new AhoyWifi()); #endif // ETHERNET - - #if !defined(ETHERNET) - mWifi.setup(mConfig, &mTimestamp, [this](bool gotIp) { this->onNetwork(gotIp); }, [this](bool gotTime) { this->onNtpUpdate(gotTime); }); - #if !defined(AP_ONLY) - everySec(std::bind(&ahoywifi::tickWifiLoop, &mWifi), "wifiL"); - #endif - #endif /* defined(ETHERNET) */ + mNetwork->setup(mConfig, &mTimestamp, [this](bool gotIp) { this->onNetwork(gotIp); }, [this](bool gotTime) { this->onNtpUpdate(gotTime); }); + mNetwork->begin(); esp_task_wdt_reset(); @@ -116,7 +114,7 @@ void app::setup() { #if defined(ENABLE_MQTT) mMqttEnabled = (mConfig->mqtt.broker[0] > 0); if (mMqttEnabled) { - mMqtt.setup(&mConfig->mqtt, mConfig->sys.deviceName, mVersion, &mSys, &mTimestamp, &mUptime); + mMqtt.setup(this, &mConfig->mqtt, mConfig->sys.deviceName, mVersion, &mSys, &mTimestamp, &mUptime); mMqtt.setSubscriptionCb(std::bind(&app::mqttSubRxCb, this, std::placeholders::_1)); mCommunication.addAlarmListener([this](Inverter<> *iv) { mMqtt.alarmEvent(iv); }); } @@ -205,7 +203,6 @@ void app::loop(void) { //----------------------------------------------------------------------------- void app::onNetwork(bool gotIp) { - DPRINTLN(DBG_INFO, F("onNetwork")); mNetworkConnected = gotIp; ah::Scheduler::resetTicker(); regularTickers(); //reinstall regular tickers @@ -213,12 +210,6 @@ void app::onNetwork(bool gotIp) { mMqttReconnect = true; mSunrise = 0; // needs to be set to 0, to reinstall sunrise and ivComm tickers! once(std::bind(&app::tickNtpUpdate, this), 2, "ntp2"); - #if !defined(ETHERNET) - if (WIFI_AP == WiFi.getMode()) { - mMqttEnabled = false; - } - everySec(std::bind(&ahoywifi::tickWifiLoop, &mWifi), "wifiL"); - #endif /* !defined(ETHERNET) */ } //----------------------------------------------------------------------------- @@ -226,6 +217,7 @@ void app::regularTickers(void) { DPRINTLN(DBG_DEBUG, F("regularTickers")); everySec(std::bind(&WebType::tickSecond, &mWeb), "webSc"); everySec([this]() { mProtection->tickSecond(); }, "prot"); + everySec([this]() {mNetwork->tickNetworkLoop(); }, "net"); // Plugins #if defined(PLUGIN_DISPLAY) @@ -300,26 +292,14 @@ void app::updateNtp(void) { void app::tickNtpUpdate(void) { uint32_t nxtTrig = 5; // default: check again in 5 sec - #if defined(ETHERNET) - if (!mNtpReceived) - mEth.updateNtpTime(); - else - mNtpReceived = false; - #else - if (!mNtpReceived) - mWifi.updateNtpTime(); - else - mNtpReceived = false; - #endif + if (!mNtpReceived) + mNetwork->updateNtpTime(); + else { + nxtTrig = mConfig->ntp.interval * 60; // check again in configured interval + mNtpReceived = false; + } updateNtp(); - nxtTrig = mConfig->ntp.interval * 60; // check again in 12h - - // immediately start communicating - if (mSendFirst) { - mSendFirst = false; - once(std::bind(&app::tickSend, this), 1, "senOn"); - } mMqttReconnect = false; @@ -476,39 +456,17 @@ void app::tickSend(void) { for (uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { Inverter<> *iv = mSys.getInverterByPos(i); - if(NULL == iv) - continue; - - if(iv->config->enabled) { - if(!iv->commEnabled) { - DPRINT_IVID(DBG_INFO, iv->id); - DBGPRINTLN(F("no communication to the inverter (night time)")); - continue; - } - - if(!iv->radio->isChipConnected()) - continue; - - if(InverterStatus::OFF != iv->status) - notAvail = false; - - iv->tickSend([this, iv](uint8_t cmd, bool isDevControl) { - if(isDevControl) - mCommunication.addImportant(iv, cmd); - else - mCommunication.add(iv, cmd); - }); - + if(!sendIv(iv)) + notAvail = false; // Plugin ZeroExport // #if defined(PLUGIN_ZEROEXPORT) -// TODO: aufräumen +// TODO: aufr�umen // if(mConfig->nrf.enabled || mConfig->cmt.enabled) { // mZeroExport.loop(); // zeroexport(); // } // #endif // Plugin ZeroExport - Ende - } } if(mAllIvNotAvail != notAvail) @@ -518,6 +476,37 @@ void app::tickSend(void) { updateLed(); } +//----------------------------------------------------------------------------- +bool app::sendIv(Inverter<> *iv) { + if(NULL == iv) + return true; + + if(!iv->config->enabled) + return true; + + if(!iv->commEnabled) { + DPRINT_IVID(DBG_INFO, iv->id); + DBGPRINTLN(F("no communication to the inverter (night time)")); + return true; + } + + if(!iv->radio->isChipConnected()) + return true; + + bool notAvail = true; + if(InverterStatus::OFF != iv->status) + notAvail = false; + + iv->tickSend([this, iv](uint8_t cmd, bool isDevControl) { + if(isDevControl) + mCommunication.addImportant(iv, cmd); + else + mCommunication.add(iv, cmd); + }); + + return notAvail; +} + //----------------------------------------------------------------------------- void app:: zeroIvValues(bool checkAvail, bool skipYieldDay) { Inverter<> *iv; @@ -614,7 +603,6 @@ void app::resetSystem(void) { mTimestamp = 1; #endif - mSendFirst = true; mAllIvNotAvail = true; mSunrise = 0; @@ -690,7 +678,7 @@ void app::updateLed(void) { #if defined(PLUGIN_ZEROEXPORT) void app::zeroexport() { return; -// TODO: aufräumen +// TODO: aufr�umen // TODO: umziehen nach loop diff --git a/src/app.h b/src/app.h index 383bdc5d..178887ee 100644 --- a/src/app.h +++ b/src/app.h @@ -37,9 +37,13 @@ #include "web/web.h" #include "hm/Communication.h" #if defined(ETHERNET) - #include "eth/ahoyeth.h" + #include "network/AhoyEthernet.h" #else /* defined(ETHERNET) */ - #include "wifi/ahoywifi.h" + #if defined(ESP32) + #include "network/AhoyWifiEsp32.h" + #else + #include "network/AhoyWifiEsp8266.h" + #endif #include "utils/improv.h" #endif /* defined(ETHERNET) */ @@ -170,31 +174,30 @@ class app : public IApp, public ah::Scheduler { } #if !defined(ETHERNET) - void scanAvailNetworks() override { - mWifi.scanAvailNetworks(); - } - bool getAvailNetworks(JsonObject obj) override { - return mWifi.getAvailNetworks(obj); + return mNetwork->getAvailNetworks(obj); } void setupStation(void) override { - mWifi.setupStation(); - } - - void setStopApAllowedMode(bool allowed) override { - mWifi.setStopApAllowedMode(allowed); - } - - String getStationIp(void) override { - return mWifi.getStationIp(); + mNetwork->begin(); } bool getWasInCh12to14(void) const override { - return mWifi.getWasInCh12to14(); + #if defined(ESP8266) + return mNetwork->getWasInCh12to14(); + #else + return false; + #endif + } + #endif /* !defined(ETHERNET) */ + + String getIp(void) override { + return mNetwork->getIp(); } - #endif /* !defined(ETHERNET) */ + bool isApActive(void) override { + return mNetwork->isApActive(); + } void setRebootFlag() override { once(std::bind(&app::tickReboot, this), 3, "rboot"); @@ -302,13 +305,7 @@ class app : public IApp, public ah::Scheduler { DPRINT(DBG_DEBUG, F("setTimestamp: ")); DBGPRINTLN(String(newTime)); if(0 == newTime) - { - #if defined(ETHERNET) - mEth.updateNtpTime(); - #else /* defined(ETHERNET) */ - mWifi.updateNtpTime(); - #endif /* defined(ETHERNET) */ - } + mNetwork->updateNtpTime(); else Scheduler::setTimestamp(newTime); } @@ -406,8 +403,10 @@ class app : public IApp, public ah::Scheduler { bool mNtpReceived = false; void updateNtp(void); - void triggerTickSend() override { - once(std::bind(&app::tickSend, this), 0, "tSend"); + void triggerTickSend(uint8_t id) override { + once([this, id]() { + sendIv(mSys.getInverterByPos(id)); + }, 0, "devct"); } void tickCalcSunrise(void); @@ -416,6 +415,7 @@ class app : public IApp, public ah::Scheduler { void tickSunrise(void); void tickComm(void); void tickSend(void); + bool sendIv(Inverter<> *iv); void tickMinute(void); void tickZeroValues(void); void tickMidnight(void); @@ -427,11 +427,7 @@ class app : public IApp, public ah::Scheduler { bool mShowRebootRequest = false; - #if defined(ETHERNET) - ahoyeth mEth; - #else /* defined(ETHERNET) */ - ahoywifi mWifi; - #endif /* defined(ETHERNET) */ + AhoyNetwork *mNetwork = nullptr; WebType mWeb; RestApiType mApi; Protection *mProtection = nullptr; @@ -460,7 +456,6 @@ class app : public IApp, public ah::Scheduler { bool mSaveReboot = false; uint8_t mSendLastIvId = 0; - bool mSendFirst = false; bool mAllIvNotAvail = false; bool mNetworkConnected = false; diff --git a/src/appInterface.h b/src/appInterface.h index b465edf9..a1f5cd0e 100644 --- a/src/appInterface.h +++ b/src/appInterface.h @@ -26,13 +26,12 @@ class IApp { virtual const char *getVersionModules() = 0; #if !defined(ETHERNET) - virtual void scanAvailNetworks() = 0; virtual bool getAvailNetworks(JsonObject obj) = 0; virtual void setupStation(void) = 0; - virtual void setStopApAllowedMode(bool allowed) = 0; - virtual String getStationIp(void) = 0; virtual bool getWasInCh12to14(void) const = 0; #endif /* defined(ETHERNET) */ + virtual String getIp(void) = 0; + virtual bool isApActive(void) = 0; virtual uint32_t getUptime() = 0; virtual uint32_t getTimestamp() = 0; @@ -44,7 +43,7 @@ class IApp { virtual void getSchedulerInfo(uint8_t *max) = 0; virtual void getSchedulerNames() = 0; - virtual void triggerTickSend() = 0; + virtual void triggerTickSend(uint8_t id) = 0; virtual bool getRebootRequestState() = 0; virtual bool getSettingsValid() = 0; diff --git a/src/config/config.h b/src/config/config.h index b7f3cc2f..7254d13d 100644 --- a/src/config/config.h +++ b/src/config/config.h @@ -78,7 +78,7 @@ #define DEF_ETH_CS_PIN 15 #endif #ifndef DEF_ETH_RST_PIN - #define DEF_ETH_RST_PIN 2 + #define DEF_ETH_RST_PIN DEF_PIN_OFF #endif #else /* defined(ETHERNET) */ // time in seconds how long the station info (ssid + pwd) will be tried diff --git a/src/config/settings.h b/src/config/settings.h index d8872230..fe7f4694 100644 --- a/src/config/settings.h +++ b/src/config/settings.h @@ -63,6 +63,19 @@ typedef struct { uint8_t gateway[4]; // standard gateway } cfgIp_t; + +#if defined(ETHERNET) +typedef struct { + bool enabled; + uint8_t pinCs; + uint8_t pinSclk; + uint8_t pinMiso; + uint8_t pinMosi; + uint8_t pinIrq; + uint8_t pinRst; +} cfgEth_t; +#endif + typedef struct { char deviceName[DEVNAME_LEN]; char adminPwd[PWD_LEN]; @@ -72,12 +85,14 @@ typedef struct { uint8_t region; int8_t timezone; + char apPwd[PWD_LEN]; #if !defined(ETHERNET) // wifi char stationSsid[SSID_LEN]; char stationPwd[PWD_LEN]; - char apPwd[PWD_LEN]; bool isHidden; +#else + cfgEth_t eth; #endif /* !defined(ETHERNET) */ cfgIp_t ip; @@ -554,10 +569,24 @@ class settings { else { snprintf(mCfg.sys.stationSsid, SSID_LEN, FB_WIFI_SSID); snprintf(mCfg.sys.stationPwd, PWD_LEN, FB_WIFI_PWD); - snprintf(mCfg.sys.apPwd, PWD_LEN, WIFI_AP_PWD); mCfg.sys.isHidden = false; } - #endif /* !defined(ETHERNET) */ + #endif + snprintf(mCfg.sys.apPwd, PWD_LEN, WIFI_AP_PWD); + + #if defined(ETHERNET) + #if defined(DEF_ETH_ENABLED) + mCfg.sys.eth.enabled = true; + #else + mCfg.sys.eth.enabled = false; + #endif + mCfg.sys.eth.pinCs = DEF_ETH_CS_PIN; + mCfg.sys.eth.pinSclk = DEF_ETH_SCK_PIN; + mCfg.sys.eth.pinMiso = DEF_ETH_MISO_PIN; + mCfg.sys.eth.pinMosi = DEF_ETH_MOSI_PIN; + mCfg.sys.eth.pinIrq = DEF_ETH_IRQ_PIN; + mCfg.sys.eth.pinRst = DEF_ETH_RST_PIN; + #endif snprintf(mCfg.sys.deviceName, DEVNAME_LEN, DEF_DEVICE_NAME); mCfg.sys.region = 0; // Europe @@ -570,7 +599,11 @@ class settings { mCfg.nrf.pinMosi = DEF_NRF_MOSI_PIN; mCfg.nrf.pinSclk = DEF_NRF_SCLK_PIN; + #if defined(ETHERNET) + mCfg.nrf.enabled = false; + #else mCfg.nrf.enabled = true; + #endif #if defined(ESP32) mCfg.cmt.pinSclk = DEF_CMT_SCLK; @@ -800,6 +833,16 @@ class settings { ah::ip2Char(mCfg.sys.ip.dns1, buf); obj[F("dns1")] = String(buf); ah::ip2Char(mCfg.sys.ip.dns2, buf); obj[F("dns2")] = String(buf); ah::ip2Char(mCfg.sys.ip.gateway, buf); obj[F("gtwy")] = String(buf); + + #if defined(ETHERNET) + obj[F("en")] = mCfg.sys.eth.enabled; + obj[F("cs")] = mCfg.sys.eth.pinCs; + obj[F("sclk")] = mCfg.sys.eth.pinSclk; + obj[F("miso")] = mCfg.sys.eth.pinMiso; + obj[F("mosi")] = mCfg.sys.eth.pinMosi; + obj[F("irq")] = mCfg.sys.eth.pinIrq; + obj[F("rst")] = mCfg.sys.eth.pinRst; + #endif } else { #if !defined(ETHERNET) getChar(obj, F("ssid"), mCfg.sys.stationSsid, SSID_LEN); @@ -823,6 +866,16 @@ class settings { if(mCfg.sys.protectionMask == 0) mCfg.sys.protectionMask = DEF_PROT_INDEX | DEF_PROT_LIVE | DEF_PROT_SERIAL | DEF_PROT_SETUP | DEF_PROT_UPDATE | DEF_PROT_SYSTEM | DEF_PROT_API | DEF_PROT_MQTT | DEF_PROT_HISTORY; + + #if defined(ETHERNET) + getVal(obj, F("en"), &mCfg.sys.eth.enabled); + getVal(obj, F("cs"), &mCfg.sys.eth.pinCs); + getVal(obj, F("sclk"), &mCfg.sys.eth.pinSclk); + getVal(obj, F("miso"), &mCfg.sys.eth.pinMiso); + getVal(obj, F("mosi"), &mCfg.sys.eth.pinMosi); + getVal(obj, F("irq"), &mCfg.sys.eth.pinIrq); + getVal(obj, F("rst"), &mCfg.sys.eth.pinRst); + #endif } } diff --git a/src/defines.h b/src/defines.h index 6a92fbe9..43fc63b0 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,8 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 970010 - +#define VERSION_PATCH 1030001 //------------------------------------- typedef struct { uint8_t ch; diff --git a/src/eth/ahoyeth.cpp b/src/eth/ahoyeth.cpp deleted file mode 100644 index 83f0aef0..00000000 --- a/src/eth/ahoyeth.cpp +++ /dev/null @@ -1,179 +0,0 @@ -//----------------------------------------------------------------------------- -// 2023 Ahoy, https://www.mikrocontroller.net/topic/525778 -// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/ -//----------------------------------------------------------------------------- - -#if defined(ETHERNET) - -#if defined(ESP32) && defined(F) - #undef F - #define F(sl) (sl) -#endif -#include "ahoyeth.h" -#include - -//----------------------------------------------------------------------------- -ahoyeth::ahoyeth() -{ - // WiFi.onEvent(ESP32_W5500_event); -} - - -//----------------------------------------------------------------------------- -void ahoyeth::setup(settings_t *config, uint32_t *utcTimestamp, OnNetworkCB onNetworkCB, OnTimeCB onTimeCB) { - mConfig = config; - mUtcTimestamp = utcTimestamp; - mOnNetworkCB = onNetworkCB; - mOnTimeCB = onTimeCB; - mEthConnected = false; - - Serial.flush(); - WiFi.onEvent([this](WiFiEvent_t event, arduino_event_info_t info) -> void { this->onEthernetEvent(event, info); }); - - Serial.flush(); - mEthSpi.begin(DEF_ETH_MISO_PIN, DEF_ETH_MOSI_PIN, DEF_ETH_SCK_PIN, DEF_ETH_CS_PIN, DEF_ETH_IRQ_PIN, DEF_ETH_RST_PIN); - - if(mConfig->sys.ip.ip[0] != 0) { - IPAddress ip(mConfig->sys.ip.ip); - IPAddress mask(mConfig->sys.ip.mask); - IPAddress dns1(mConfig->sys.ip.dns1); - IPAddress dns2(mConfig->sys.ip.dns2); - IPAddress gateway(mConfig->sys.ip.gateway); - if(!ETH.config(ip, gateway, mask, dns1, dns2)) - DPRINTLN(DBG_ERROR, F("failed to set static IP!")); - } -} - - -//----------------------------------------------------------------------------- -bool ahoyeth::updateNtpTime(void) { - if (!ETH.localIP()) - return false; - - DPRINTLN(DBG_DEBUG, F("updateNtpTime: checking udp \"connection\"...")); Serial.flush(); - if (!mUdp.connected()) { - DPRINTLN(DBG_DEBUG, F("updateNtpTime: About to (re)connect...")); Serial.flush(); - IPAddress timeServer; - if (!WiFi.hostByName(mConfig->ntp.addr, timeServer)) - return false; - - if (!mUdp.connect(timeServer, mConfig->ntp.port)) - return false; - - DPRINTLN(DBG_DEBUG, F("updateNtpTime: Connected...")); Serial.flush(); - mUdp.onPacket([this](AsyncUDPPacket packet) { - DPRINTLN(DBG_DEBUG, F("updateNtpTime: about to handle ntp packet...")); Serial.flush(); - this->handleNTPPacket(packet); - }); - } - - DPRINTLN(DBG_DEBUG, F("updateNtpTime: prepare packet...")); Serial.flush(); - - // set all bytes in the buffer to 0 - memset(mUdpPacketBuffer, 0, NTP_PACKET_SIZE); - // Initialize values needed to form NTP request - // (see URL above for details on the packets) - - mUdpPacketBuffer[0] = 0b11100011; // LI, Version, Mode - mUdpPacketBuffer[1] = 0; // Stratum, or type of clock - mUdpPacketBuffer[2] = 6; // Polling Interval - mUdpPacketBuffer[3] = 0xEC; // Peer Clock Precision - - // 8 bytes of zero for Root Delay & Root Dispersion - mUdpPacketBuffer[12] = 49; - mUdpPacketBuffer[13] = 0x4E; - mUdpPacketBuffer[14] = 49; - mUdpPacketBuffer[15] = 52; - - //Send unicast - DPRINTLN(DBG_DEBUG, F("updateNtpTime: send packet...")); Serial.flush(); - mUdp.write(mUdpPacketBuffer, sizeof(mUdpPacketBuffer)); - - return true; -} - -//----------------------------------------------------------------------------- -void ahoyeth::handleNTPPacket(AsyncUDPPacket packet) { - char buf[80]; - - memcpy(buf, packet.data(), sizeof(buf)); - - unsigned long highWord = word(buf[40], buf[41]); - unsigned long lowWord = word(buf[42], buf[43]); - - // combine the four bytes (two words) into a long integer - // this is NTP time (seconds since Jan 1 1900): - unsigned long secsSince1900 = highWord << 16 | lowWord; - - *mUtcTimestamp = secsSince1900 - 2208988800UL; // UTC time - DPRINTLN(DBG_INFO, "[NTP]: " + ah::getDateTimeStr(*mUtcTimestamp) + " UTC"); - mOnTimeCB(true); -} - -//----------------------------------------------------------------------------- -void ahoyeth::welcome(String ip, String mode) { - DBGPRINTLN(F("\n\n--------------------------------")); - DBGPRINTLN(F("Welcome to AHOY!")); - DBGPRINT(F("\npoint your browser to http://")); - DBGPRINT(ip); - DBGPRINTLN(mode); - DBGPRINTLN(F("to configure your device")); - DBGPRINTLN(F("--------------------------------\n")); -} - -void ahoyeth::onEthernetEvent(WiFiEvent_t event, arduino_event_info_t info) { - DPRINTLN(DBG_VERBOSE, F("[ETH]: Got event...")); - switch (event) { - case ARDUINO_EVENT_ETH_START: - DPRINTLN(DBG_VERBOSE, F("ETH Started")); - - if(String(mConfig->sys.deviceName) != "") - ETH.setHostname(mConfig->sys.deviceName); - else - ETH.setHostname(F("ESP32_W5500")); - break; - - case ARDUINO_EVENT_ETH_CONNECTED: - DPRINTLN(DBG_VERBOSE, F("ETH Connected")); - break; - - case ARDUINO_EVENT_ETH_GOT_IP: - if (!mEthConnected) { - /*DPRINT(DBG_INFO, F("ETH MAC: ")); - DBGPRINT(mEthSpi.macAddress());*/ - welcome(ETH.localIP().toString(), F(" (Station)")); - - mEthConnected = true; - mOnNetworkCB(true); - } - - if (!MDNS.begin(mConfig->sys.deviceName)) { - DPRINTLN(DBG_ERROR, F("Error setting up MDNS responder!")); - } else { - DBGPRINT(F("mDNS established: ")); - DBGPRINT(mConfig->sys.deviceName); - DBGPRINTLN(F(".local")); - } - break; - - case ARDUINO_EVENT_ETH_DISCONNECTED: - DPRINTLN(DBG_INFO, F("ETH Disconnected")); - mEthConnected = false; - mUdp.close(); - mOnNetworkCB(false); - break; - - case ARDUINO_EVENT_ETH_STOP: - DPRINTLN(DBG_INFO, F("ETH Stopped")); - mEthConnected = false; - mUdp.close(); - mOnNetworkCB(false); - break; - - default: - break; - } - -} - -#endif /* defined(ETHERNET) */ diff --git a/src/eth/ahoyeth.h b/src/eth/ahoyeth.h deleted file mode 100644 index 557db5ec..00000000 --- a/src/eth/ahoyeth.h +++ /dev/null @@ -1,65 +0,0 @@ -//----------------------------------------------------------------------------- -// 2024 Ahoy, https://github.com/lumpapu/ahoy -// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/4.0/deed -//----------------------------------------------------------------------------- - -#if defined(ETHERNET) -#ifndef __AHOYETH_H__ -#define __AHOYETH_H__ - -#include - -#include "../utils/dbg.h" -#include -#include -#include - -#include "ethSpi.h" -#include -#include "../utils/dbg.h" -#include "../config/config.h" -#include "../config/settings.h" - - -class app; - -#define NTP_PACKET_SIZE 48 - -class ahoyeth { - public: /* types */ - typedef std::function OnNetworkCB; - typedef std::function OnTimeCB; - - public: - ahoyeth(); - - void setup(settings_t *config, uint32_t *utcTimestamp, OnNetworkCB onNetworkCB, OnTimeCB onTimeCB); - bool updateNtpTime(void); - - private: - void setupEthernet(); - - void handleNTPPacket(AsyncUDPPacket packet); - - void welcome(String ip, String mode); - - void onEthernetEvent(WiFiEvent_t event, arduino_event_info_t info); - - private: - //#if defined(CONFIG_IDF_TARGET_ESP32S3) - EthSpi mEthSpi; - //#endif - settings_t *mConfig = nullptr; - - uint32_t *mUtcTimestamp; - AsyncUDP mUdp; // for time server - byte mUdpPacketBuffer[NTP_PACKET_SIZE]; // buffer to hold incoming and outgoing packets - - OnNetworkCB mOnNetworkCB; - OnTimeCB mOnTimeCB; - bool mEthConnected; - -}; - -#endif /*__AHOYETH_H__*/ -#endif /* defined(ETHERNET) */ diff --git a/src/hm/nrfHal.h b/src/hm/nrfHal.h index b9265626..89fe0885 100644 --- a/src/hm/nrfHal.h +++ b/src/hm/nrfHal.h @@ -11,7 +11,7 @@ #include "../utils/spiPatcher.h" #include -#include +#include #define NRF_MAX_TRANSFER_SZ 64 #define NRF_DEFAULT_SPI_SPEED 10000000 // 10 MHz diff --git a/src/hms/hmsRadio.h b/src/hms/hmsRadio.h index d074442b..54975197 100644 --- a/src/hms/hmsRadio.h +++ b/src/hms/hmsRadio.h @@ -183,7 +183,7 @@ class CmtRadio : public Radio { if(p.packet[9] > ALL_FRAMES) { // indicates last frame 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? } } diff --git a/src/network/AhoyEthernet.h b/src/network/AhoyEthernet.h new file mode 100644 index 00000000..db624a41 --- /dev/null +++ b/src/network/AhoyEthernet.h @@ -0,0 +1,70 @@ +//----------------------------------------------------------------------------- +// 2024 Ahoy, https://ahoydtu.de +// Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed +//----------------------------------------------------------------------------- + +#ifndef __AHOY_ETHERNET_H__ +#define __AHOY_ETHERNET_H__ + +#if defined(ETHERNET) +#include +#include +#include +#include "AhoyEthernetSpi.h" +#include "AhoyNetwork.h" + +class AhoyEthernet : public AhoyNetwork { + public: + void begin() override { + mAp.enable(); + + if(!mConfig->sys.eth.enabled) + return; + + mEthSpi.begin(mConfig->sys.eth.pinMiso, mConfig->sys.eth.pinMosi, mConfig->sys.eth.pinSclk, mConfig->sys.eth.pinCs, mConfig->sys.eth.pinIrq, mConfig->sys.eth.pinRst); + ETH.setHostname(mConfig->sys.deviceName); + + // static IP + setupIp([this](IPAddress ip, IPAddress gateway, IPAddress mask, IPAddress dns1, IPAddress dns2) -> bool { + return ETH.config(ip, gateway, mask, dns1, dns2); + }); + } + + void tickNetworkLoop() override { + if(mAp.isEnabled()) + mAp.tickLoop(); + + switch(mStatus) { + case NetworkState::DISCONNECTED: + if(mConnected) { + mConnected = false; + mOnNetworkCB(false); + mAp.enable(); + } + break; + + case NetworkState::CONNECTED: + break; + + case NetworkState::GOT_IP: + if(!mConnected) { + mAp.disable(); + mConnected = true; + ah::welcome(ETH.localIP().toString(), F("Station")); + MDNS.begin(mConfig->sys.deviceName); + mOnNetworkCB(true); + } + break; + } + } + + String getIp(void) override { + return ETH.localIP().toString(); + } + + private: + AhoyEthernetSpi mEthSpi; +}; + +#endif /*ETHERNET*/ +#endif /*__AHOY_ETHERNET_H__*/ diff --git a/src/eth/ethSpi.h b/src/network/AhoyEthernetSpi.h similarity index 88% rename from src/eth/ethSpi.h rename to src/network/AhoyEthernetSpi.h index 1339c8ec..b41431b4 100644 --- a/src/eth/ethSpi.h +++ b/src/network/AhoyEthernetSpi.h @@ -1,6 +1,6 @@ //----------------------------------------------------------------------------- -// 2024 Ahoy, https://www.mikrocontroller.net/topic/525778 -// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/ +// 2024 Ahoy, https://ahoydtu.de +// Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed //----------------------------------------------------------------------------- #if defined(ETHERNET) @@ -18,17 +18,19 @@ void tcpipInit(); void add_esp_interface_netif(esp_interface_t interface, esp_netif_t* esp_netif); -class EthSpi { +class AhoyEthernetSpi { public: - EthSpi() : + AhoyEthernetSpi() : eth_handle(nullptr), eth_netif(nullptr) {} void begin(int8_t pin_miso, int8_t pin_mosi, int8_t pin_sclk, int8_t pin_cs, int8_t pin_int, int8_t pin_rst) { - gpio_reset_pin(static_cast(pin_rst)); - gpio_set_direction(static_cast(pin_rst), GPIO_MODE_OUTPUT); - gpio_set_level(static_cast(pin_rst), 0); + if(-1 != pin_rst) { + gpio_reset_pin(static_cast(pin_rst)); + gpio_set_direction(static_cast(pin_rst), GPIO_MODE_OUTPUT); + gpio_set_level(static_cast(pin_rst), 0); + } gpio_reset_pin(static_cast(pin_sclk)); gpio_reset_pin(static_cast(pin_mosi)); @@ -42,6 +44,7 @@ class EthSpi { gpio_reset_pin(static_cast(pin_int)); gpio_set_pull_mode(static_cast(pin_int), GPIO_PULLUP_ONLY); + spi_bus_config_t buscfg = { .mosi_io_num = pin_mosi, .miso_io_num = pin_miso, @@ -80,9 +83,11 @@ class EthSpi { ESP_ERROR_CHECK(spi_bus_add_device(SPI3_HOST, &devcfg, &spi)); // Reset sequence - delayMicroseconds(500); - gpio_set_level(static_cast(pin_rst), 1); - delayMicroseconds(1000); + if(-1 != pin_rst) { + delayMicroseconds(500); + gpio_set_level(static_cast(pin_rst), 1); + delayMicroseconds(1000); + } // Arduino function to start networking stack if not already started tcpipInit(); diff --git a/src/network/AhoyNetwork.h b/src/network/AhoyNetwork.h new file mode 100644 index 00000000..55c5d193 --- /dev/null +++ b/src/network/AhoyNetwork.h @@ -0,0 +1,246 @@ +//----------------------------------------------------------------------------- +// 2024 Ahoy, https://ahoydtu.de +// Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed +//----------------------------------------------------------------------------- + +#ifndef __AHOY_NETWORK_H__ +#define __AHOY_NETWORK_H__ + +#include "AhoyNetworkHelper.h" +#include "../config/settings.h" +#include "../utils/helper.h" +#include "AhoyWifiAp.h" +#include "AsyncJson.h" + +#define NTP_PACKET_SIZE 48 + +class AhoyNetwork { + public: + typedef std::function OnNetworkCB; + typedef std::function OnTimeCB; + + public: + void setup(settings_t *config, uint32_t *utcTimestamp, OnNetworkCB onNetworkCB, OnTimeCB onTimeCB) { + mConfig = config; + mUtcTimestamp = utcTimestamp; + mOnNetworkCB = onNetworkCB; + mOnTimeCB = onTimeCB; + + if('\0' == mConfig->sys.deviceName[0]) + snprintf(mConfig->sys.deviceName, DEVNAME_LEN, "%s", DEF_DEVICE_NAME); + WiFi.hostname(mConfig->sys.deviceName); + + mAp.setup(&mConfig->sys); + + #if defined(ESP32) + WiFi.onEvent([this](WiFiEvent_t event, arduino_event_info_t info) -> void { + OnEvent(event); + }); + #else + wifiConnectHandler = WiFi.onStationModeConnected( + [this](const WiFiEventStationModeConnected& event) -> void { + OnEvent((WiFiEvent_t)SYSTEM_EVENT_STA_CONNECTED); + }); + wifiGotIPHandler = WiFi.onStationModeGotIP( + [this](const WiFiEventStationModeGotIP& event) -> void { + OnEvent((WiFiEvent_t)SYSTEM_EVENT_STA_GOT_IP); + }); + wifiDisconnectHandler = WiFi.onStationModeDisconnected( + [this](const WiFiEventStationModeDisconnected& event) -> void { + OnEvent((WiFiEvent_t)SYSTEM_EVENT_STA_DISCONNECTED); + }); + #endif + } + + bool isConnected() const { + return (mStatus == NetworkState::CONNECTED); + } + + bool updateNtpTime(void) { + if(NetworkState::GOT_IP != mStatus) + return false; + + if (!mUdp.connected()) { + IPAddress timeServer; + if (!WiFi.hostByName(mConfig->ntp.addr, timeServer)) + return false; + if (!mUdp.connect(timeServer, mConfig->ntp.port)) + return false; + } + + mUdp.onPacket([this](AsyncUDPPacket packet) { + this->handleNTPPacket(packet); + }); + sendNTPpacket(); + + return true; + } + + public: + virtual void begin() = 0; + virtual void tickNetworkLoop() = 0; + virtual String getIp(void) = 0; + + virtual bool getWasInCh12to14() { + return false; + } + + bool isApActive() { + return mAp.isEnabled(); + } + + #if !defined(ETHERNET) + bool getAvailNetworks(JsonObject obj) { + JsonArray nets = obj.createNestedArray(F("networks")); + + if(!mScanActive) { + mScanActive = true; + if(NetworkState::GOT_IP != mStatus) + WiFi.disconnect(); + WiFi.scanNetworks(true, true); + return false; + } + + int n = WiFi.scanComplete(); + if (WIFI_SCAN_RUNNING == n) + return false; + + if(n > 0) { + int sort[n]; + sortRSSI(&sort[0], n); + for (int i = 0; i < n; ++i) { + nets[i][F("ssid")] = WiFi.SSID(sort[i]); + nets[i][F("rssi")] = WiFi.RSSI(sort[i]); + } + } + mScanActive = false; + WiFi.scanDelete(); + + return true; + } + #endif + + protected: + void setupIp(std::function cb) { + if(mConfig->sys.ip.ip[0] != 0) { + IPAddress ip(mConfig->sys.ip.ip); + IPAddress mask(mConfig->sys.ip.mask); + IPAddress dns1(mConfig->sys.ip.dns1); + IPAddress dns2(mConfig->sys.ip.dns2); + IPAddress gateway(mConfig->sys.ip.gateway); + if(cb(ip, gateway, mask, dns1, dns2)) + DPRINTLN(DBG_ERROR, F("failed to set static IP!")); + } + } + + void OnEvent(WiFiEvent_t event) { + switch(event) { + case SYSTEM_EVENT_STA_CONNECTED: + [[fallthrough]]; + case ARDUINO_EVENT_ETH_CONNECTED: + if(NetworkState::CONNECTED != mStatus) { + mStatus = NetworkState::CONNECTED; + DPRINTLN(DBG_INFO, F("Network connected")); + } + break; + + case SYSTEM_EVENT_STA_GOT_IP: + [[fallthrough]]; + case ARDUINO_EVENT_ETH_GOT_IP: + mStatus = NetworkState::GOT_IP; + break; + + case ARDUINO_EVENT_WIFI_STA_LOST_IP: + [[fallthrough]]; + case ARDUINO_EVENT_WIFI_STA_STOP: + [[fallthrough]]; + case SYSTEM_EVENT_STA_DISCONNECTED: + [[fallthrough]]; + case ARDUINO_EVENT_ETH_STOP: + [[fallthrough]]; + case ARDUINO_EVENT_ETH_DISCONNECTED: + mStatus = NetworkState::DISCONNECTED; + break; + + default: + break; + } + } + + #if !defined(ETHERNET) + 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 + + private: + void sendNTPpacket(void) { + uint8_t buf[NTP_PACKET_SIZE]; + memset(buf, 0, NTP_PACKET_SIZE); + + buf[0] = 0b11100011; // LI, Version, Mode + buf[1] = 0; // Stratum + buf[2] = 6; // Max Interval between messages in seconds + buf[3] = 0xEC; // Clock Precision + // bytes 4 - 11 are for Root Delay and Dispersion and were set to 0 by memset + buf[12] = 49; // four-byte reference ID identifying + buf[13] = 0x4E; + buf[14] = 49; + buf[15] = 52; + + mUdp.write(buf, NTP_PACKET_SIZE); + } + + void handleNTPPacket(AsyncUDPPacket packet) { + char buf[80]; + + memcpy(buf, packet.data(), sizeof(buf)); + + unsigned long highWord = word(buf[40], buf[41]); + unsigned long lowWord = word(buf[42], buf[43]); + + // combine the four bytes (two words) into a long integer + // this is NTP time (seconds since Jan 1 1900): + unsigned long secsSince1900 = highWord << 16 | lowWord; + + *mUtcTimestamp = secsSince1900 - 2208988800UL; // UTC time + DPRINTLN(DBG_INFO, "[NTP]: " + ah::getDateTimeStr(*mUtcTimestamp) + " UTC"); + mOnTimeCB(true); + mUdp.close(); + } + + protected: + enum class NetworkState : uint8_t { + DISCONNECTED, + CONNECTED, + GOT_IP, + SCAN_READY, // ESP8266 + CONNECTING // ESP8266 + }; + + protected: + settings_t *mConfig = nullptr; + uint32_t *mUtcTimestamp = nullptr; + bool mConnected = false; + bool mScanActive = false; + + OnNetworkCB mOnNetworkCB; + OnTimeCB mOnTimeCB; + + NetworkState mStatus = NetworkState::DISCONNECTED; + + AhoyWifiAp mAp; + DNSServer mDns; + + AsyncUDP mUdp; // for time server + #if defined(ESP8266) + WiFiEventHandler wifiConnectHandler, wifiDisconnectHandler, wifiGotIPHandler; + #endif +}; + +#endif /*__AHOY_NETWORK_H__*/ diff --git a/src/network/AhoyNetworkHelper.cpp b/src/network/AhoyNetworkHelper.cpp new file mode 100644 index 00000000..09678023 --- /dev/null +++ b/src/network/AhoyNetworkHelper.cpp @@ -0,0 +1,20 @@ +//----------------------------------------------------------------------------- +// 2024 Ahoy, https://ahoydtu.de +// Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed +//----------------------------------------------------------------------------- + +#include "AhoyNetworkHelper.h" + +namespace ah { + void welcome(String ip, String info) { + DBGPRINTLN(F("\n\n-------------------")); + DBGPRINTLN(F("Welcome to AHOY!")); + DBGPRINT(F("\npoint your browser to http://")); + DBGPRINT(ip); + DBGPRINT(" ("); + DBGPRINT(info); + DBGPRINTLN(")"); + DBGPRINTLN(F("to configure your device")); + DBGPRINTLN(F("-------------------\n")); + } +} diff --git a/src/network/AhoyNetworkHelper.h b/src/network/AhoyNetworkHelper.h new file mode 100644 index 00000000..378ba033 --- /dev/null +++ b/src/network/AhoyNetworkHelper.h @@ -0,0 +1,39 @@ +//----------------------------------------------------------------------------- +// 2024 Ahoy, https://ahoydtu.de +// Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed +//----------------------------------------------------------------------------- + +#ifndef __AHOY_NETWORK_HELPER_H__ +#define __AHOY_NETWORK_HELPER_H__ + +#include "../utils/dbg.h" +#include +#if defined(ESP32) + #include "ESPAsyncWebServer.h" + #include + #include +#else + #include + #include + //#include + #include "ESPAsyncUDP.h" + + enum { + SYSTEM_EVENT_STA_CONNECTED = 1, + ARDUINO_EVENT_ETH_CONNECTED, + SYSTEM_EVENT_STA_GOT_IP, + ARDUINO_EVENT_ETH_GOT_IP, + ARDUINO_EVENT_WIFI_STA_LOST_IP, + ARDUINO_EVENT_WIFI_STA_STOP, + SYSTEM_EVENT_STA_DISCONNECTED, + ARDUINO_EVENT_ETH_STOP, + ARDUINO_EVENT_ETH_DISCONNECTED + }; +#endif +#include + +namespace ah { + void welcome(String ip, String info); +} + +#endif /*__AHOY_NETWORK_HELPER_H__*/ diff --git a/src/network/AhoyWifiAp.h b/src/network/AhoyWifiAp.h new file mode 100644 index 00000000..ce2bbd1b --- /dev/null +++ b/src/network/AhoyWifiAp.h @@ -0,0 +1,83 @@ +//----------------------------------------------------------------------------- +// 2024 Ahoy, https://ahoydtu.de +// Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed +//----------------------------------------------------------------------------- + +#ifndef __AHOY_WIFI_AP_H__ +#define __AHOY_WIFI_AP_H__ + +#include "../utils/dbg.h" +#include +#include "../config/settings.h" +#include "AhoyNetworkHelper.h" + +class AhoyWifiAp { + public: + AhoyWifiAp() : mIp(192, 168, 4, 1) {} + + void setup(cfgSys_t *cfg) { + mCfg = cfg; + } + + void tickLoop() { + if(mEnabled) + mDns.processNextRequest(); + + if (WiFi.softAPgetStationNum() != mLast) { + mLast = WiFi.softAPgetStationNum(); + if(mLast > 0) + DBGPRINTLN(F("AP client connected")); + } + } + + void enable() { + if(mEnabled) + return; + + 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); + + mDns.start(53, "*", mIp); + + mEnabled = true; + tickLoop(); + } + + void disable() { + if(!mEnabled) + return; + + if(WiFi.softAPgetStationNum() > 0) + return; + + mDns.stop(); + WiFi.softAPdisconnect(); + #if defined(ETHERNET) + WiFi.mode(WIFI_OFF); + #else + WiFi.mode(WIFI_STA); + #endif + + mEnabled = false; + } + + bool isEnabled() const { + return mEnabled; + } + + private: + cfgSys_t *mCfg = nullptr; + DNSServer mDns; + IPAddress mIp; + bool mEnabled = false; + uint8_t mLast = 0; +}; + +#endif /*__AHOY_WIFI_AP_H__*/ diff --git a/src/network/AhoyWifiEsp32.h b/src/network/AhoyWifiEsp32.h new file mode 100644 index 00000000..a3bbb9cf --- /dev/null +++ b/src/network/AhoyWifiEsp32.h @@ -0,0 +1,74 @@ +//----------------------------------------------------------------------------- +// 2024 Ahoy, https://ahoydtu.de +// Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed +//----------------------------------------------------------------------------- + +#ifndef __AHOY_WIFI_ESP32_H__ +#define __AHOY_WIFI_ESP32_H__ + +#if defined(ESP32) && !defined(ETHERNET) +#include +#include +#include "AhoyNetwork.h" +#include "ESPAsyncWebServer.h" + +class AhoyWifi : public AhoyNetwork { + public: + void begin() override { + mAp.enable(); + + // static IP + setupIp([this](IPAddress ip, IPAddress gateway, IPAddress mask, IPAddress dns1, IPAddress dns2) -> bool { + return WiFi.config(ip, gateway, mask, dns1, dns2); + }); + + WiFi.setHostname(mConfig->sys.deviceName); + #if !defined(AP_ONLY) + WiFi.setScanMethod(WIFI_ALL_CHANNEL_SCAN); + WiFi.setSortMethod(WIFI_CONNECT_AP_BY_SIGNAL); + WiFi.begin(mConfig->sys.stationSsid, mConfig->sys.stationPwd, WIFI_ALL_CHANNEL_SCAN); + + DBGPRINT(F("connect to network '")); + DBGPRINT(mConfig->sys.stationSsid); + #endif + } + + void tickNetworkLoop() override { + if(mAp.isEnabled()) + mAp.tickLoop(); + + switch(mStatus) { + case NetworkState::DISCONNECTED: + if(mConnected) { + mConnected = false; + mOnNetworkCB(false); + mAp.enable(); + MDNS.end(); + } + break; + + case NetworkState::CONNECTED: + break; + + case NetworkState::GOT_IP: + if(mAp.isEnabled()) + mAp.disable(); + + if(!mConnected) { + mConnected = true; + ah::welcome(WiFi.localIP().toString(), F("Station")); + MDNS.begin(mConfig->sys.deviceName); + MDNS.addServiceTxt("http", "tcp", "path", "/"); + mOnNetworkCB(true); + } + break; + } + } + + String getIp(void) override { + return WiFi.localIP().toString(); + } +}; + +#endif /*ESP32 & !ETHERNET*/ +#endif /*__AHOY_WIFI_ESP32_H__*/ diff --git a/src/network/AhoyWifiEsp8266.h b/src/network/AhoyWifiEsp8266.h new file mode 100644 index 00000000..2497448b --- /dev/null +++ b/src/network/AhoyWifiEsp8266.h @@ -0,0 +1,161 @@ +//----------------------------------------------------------------------------- +// 2024 Ahoy, https://ahoydtu.de +// Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed +//----------------------------------------------------------------------------- + +#ifndef __AHOY_WIFI_ESP8266_H__ +#define __AHOY_WIFI_ESP8266_H__ + +#if defined(ESP8266) +#include +#include +#include +#include "AhoyNetwork.h" +#include "ESPAsyncWebServer.h" + +class AhoyWifi : public AhoyNetwork { + public: + void begin() override { + mAp.enable(); + + // static IP + setupIp([this](IPAddress ip, IPAddress gateway, IPAddress mask, IPAddress dns1, IPAddress dns2) -> bool { + return WiFi.config(ip, gateway, mask, dns1, dns2); + }); + + WiFi.setHostname(mConfig->sys.deviceName); + mBSSIDList.clear(); + } + + void tickNetworkLoop() override { + if(mAp.isEnabled()) + mAp.tickLoop(); + + mCnt++; + + switch(mStatus) { + case NetworkState::DISCONNECTED: + if(mConnected) { + mConnected = false; + mOnNetworkCB(false); + mAp.enable(); + MDNS.end(); + } + + if (WiFi.softAPgetStationNum() > 0) { + DBGPRINTLN(F("AP client connected")); + } + #if !defined(AP_ONLY) + else if (!mScanActive) { + DBGPRINT(F("scanning APs with SSID ")); + DBGPRINTLN(String(mConfig->sys.stationSsid)); + mScanCnt = 0; + mCnt = 0; + mScanActive = true; + WiFi.scanNetworks(true, true, 0U, ([this]() { + if (mConfig->sys.isHidden) + return (uint8_t*)NULL; + return (uint8_t*)(mConfig->sys.stationSsid); + })()); + } else if(getBSSIDs()) { + mStatus = NetworkState::SCAN_READY; + DBGPRINT(F("connect to network '")); Serial.flush(); + DBGPRINTLN(mConfig->sys.stationSsid); + } + #endif + break; + + case NetworkState::SCAN_READY: + mStatus = NetworkState::CONNECTING; + DBGPRINT(F("try to connect to BSSID:")); + uint8_t bssid[6]; + for (int j = 0; j < 6; j++) { + bssid[j] = mBSSIDList.front(); + mBSSIDList.pop_front(); + DBGPRINT(" " + String(bssid[j], HEX)); + } + DBGPRINTLN(""); + WiFi.begin(mConfig->sys.stationSsid, mConfig->sys.stationPwd, 0, &bssid[0]); + break; + + case NetworkState::CONNECTING: + if (isTimeout(TIMEOUT)) { + WiFi.disconnect(); + mStatus = mBSSIDList.empty() ? NetworkState::DISCONNECTED : NetworkState::SCAN_READY; + } + break; + + case NetworkState::CONNECTED: + break; + + case NetworkState::GOT_IP: + if(!mConnected) { + mAp.disable(); + mConnected = true; + ah::welcome(WiFi.localIP().toString(), F("Station")); + MDNS.begin(mConfig->sys.deviceName); + MDNSResponder::hMDNSService hRes = MDNS.addService(NULL, "http", "tcp", 80); + MDNS.addServiceTxt(hRes, "path", "/"); + MDNS.announce(); + mOnNetworkCB(true); + } + + MDNS.update(); + + if(WiFi.channel() > 11) + mWasInCh12to14 = true; + break; + } + } + + String getIp(void) override { + return WiFi.localIP().toString(); + } + + bool getWasInCh12to14() override { + return mWasInCh12to14; + } + + private: + bool getBSSIDs() { + bool result = false; + int n = WiFi.scanComplete(); + if (n < 0) { + if (++mScanCnt < 20) + return false; + } + if(n > 0) { + mBSSIDList.clear(); + int sort[n]; + sortRSSI(&sort[0], n); + for (int i = 0; i < n; i++) { + DBGPRINT("BSSID " + String(i) + ":"); + uint8_t *bssid = WiFi.BSSID(sort[i]); + for (int j = 0; j < 6; j++){ + DBGPRINT(" " + String(bssid[j], HEX)); + mBSSIDList.push_back(bssid[j]); + } + DBGPRINTLN(""); + } + result = true; + } + mScanActive = false; + WiFi.scanDelete(); + return result; + } + + bool isTimeout(uint8_t timeout) { + return ((mCnt % timeout) == 0); + } + + private: + uint8_t mCnt = 0; + uint8_t mScanCnt = 0; + std::list mBSSIDList; + bool mWasInCh12to14 = false; + static constexpr uint8_t TIMEOUT = 20; + static constexpr uint8_t SCAN_TIMEOUT = 10; +}; + +#endif /*ESP8266*/ +#endif /*__AHOY_WIFI_ESP8266_H__*/ diff --git a/src/platformio.ini b/src/platformio.ini index 34a40c21..0a029729 100644 --- a/src/platformio.ini +++ b/src/platformio.ini @@ -33,6 +33,7 @@ lib_deps = https://github.com/JChristensen/Timezone @ ^1.2.4 olikraus/U8g2 @ ^2.35.9 https://github.com/zinggjm/GxEPD2#1.5.3 + build_flags = -std=c++17 -std=gnu++17 @@ -40,14 +41,27 @@ build_unflags = -std=gnu++11 +[env:esp8266-minimal] +platform = espressif8266 +board = esp12e +board_build.f_cpu = 80000000L +lib_deps = + ${env.lib_deps} + https://github.com/me-no-dev/ESPAsyncUDP +build_flags = ${env.build_flags} + -DEMC_MIN_FREE_MEMORY=4096 + ;-Wl,-Map,output.map +monitor_filters = + esp8266_exception_decoder + [env:esp8266] platform = espressif8266 board = esp12e board_build.f_cpu = 80000000L -build_flags = ${env.build_flags} - -DEMC_MIN_FREE_MEMORY=4096 +lib_deps = ${env:esp8266-minimal.lib_deps} + https://github.com/me-no-dev/ESPAsyncUDP +build_flags = ${env:esp8266-minimal.build_flags} -DENABLE_MQTT - ;-Wl,-Map,output.map monitor_filters = esp8266_exception_decoder @@ -55,11 +69,9 @@ monitor_filters = platform = espressif8266 board = esp12e board_build.f_cpu = 80000000L -build_flags = ${env.build_flags} - -DEMC_MIN_FREE_MEMORY=4096 +lib_deps = ${env:esp8266.lib_deps} +build_flags = ${env:esp8266.build_flags} -DLANG_DE - -DENABLE_MQTT - ;-Wl,-Map,output.map monitor_filters = esp8266_exception_decoder @@ -67,12 +79,10 @@ monitor_filters = platform = espressif8266 board = esp12e board_build.f_cpu = 80000000L -build_flags = ${env.build_flags} - -DEMC_MIN_FREE_MEMORY=4096 - -DENABLE_MQTT +lib_deps = ${env:esp8266.lib_deps} +build_flags = ${env:esp8266.build_flags} -DPLUGIN_DISPLAY -DENABLE_HISTORY - ;-Wl,-Map,output.map monitor_filters = esp8266_exception_decoder @@ -80,13 +90,9 @@ monitor_filters = platform = espressif8266 board = esp12e board_build.f_cpu = 80000000L -build_flags = ${env.build_flags} - -DEMC_MIN_FREE_MEMORY=4096 +lib_deps = ${env:esp8266.lib_deps} +build_flags = ${env:esp8266-all.build_flags} -DLANG_DE - -DENABLE_MQTT - -DPLUGIN_DISPLAY - -DENABLE_HISTORY - ;-Wl,-Map,output.map monitor_filters = esp8266_exception_decoder @@ -94,12 +100,9 @@ monitor_filters = platform = espressif8266 board = esp12e board_build.f_cpu = 80000000L -build_flags = ${env.build_flags} - -DEMC_MIN_FREE_MEMORY=4096 +lib_deps = ${env:esp8266.lib_deps} +build_flags = ${env:esp8266-all.build_flags} -DENABLE_PROMETHEUS_EP - -DENABLE_MQTT - -DPLUGIN_DISPLAY - -DENABLE_HISTORY monitor_filters = esp8266_exception_decoder @@ -107,23 +110,9 @@ monitor_filters = platform = espressif8266 board = esp12e board_build.f_cpu = 80000000L -build_flags = ${env.build_flags} - -DEMC_MIN_FREE_MEMORY=4096 - -DENABLE_PROMETHEUS_EP +lib_deps = ${env:esp8266.lib_deps} +build_flags = ${env:esp8266-prometheus.build_flags} -DLANG_DE - -DENABLE_MQTT - -DPLUGIN_DISPLAY - -DENABLE_HISTORY -monitor_filters = - esp8266_exception_decoder - -[env:esp8266-minimal] -platform = espressif8266 -board = esp12e -board_build.f_cpu = 80000000L -build_flags = ${env.build_flags} - -DEMC_MIN_FREE_MEMORY=4096 - ;-Wl,-Map,output.map monitor_filters = esp8266_exception_decoder @@ -134,6 +123,7 @@ platform = espressif8266 board = esp8285 board_build.ldscript = eagle.flash.1m64.ld board_build.f_cpu = 80000000L +lib_deps = ${env:esp8266.lib_deps} build_flags = ${env.build_flags} -DEMC_MIN_FREE_MEMORY=4096 -DENABLE_MQTT @@ -147,6 +137,7 @@ platform = espressif8266 board = esp8285 board_build.ldscript = eagle.flash.1m64.ld board_build.f_cpu = 80000000L +lib_deps = ${env:esp8266.lib_deps} build_flags = ${env.build_flags} -DEMC_MIN_FREE_MEMORY=4096 -DLANG_DE @@ -156,17 +147,6 @@ build_flags = ${env.build_flags} monitor_filters = esp8266_exception_decoder -[env:esp32-wroom32] -platform = espressif32@6.5.0 -board = lolin_d32 -build_flags = ${env.build_flags} - -DUSE_HSPI_FOR_EPD - -DENABLE_MQTT - -DPLUGIN_DISPLAY - -DENABLE_HISTORY -monitor_filters = - esp32_exception_decoder - [env:esp32-wroom32-minimal] platform = espressif32@6.5.0 board = lolin_d32 @@ -175,14 +155,21 @@ build_flags = ${env.build_flags} monitor_filters = esp32_exception_decoder -[env:esp32-wroom32-de] +[env:esp32-wroom32] platform = espressif32@6.5.0 board = lolin_d32 -build_flags = ${env.build_flags} - -DUSE_HSPI_FOR_EPD +build_flags = ${env:esp32-wroom32-minimal.build_flags} -DENABLE_MQTT -DPLUGIN_DISPLAY -DENABLE_HISTORY + -DPLUGIN_ZEROEXPORT +monitor_filters = + esp32_exception_decoder + +[env:esp32-wroom32-de] +platform = espressif32@6.5.0 +board = lolin_d32 +build_flags = ${env:esp32-wroom32.build_flags} -DLANG_DE monitor_filters = esp32_exception_decoder @@ -190,38 +177,24 @@ monitor_filters = [env:esp32-wroom32-prometheus] platform = espressif32@6.5.0 board = lolin_d32 -build_flags = ${env.build_flags} - -DUSE_HSPI_FOR_EPD +build_flags = ${env:esp32-wroom32.build_flags} -DENABLE_PROMETHEUS_EP - -DENABLE_MQTT - -DPLUGIN_DISPLAY - -DENABLE_HISTORY monitor_filters = esp32_exception_decoder [env:esp32-wroom32-prometheus-de] platform = espressif32@6.5.0 board = lolin_d32 -build_flags = ${env.build_flags} - -DUSE_HSPI_FOR_EPD +build_flags = ${env:esp32-wroom32-prometheus.build_flags} -DLANG_DE - -DENABLE_PROMETHEUS_EP - -DENABLE_MQTT - -DPLUGIN_DISPLAY - -DENABLE_HISTORY monitor_filters = esp32_exception_decoder [env:esp32-wroom32-ethernet] platform = espressif32 board = lolin_d32 -build_flags = ${env.build_flags} +build_flags = ${env:esp32-wroom32.build_flags} -DETHERNET - -DRELEASE - -DUSE_HSPI_FOR_EPD - -DENABLE_MQTT - -DPLUGIN_DISPLAY - -DENABLE_HISTORY -DDEF_ETH_CS_PIN=15 -DDEF_ETH_SCK_PIN=14 -DDEF_ETH_MISO_PIN=12 @@ -240,26 +213,8 @@ monitor_filters = [env:esp32-wroom32-ethernet-de] platform = espressif32 board = lolin_d32 -build_flags = ${env.build_flags} - -DETHERNET - -DRELEASE - -DUSE_HSPI_FOR_EPD +build_flags = ${env:esp32-wroom32-ethernet.build_flags} -DLANG_DE - -DENABLE_MQTT - -DPLUGIN_DISPLAY - -DENABLE_HISTORY - -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=2 - -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 @@ -289,23 +244,7 @@ monitor_filters = [env:esp32-s2-mini-de] platform = espressif32@6.5.0 board = lolin_s2_mini -build_flags = ${env.build_flags} - -DUSE_HSPI_FOR_EPD - -DENABLE_MQTT - -DPLUGIN_DISPLAY - -DENABLE_HISTORY - -DPLUGIN_ZEROEXPORT - -DDEF_NRF_CS_PIN=12 - -DDEF_NRF_CE_PIN=3 - -DDEF_NRF_IRQ_PIN=5 - -DDEF_NRF_MISO_PIN=9 - -DDEF_NRF_MOSI_PIN=11 - -DDEF_NRF_SCLK_PIN=7 - -DDEF_CMT_CSB=16 - -DDEF_CMT_FCSB=18 - -DDEF_CMT_IRQ=33 - -DDEF_CMT_SDIO=35 - -DDEF_CMT_SCLK=37 +build_flags = ${env:esp32-s2-mini.build_flags} -DLANG_DE monitor_filters = esp32_exception_decoder @@ -318,6 +257,7 @@ build_flags = ${env.build_flags} -DENABLE_MQTT -DPLUGIN_DISPLAY -DENABLE_HISTORY + -DPLUGIN_ZEROEXPORT -DDEF_NRF_CS_PIN=5 -DDEF_NRF_CE_PIN=0 -DDEF_NRF_IRQ_PIN=1 @@ -335,85 +275,11 @@ monitor_filters = [env:esp32-c3-mini-de] platform = espressif32@6.5.0 board = lolin_c3_mini -build_flags = ${env.build_flags} - -DUSE_HSPI_FOR_EPD - -DENABLE_MQTT - -DPLUGIN_DISPLAY - -DENABLE_HISTORY - -DPLUGIN_ZEROEXPORT - -DDEF_NRF_CS_PIN=5 - -DDEF_NRF_CE_PIN=0 - -DDEF_NRF_IRQ_PIN=1 - -DDEF_NRF_MISO_PIN=3 - -DDEF_NRF_MOSI_PIN=4 - -DDEF_NRF_SCLK_PIN=2 - -DDEF_CMT_CSB=255 - -DDEF_CMT_FCSB=255 - -DDEF_CMT_IRQ=255 - -DDEF_CMT_SDIO=255 - -DDEF_CMT_SCLK=255 +build_flags = ${env:esp32-c3-mini.build_flags} -DLANG_DE monitor_filters = esp32_exception_decoder -[env:opendtufusion] -platform = espressif32@6.5.0 -board = esp32-s3-devkitc-1 -upload_protocol = esp-builtin -build_flags = ${env.build_flags} - -DENABLE_MQTT - -DPLUGIN_DISPLAY - -DENABLE_HISTORY - -DPLUGIN_ZEROEXPORT - -DSPI_HAL - -DDEF_NRF_CS_PIN=37 - -DDEF_NRF_CE_PIN=38 - -DDEF_NRF_IRQ_PIN=47 - -DDEF_NRF_MISO_PIN=48 - -DDEF_NRF_MOSI_PIN=35 - -DDEF_NRF_SCLK_PIN=36 - -DDEF_CMT_CSB=4 - -DDEF_CMT_FCSB=21 - -DDEF_CMT_IRQ=8 - -DDEF_CMT_SDIO=5 - -DDEF_CMT_SCLK=6 - -DDEF_LED0=18 - -DDEF_LED1=17 - -DLED_ACTIVE_HIGH - -DARDUINO_USB_MODE=1 - #-DARDUINO_USB_CDC_ON_BOOT=1 -monitor_filters = - esp32_exception_decoder, colorize - -[env:opendtufusion-de] -platform = espressif32@6.5.0 -board = esp32-s3-devkitc-1 -upload_protocol = esp-builtin -build_flags = ${env.build_flags} - -DLANG_DE - -DENABLE_MQTT - -DPLUGIN_DISPLAY - -DENABLE_HISTORY - -DPLUGIN_ZEROEXPORT - -DSPI_HAL - -DDEF_NRF_CS_PIN=37 - -DDEF_NRF_CE_PIN=38 - -DDEF_NRF_IRQ_PIN=47 - -DDEF_NRF_MISO_PIN=48 - -DDEF_NRF_MOSI_PIN=35 - -DDEF_NRF_SCLK_PIN=36 - -DDEF_CMT_CSB=4 - -DDEF_CMT_FCSB=21 - -DDEF_CMT_IRQ=8 - -DDEF_CMT_SDIO=5 - -DDEF_CMT_SCLK=6 - -DDEF_LED0=18 - -DDEF_LED1=17 - -DLED_ACTIVE_HIGH - -DARDUINO_USB_MODE=1 -monitor_filters = - esp32_exception_decoder, colorize - [env:opendtufusion-minimal] platform = espressif32@6.5.0 board = esp32-s3-devkitc-1 @@ -435,26 +301,37 @@ build_flags = ${env.build_flags} -DDEF_LED1=17 -DLED_ACTIVE_HIGH -DARDUINO_USB_MODE=1 + #-DARDUINO_USB_CDC_ON_BOOT=1 +monitor_filters = + esp32_exception_decoder, colorize + +[env:opendtufusion] +platform = espressif32@6.5.0 +board = esp32-s3-devkitc-1 +upload_protocol = esp-builtin +build_flags = ${env:opendtufusion-minimal.build_flags} + -DENABLE_MQTT + -DPLUGIN_DISPLAY + -DENABLE_HISTORY + -DPLUGIN_ZEROEXPORT +monitor_filters = + esp32_exception_decoder, colorize + +[env:opendtufusion-de] +platform = espressif32@6.5.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.5.0 board = esp32-s3-devkitc-1 -#lib_deps = -# khoih-prog/AsyncWebServer_ESP32_W5500 -# khoih-prog/AsyncUDP_ESP32_W5500 -# https://github.com/nrf24/RF24 @ ^1.4.8 -# paulstoffregen/Time @ ^1.6.1 -# https://github.com/bertmelis/espMqttClient#v1.6.0 -# bblanchon/ArduinoJson @ ^6.21.3 -# https://github.com/JChristensen/Timezone @ ^1.2.4 -# olikraus/U8g2 @ ^2.35.9 -# https://github.com/zinggjm/GxEPD2#1.5.3 upload_protocol = esp-builtin -build_flags = ${env.build_flags} +build_flags = ${env:opendtufusion-minimal.build_flags} -DETHERNET - -DSPI_HAL -DENABLE_MQTT -DPLUGIN_DISPLAY -DENABLE_HISTORY @@ -465,68 +342,15 @@ build_flags = ${env.build_flags} -DDEF_ETH_MOSI_PIN=40 -DDEF_ETH_IRQ_PIN=44 -DDEF_ETH_RST_PIN=43 - -DDEF_NRF_CS_PIN=37 - -DDEF_NRF_CE_PIN=38 - -DDEF_NRF_IRQ_PIN=47 - -DDEF_NRF_MISO_PIN=48 - -DDEF_NRF_MOSI_PIN=35 - -DDEF_NRF_SCLK_PIN=36 - -DDEF_CMT_CSB=4 - -DDEF_CMT_FCSB=21 - -DDEF_CMT_IRQ=8 - -DDEF_CMT_SDIO=5 - -DDEF_CMT_SCLK=6 - -DDEF_LED0=18 - -DDEF_LED1=17 - -DLED_ACTIVE_HIGH - -DARDUINO_USB_MODE=1 - #-DARDUINO_USB_CDC_ON_BOOT=1 + -DDEF_ETH_ENABLED monitor_filters = esp32_exception_decoder, colorize [env:opendtufusion-ethernet-de] platform = espressif32@6.5.0 board = esp32-s3-devkitc-1 -#lib_deps = -# khoih-prog/AsyncWebServer_ESP32_W5500 -# khoih-prog/AsyncUDP_ESP32_W5500 -# https://github.com/nrf24/RF24 @ ^1.4.8 -# paulstoffregen/Time @ ^1.6.1 -# https://github.com/bertmelis/espMqttClient#v1.6.0 -# bblanchon/ArduinoJson @ ^6.21.3 -# https://github.com/JChristensen/Timezone @ ^1.2.4 -# olikraus/U8g2 @ ^2.35.9 -# https://github.com/zinggjm/GxEPD2#1.5.3 upload_protocol = esp-builtin -build_flags = ${env.build_flags} - -DETHERNET - -DSPI_HAL +build_flags = ${env:opendtufusion-ethernet.build_flags} -DLANG_DE - -DENABLE_MQTT - -DPLUGIN_DISPLAY - -DENABLE_HISTORY - -DPLUGIN_ZEROEXPORT - -DDEF_ETH_CS_PIN=42 - -DDEF_ETH_SCK_PIN=39 - -DDEF_ETH_MISO_PIN=41 - -DDEF_ETH_MOSI_PIN=40 - -DDEF_ETH_IRQ_PIN=44 - -DDEF_ETH_RST_PIN=43 - -DDEF_NRF_CS_PIN=37 - -DDEF_NRF_CE_PIN=38 - -DDEF_NRF_IRQ_PIN=47 - -DDEF_NRF_MISO_PIN=48 - -DDEF_NRF_MOSI_PIN=35 - -DDEF_NRF_SCLK_PIN=36 - -DDEF_CMT_CSB=4 - -DDEF_CMT_FCSB=21 - -DDEF_CMT_IRQ=8 - -DDEF_CMT_SDIO=5 - -DDEF_CMT_SCLK=6 - -DDEF_LED0=18 - -DDEF_LED1=17 - -DLED_ACTIVE_HIGH - -DARDUINO_USB_MODE=1 - #-DARDUINO_USB_CDC_ON_BOOT=1 monitor_filters = esp32_exception_decoder, colorize diff --git a/src/publisher/pubMqtt.h b/src/publisher/pubMqtt.h index 2734ff19..0140d152 100644 --- a/src/publisher/pubMqtt.h +++ b/src/publisher/pubMqtt.h @@ -16,10 +16,6 @@ #endif #include -#if defined(ETHERNET) -#include "../eth/ahoyeth.h" -#endif - #include "../utils/dbg.h" #include "../config/config.h" #include @@ -56,7 +52,8 @@ class PubMqtt { ~PubMqtt() { } - void setup(cfgMqtt_t *cfg_mqtt, const char *devName, const char *version, HMSYSTEM *sys, uint32_t *utcTs, uint32_t *uptime) { + void setup(IApp *app, cfgMqtt_t *cfg_mqtt, const char *devName, const char *version, HMSYSTEM *sys, uint32_t *utcTs, uint32_t *uptime) { + mApp = app; mCfgMqtt = cfg_mqtt; mDevName = devName; mVersion = version; @@ -254,13 +251,9 @@ class PubMqtt { void onConnect(bool sessionPreset) { DPRINTLN(DBG_INFO, F("MQTT connected")); - publish(subtopics[MQTT_VERSION], mVersion, true); - publish(subtopics[MQTT_DEVICE], mDevName, true); - #if defined(ETHERNET) - publish(subtopics[MQTT_IP_ADDR], ETH.localIP().toString().c_str(), true); - #else - publish(subtopics[MQTT_IP_ADDR], WiFi.localIP().toString().c_str(), true); - #endif + publish(subtopics[MQTT_VERSION], mVersion, false); + publish(subtopics[MQTT_DEVICE], mDevName, false); + publish(subtopics[MQTT_IP_ADDR], mApp->getIp().c_str(), true); tickerMinute(); publish(mLwtTopic.data(), mqttStr[MQTT_STR_LWT_CONN], true, false); @@ -612,6 +605,7 @@ class PubMqtt { espMqttClient mClient; cfgMqtt_t *mCfgMqtt = nullptr; + IApp *mApp; #if defined(ESP8266) WiFiEventHandler mHWifiCon, mHWifiDiscon; #endif diff --git a/src/publisher/pubMqttIvData.h b/src/publisher/pubMqttIvData.h index 6ddd63a9..cd212aa4 100644 --- a/src/publisher/pubMqttIvData.h +++ b/src/publisher/pubMqttIvData.h @@ -187,7 +187,6 @@ class PubMqttIvData { static_cast(mIv->getChannelFieldValue(CH0, FLD_FW_BUILD_MONTH_DAY, rec)), static_cast(mIv->getChannelFieldValue(CH0, FLD_FW_BUILD_HOUR_MINUTE, rec)), static_cast(mIv->getChannelFieldValue(CH0, FLD_BOOTLOADER_VER, rec))); - retained = true; } else if(InverterDevInform_Simple == mCmd) { 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}", @@ -195,7 +194,6 @@ class PubMqttIvData { static_cast(mIv->getChannelFieldValue(CH0, FLD_HW_VERSION, rec)), static_cast(mIv->getChannelFieldValue(CH0, FLD_GRID_PROFILE_CODE, rec)), static_cast(mIv->getChannelFieldValue(CH0, FLD_GRID_PROFILE_VERSION, rec))); - retained = true; } else { snprintf(mSubTopic.data(), mSubTopic.size(), "%s/ch%d/%s", mIv->config->name, rec->assign[mPos].ch, fields[rec->assign[mPos].fieldId]); snprintf(mVal.data(), mVal.size(), "%g", ah::round3(mIv->getValue(mPos, rec))); diff --git a/src/utils/improv.h b/src/utils/improv.h index 20b2bcad..d2ccc0c3 100644 --- a/src/utils/improv.h +++ b/src/utils/improv.h @@ -147,10 +147,12 @@ class Improv { } void getNetworks(void) { - if(!mScanRunning) - mApp->scanAvailNetworks(); - JsonObject obj; + if(!mScanRunning) { + mApp->getAvailNetworks(obj); + return; + } + if(!mApp->getAvailNetworks(obj)) return; diff --git a/src/web/RestApi.h b/src/web/RestApi.h index 70a30a48..801d5e2e 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -100,7 +100,7 @@ class RestApi { else if(path == "setup") getSetup(request, root); #if !defined(ETHERNET) else if(path == "setup/networks") getNetworks(root); - else if(path == "setup/getip") getWifiIp(root); + else if(path == "setup/getip") getIp(root); #endif /* !defined(ETHERNET) */ else if(path == "live") getLive(request,root); else if (path == "powerHistory") getPowerHistory(request, root); @@ -166,7 +166,7 @@ class RestApi { #else DynamicJsonDocument json(12000); // does this work? I have no ESP32 :-( #endif - DeserializationError err = deserializeJson(json, (const char *)mTmpBuf, mTmpSize); + DeserializationError err = deserializeJson(json, static_cast(mTmpBuf, mTmpSize)); json.shrinkToFit(); JsonObject obj = json.as(); @@ -375,9 +375,9 @@ 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("ap_pwd")] = mConfig->sys.apPwd; obj[F("hidd")] = mConfig->sys.isHidden; obj[F("mac")] = WiFi.macAddress(); obj[F("wifi_channel")] = WiFi.channel(); @@ -762,6 +762,18 @@ class RestApi { } #endif + #if defined(ETHERNET) + void getEthernet(JsonObject obj) { + obj[F("en")] = mConfig->sys.eth.enabled; + obj[F("cs")] = mConfig->sys.eth.pinCs; + obj[F("sclk")] = mConfig->sys.eth.pinSclk; + obj[F("miso")] = mConfig->sys.eth.pinMiso; + obj[F("mosi")] = mConfig->sys.eth.pinMosi; + obj[F("irq")] = mConfig->sys.eth.pinIrq; + obj[F("reset")] = mConfig->sys.eth.pinRst; + } + #endif + void getRadioNrf(JsonObject obj) { obj[F("en")] = (bool) mConfig->nrf.enabled; if(mConfig->nrf.enabled) { @@ -920,6 +932,9 @@ class RestApi { #if defined(ESP32) getRadioCmt(obj.createNestedObject(F("radioCmt"))); #endif + #if defined(ETHERNET) + getEthernet(obj.createNestedObject(F("eth"))); + #endif getRadioNrf(obj.createNestedObject(F("radioNrf"))); getSerial(obj.createNestedObject(F("serial"))); getStaticIp(obj.createNestedObject(F("static_ip"))); @@ -935,13 +950,14 @@ class RestApi { #if !defined(ETHERNET) void getNetworks(JsonObject obj) { - mApp->getAvailNetworks(obj); - } - void getWifiIp(JsonObject obj) { - obj[F("ip")] = mApp->getStationIp(); + obj[F("success")] = mApp->getAvailNetworks(obj); } #endif /* !defined(ETHERNET) */ + void getIp(JsonObject obj) { + obj[F("ip")] = mApp->getIp(); + } + void getLive(AsyncWebServerRequest *request, JsonObject obj) { getGeneric(request, obj.createNestedObject(F("generic"))); obj[F("refresh")] = mConfig->inst.sendInterval; @@ -1054,7 +1070,7 @@ class RestApi { accepted = iv->setDevControlRequest(ActivePowerContr); if(accepted) - mApp->triggerTickSend(); + mApp->triggerTickSend(iv->id); } else if(F("dev") == jsonIn[F("cmd")]) { DPRINTLN(DBG_INFO, F("dev cmd")); iv->setDevCommand(jsonIn[F("val")].as()); @@ -1075,11 +1091,6 @@ class RestApi { if(isProtected(jsonIn, jsonOut, clientIP)) 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")]) mApp->setTimestamp(jsonIn[F("val")]); else if(F("sync_ntp") == jsonIn[F("cmd")]) @@ -1093,9 +1104,19 @@ class RestApi { snprintf(mConfig->sys.stationSsid, SSID_LEN, "%s", jsonIn[F("ssid")].as()); snprintf(mConfig->sys.stationPwd, PWD_LEN, "%s", jsonIn[F("pwd")].as()); mApp->saveSettings(false); // without reboot - mApp->setStopApAllowedMode(false); mApp->setupStation(); } + #else + else if(F("save_eth") == jsonIn[F("cmd")]) { + mConfig->sys.eth.enabled = jsonIn[F("en")].as(); + mConfig->sys.eth.pinCs = jsonIn[F("cs")].as(); + mConfig->sys.eth.pinSclk = jsonIn[F("sclk")].as(); + mConfig->sys.eth.pinMiso = jsonIn[F("miso")].as(); + mConfig->sys.eth.pinMosi = jsonIn[F("mosi")].as(); + mConfig->sys.eth.pinIrq = jsonIn[F("irq")].as(); + mConfig->sys.eth.pinRst = jsonIn[F("reset")].as(); + mApp->saveSettings(true); + } #endif /* !defined(ETHERNET */ else if(F("save_iv") == jsonIn[F("cmd")]) { Inverter<> *iv = mSys->getInverterByPos(jsonIn[F("id")], false); diff --git a/src/web/html/history.html b/src/web/html/history.html index 57bff2fc..d21e6b96 100644 --- a/src/web/html/history.html +++ b/src/web/html/history.html @@ -136,7 +136,7 @@ return [ mlNs("polyline", {stroke: "url(#gLine)", fill: "none", points: pts}), mlNs("polyline", {stroke: "none", fill: "url(#gFill)", points: pts2}), - mlNs("text", {x: i*.8, y: 10}, "{#MAX_DAY}: " + String(obj.max) + "W"), + mlNs("text", {x: i*.8, y: 10}, "{#MAXIMUM}: " + String(obj.max) + "W"), mlNs("text", {x: i*.8, y: 25}, "{#LAST_VALUE}: " + String(lastVal) + "W") ] } @@ -150,11 +150,11 @@ parseRssi(obj.generic) window.setInterval("getAjax('/api/powerHistory', parsePowerHistory)", obj.refresh * 1000) setTimeout(() => { - window.setInterval("getAjax('/api/powerHistoryDay', parsePowerHistoryDay)", refresh * 1000) + window.setInterval("getAjax('/api/powerHistoryDay', parsePowerHistoryDay)", obj.refresh * 1000) }, 200) /*IF_ENABLE_HISTORY_YIELD_PER_DAY*/ setTimeout(() => { - window.setInterval("getAjax('/api/yieldDayHistory', parseYieldDayHistory)", refresh * 1000) + window.setInterval("getAjax('/api/yieldDayHistory', parseYieldDayHistory)", obj.refresh * 1000) }, 400) /*ENDIF_ENABLE_HISTORY_YIELD_PER_DAY*/ } diff --git a/src/web/html/setup.html b/src/web/html/setup.html index 7d310cb7..db474150 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -57,22 +57,9 @@
{#AP_PWD}
-
-
{#SEARCH_NETWORKS}
-
-
- -
-
{#AVAIL_NETWORKS}
-
- -
-
SSID
-
+
{#SSID_HIDDEN}
@@ -247,7 +234,7 @@

{#MQTT_NOTE}

{#INTERVAL}
-
+
Discovery Config (homeassistant)
@@ -272,6 +259,10 @@

{#RADIO} (CMT2300A)

+ +

Ethernet

+
+
@@ -625,12 +616,6 @@ 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() { var obj = {cmd: "sync_ntp", token: "*"} getAjax("/api/setup", apiCbNtp, "POST", JSON.stringify(obj)) @@ -968,7 +953,7 @@ } } - function parsePinout(obj, type, system) { + function parsePinout(obj) { var e = document.getElementById("pinout"); /*IF_ESP32*/ var pinList = esp32pins; @@ -1009,7 +994,7 @@ ) } - function parseNrfRadio(obj, objPin, type, system) { + function parseNrfRadio(obj, objPin) { var e = document.getElementById("rf24"); var en = inp("nrfEnable", null, null, ["cb"], "nrfEnable", "checkbox"); en.checked = obj["en"]; @@ -1036,11 +1021,11 @@ ]) ); - if ("ESP8266" == type) { - pins = [['cs', 'pinCs'], ['ce', 'pinCe'], ['irq', 'pinIrq']]; - } else { - pins = [['cs', 'pinCs'], ['ce', 'pinCe'], ['irq', 'pinIrq'], ['sclk', 'pinSclk'], ['mosi', 'pinMosi'], ['miso', 'pinMiso']]; - } + /*IF_ESP32*/ + var pins = [['cs', 'pinCs'], ['ce', 'pinCe'], ['irq', 'pinIrq'], ['sclk', 'pinSclk'], ['mosi', 'pinMosi'], ['miso', 'pinMiso']]; + /*ELSE*/ + var pins = [['cs', 'pinCs'], ['ce', 'pinCe'], ['irq', 'pinIrq']]; + /*ENDIF_ESP32*/ for(p of pins) { e.append( ml("div", {class: "row mb-3"}, [ @@ -1054,7 +1039,7 @@ } /*IF_ESP32*/ - function parseCmtRadio(obj, type, system) { + function parseCmtRadio(obj) { var e = document.getElementById("cmt"); var en = inp("cmtEnable", null, null, ["cb"], "cmtEnable", "checkbox"); var pinList = esp32pins; @@ -1069,7 +1054,6 @@ /*ENDIF_ESP32-C3*/ en.checked = obj["en"]; - e.replaceChildren ( ml("div", {class: "row mb-3"}, [ ml("div", {class: "col-8 col-sm-3 my-2"}, "{#CMT_ENABLE}"), @@ -1096,6 +1080,42 @@ } /*ENDIF_ESP32*/ + /*IF_ETHERNET*/ + function parseEth(obj) { + var e = document.getElementById("eth"); + var en = inp("ethEn", null, null, ["cb"], "ethEn", "checkbox"); + var pinList = esp32pins; + /*IF_ESP32-S2*/ + pinList = esp32sXpins; + /*ENDIF_ESP32-S2*/ + /*IF_ESP32-S3*/ + pinList = esp32sXpins; + /*ENDIF_ESP32-S3*/ + /*IF_ESP32-C3*/ + pinList = esp32c3pins; + /*ENDIF_ESP32-C3*/ + + en.checked = obj["en"]; + e.replaceChildren ( + ml("div", {class: "row mb-3"}, [ + ml("div", {class: "col-8 col-sm-3 my-2"}, "{#ETH_ENABLE}"), + ml("div", {class: "col-4 col-sm-9"}, en) + ]) + ); + pins = [['cs', 'ethCs'], ['sclk', 'ethSclk'], ['miso', 'ethMiso'], ['mosi', 'ethMosi'], ['irq', 'ethIrq'], ['reset', 'ethRst']]; + for(p of pins) { + e.append( + ml("div", {class: "row mb-3"}, [ + ml("div", {class: "col-12 col-sm-3 my-2"}, p[0].toUpperCase()), + ml("div", {class: "col-12 col-sm-9"}, + sel(p[1], pinList, obj[p[0]]) + ) + ]) + ); + } + } + /*ENDIF_ETHERNET*/ + function parseSerial(obj) { var e = document.getElementById("serialCb") var l = [["serEn", "show_live_data", "{#LOG_PRINT_INVERTER_DATA}"], ["serDbg", "debug", "{#LOG_SERIAL_DEBUG}"], ["priv", "priv", "{#LOG_PRIVACY_MODE}"], ["wholeTrace", "wholeTrace", "{#LOG_PRINT_TRACES}"], ["log2mqtt", "log2mqtt", "{#LOG_TO_MQTT}"]] @@ -1442,10 +1462,10 @@ modal("{#ZE_GROUP_EDIT_MODAL}: " + obj.id, html); // ser.dispatchEvent(new Event('change')); -// Inhalt f�r pm_type aus config laden und in eine Funktion ausgliedern +// Inhalt f?r pm_type aus config laden und in eine Funktion ausgliedern var e = document.getElementById("pm_type"); selDelAllOpt(e); -// TODO: �bersetzen? +// TODO: ?bersetzen? e.appendChild(opt("0", "---")); e.appendChild(opt("1", "Shelly")); e.appendChild(opt("2", "Tasmota")); @@ -1482,7 +1502,7 @@ for (var inv = 0; inv < maxInv; inv++) { var e = document.getElementById("invTarget"+inv); selDelAllOpt(e); -// TODO: �bersetzen? +// TODO: ?bersetzen? e.appendChild(opt("-1", "---")); e.appendChild(opt("0", "Sum")); e.appendChild(opt("1", "L1")); @@ -1719,13 +1739,15 @@ parseMqtt(root["mqtt"]); parseNtp(root["ntp"]); parseSun(root["sun"]); - parsePinout(root["pinout"], root["system"]["esp_type"], root["system"]); - parseNrfRadio(root["radioNrf"], root["pinout"], root["system"]["esp_type"], root["system"]); + parsePinout(root.pinout); + parseNrfRadio(root["radioNrf"], root["pinout"]); /*IF_ESP32*/ - parseCmtRadio(root["radioCmt"], root["system"]["esp_type"], root["system"]); + parseCmtRadio(root.radioCmt); /*ENDIF_ESP32*/ - + /*IF_ETHERNET*/ + parseEth(root.eth) + /*ENDIF_ETHERNET*/ parseSerial(root["serial"]); /*IF_PLUGIN_DISPLAY*/ parseDisplay(root["display"], root["system"]["esp_type"], root["system"]); @@ -1748,13 +1770,6 @@ 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); diff --git a/src/web/html/wizard.html b/src/web/html/wizard.html index 3df44dc4..1fc8503c 100644 --- a/src/web/html/wizard.html +++ b/src/web/html/wizard.html @@ -15,6 +15,165 @@ var found = false; var c = document.getElementById("con"); + /*IF_ESP32*/ + var pinList = [ + [255, "{#PIN_OFF}"], + [0, "GPIO0"], + [1, "TX (GPIO1)"], + [2, "GPIO2 (LED)"], + [3, "RX (GPIO3)"], + [4, "GPIO4"], + [5, "GPIO5"], + [12, "GPIO12 (HSPI MISO)"], + [13, "GPIO13 (HSPI MOSI)"], + [14, "GPIO14 (HSPI SCLK)"], + [15, "GPIO15"], + [16, "GPIO16"], + [17, "GPIO17"], + [18, "GPIO18 (VSPI SCLK)"], + [19, "GPIO19 (VSPI MISO)"], + [21, "GPIO21 (SDA)"], + [22, "GPIO22 (SCL)"], + [23, "GPIO23 (VSPI MOSI)"], + [25, "GPIO25"], + [26, "GPIO26"], + [27, "GPIO27"], + [32, "GPIO32"], + [33, "GPIO33"], + [34, "GPIO34 ({#PIN_INPUT_ONLY})"], + [35, "GPIO35 ({#PIN_INPUT_ONLY})"], + [36, "VP (GPIO36, {#PIN_INPUT_ONLY})"], + [39, "VN (GPIO39, {#PIN_INPUT_ONLY})"] + ]; + /*IF_ESP32-S2*/ + pinList = [ + [255, "off / default"], + [0, "GPIO0 ({#PIN_DONT_USE} - BOOT)"], + [1, "GPIO1"], + [2, "GPIO2"], + [3, "GPIO3"], + [4, "GPIO4"], + [5, "GPIO5"], + [6, "GPIO6"], + [7, "GPIO7"], + [8, "GPIO8"], + [9, "GPIO9"], + [10, "GPIO10"], + [11, "GPIO11"], + [12, "GPIO12"], + [13, "GPIO13"], + [14, "GPIO14"], + [15, "GPIO15"], + [16, "GPIO16"], + [17, "GPIO17"], + [18, "GPIO18"], + [19, "GPIO19 ({#PIN_DONT_USE} - USB-)"], + [20, "GPIO20 ({#PIN_DONT_USE} - USB+)"], + [21, "GPIO21"], + [26, "GPIO26 (PSRAM - {#PIN_NOT_AVAIL})"], + [27, "GPIO27 (FLASH - {#PIN_NOT_AVAIL})"], + [28, "GPIO28 (FLASH - {#PIN_NOT_AVAIL})"], + [29, "GPIO29 (FLASH - {#PIN_NOT_AVAIL})"], + [30, "GPIO30 (FLASH - {#PIN_NOT_AVAIL})"], + [31, "GPIO31 (FLASH - {#PIN_NOT_AVAIL})"], + [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"], + [45, "GPIO45 ({#PIN_DONT_USE} - STRAPPING PIN)"], + [46, "GPIO46 ({#PIN_DONT_USE} - STRAPPING PIN)"], + [47, "GPIO47"], + [48, "GPIO48"], + ]; + /*ENDIF_ESP32-S2*/ + /*IF_ESP32-S3*/ + pinList = [ + [255, "off / default"], + [0, "GPIO0 ({#PIN_DONT_USE} - BOOT)"], + [1, "GPIO1"], + [2, "GPIO2"], + [3, "GPIO3"], + [4, "GPIO4"], + [5, "GPIO5"], + [6, "GPIO6"], + [7, "GPIO7"], + [8, "GPIO8"], + [9, "GPIO9"], + [10, "GPIO10"], + [11, "GPIO11"], + [12, "GPIO12"], + [13, "GPIO13"], + [14, "GPIO14"], + [15, "GPIO15"], + [16, "GPIO16"], + [17, "GPIO17"], + [18, "GPIO18"], + [19, "GPIO19 ({#PIN_DONT_USE} - USB-)"], + [20, "GPIO20 ({#PIN_DONT_USE} - USB+)"], + [21, "GPIO21"], + [26, "GPIO26 (PSRAM - {#PIN_NOT_AVAIL})"], + [27, "GPIO27 (FLASH - {#PIN_NOT_AVAIL})"], + [28, "GPIO28 (FLASH - {#PIN_NOT_AVAIL})"], + [29, "GPIO29 (FLASH - {#PIN_NOT_AVAIL})"], + [30, "GPIO30 (FLASH - {#PIN_NOT_AVAIL})"], + [31, "GPIO31 (FLASH - {#PIN_NOT_AVAIL})"], + [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"], + [45, "GPIO45 ({#PIN_DONT_USE} - STRAPPING PIN)"], + [46, "GPIO46 ({#PIN_DONT_USE} - STRAPPING PIN)"], + [47, "GPIO47"], + [48, "GPIO48"], + ]; + /*ENDIF_ESP32-S3*/ + /*IF_ESP32-C3*/ + pinList = [ + [255, "off / default"], + [0, "GPIO0"], + [1, "GPIO1"], + [2, "GPIO2"], + [3, "GPIO3"], + [4, "GPIO4"], + [5, "GPIO5"], + [6, "GPIO6"], + [7, "GPIO7"], + [8, "GPIO8"], + [9, "GPIO9"], + [10, "GPIO10"], + [11, "GPIO11"], + [12, "GPIO12 (PSRAM/FLASH)"], + [13, "GPIO13 (PSRAM/FLASH)"], + [14, "GPIO14 (PSRAM/FLASH)"], + [15, "GPIO15 (PSRAM/FLASH)"], + [16, "GPIO16 (PSRAM/FLASH)"], + [17, "GPIO17 (PSRAM/FLASH)"], + [18, "GPIO18 ({#PIN_DONT_USE} - USB-)"], + [19, "GPIO19 ({#PIN_DONT_USE} - USB+)"], + [20, "GPIO20 (RX)"], + [21, "GPIO21 (TX)"], + ]; + /*ENDIF_ESP32-C3*/ + /*ENDIF_ESP32*/ + function sect(e1, e2) { return ml("div", {class: "row"}, [ ml("div", {class: "col-12"}, ml("p", {}, e1)), @@ -22,7 +181,36 @@ ]) } - function wifi() { + /*IF_ETHERNET*/ + var pins = ['cs', 'sclk', 'miso', 'mosi', 'irq', 'reset'] + function step1(obj) { + console.log(obj) + lst = [] + for(p of pins) { + lst.push( + ml("div", {class: "row mb-3"}, [ + ml("div", {class: "col-12 col-sm-3 my-2"}, p.toUpperCase()), + ml("div", {class: "col-12 col-sm-9"}, + sel(p, pinList, obj[p]) + ) + ]) + ) + } + let en = inp("en", null, null, ["cb"], "en", "checkbox"); + en.checked = obj["en"]; + + return sect("{#NETWORK_SETUP}", [ + ml("div", {class: "row mb-3"}, [ + ml("div", {class: "col-8"}, "{#ETH_ENABLE}"), + ml("div", {class: "col-4"}, en) + ]), + ...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 mt-5"}, ml("div", {class: "col a-c"}, ml("a", {href: "http://192.168.4.1/"}, "{#STOP_WIZARD}"))) + ]) + } + /*ELSE*/ + function step1() { 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}"))), @@ -30,9 +218,10 @@ sect("{#WIFI_MANUAL}", ml("input", {id: "man", type: "text"})), 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 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", {href: "http://192.168.4.1/index"}, "{#STOP_WIZARD}"))) ]) } + /*ENDIF_ETHERNET*/ function checkWifi() { c.replaceChildren( @@ -40,9 +229,9 @@ ml("div", {class: "row"}, ml("div", {class: "col"}, ml("span", {class: "fs-5"}, "{#TEST_CONNECTION}"))), 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 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", {href: "http://192.168.4.1/index"}, "{#STOP_WIZARD}"))) ) - v = setInterval(() => {getAjax('/api/setup/getip', printIp)}, 2500); + v = setInterval(() => {getAjax('/api/setup/getip', printIp)}, 300); } function redirect() { @@ -57,14 +246,33 @@ } } + /*IF_ETHERNET*/ + function saveEth() { + let o = { + cmd: "save_eth", + en: document.getElementsByName("en")[0].checked + } + for(p of pins) { + o[p] = document.getElementsByName(p)[0].value + } + getAjax("/api/setup", ((o) => {}), "POST", JSON.stringify(o)); + } + /*ELSE*/ 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*/ + /*IF_ETHERNET*/ + getAjax("/api/setup", ((o) => c.append(step1(o.eth)))); + /*ELSE*/ function nets(obj) { + if(!obj.success) + return; + var e = document.getElementById("net"); if(obj.networks.length > 0) { var a = [] @@ -75,13 +283,13 @@ } e.replaceChildren(...a) } - getAjax("/api/setup", ((o) => {}), "POST", JSON.stringify({cmd: "scan_wifi"})); } - getAjax("/api/setup", ((o) => {}), "POST", JSON.stringify({cmd: "scan_wifi"})); - c.append(wifi()) + c.append(step1()) + getAjax('/api/setup/networks', nets) + v = setInterval(() => {getAjax('/api/setup/networks', nets)}, 1000) + /*ENDIF_ETHERNET*/ - v = setInterval(() => {getAjax('/api/setup/networks', nets)}, 2500); diff --git a/src/web/lang.json b/src/web/lang.json index f31bd173..4924e678 100644 --- a/src/web/lang.json +++ b/src/web/lang.json @@ -81,12 +81,17 @@ { "token": "BTN_NEXT", "en": "next >>", - "de": "prüfen >>" + "de": "prüfen >>" + }, + { + "token": "BTN_REBOOT", + "en": "reboot >>", + "de": "Ahoy neustarten >>" }, { "token": "TEST_CONNECTION", "en": "Test Connection", - "de": "Verbindung wird überprüft" + "de": "Verbindung wird überprüft" }, { "token": "TRY_TO_CONNECT", @@ -112,6 +117,36 @@ "token": "NUM_NETWORKS_FOUND", "en": "Network(s) found", "de": "Netzwerk(e) gefunden" + }, + { + "token": "PIN_OFF", + "en": "off / default", + "de": "aus / Standard" + }, + { + "token": "PIN_NO_IRQ", + "en": "no IRQ!", + "de": "kein Interrupt!" + }, + { + "token": "PIN_INPUT_ONLY", + "en": "in only", + "de": "nur Eingang" + }, + { + "token": "PIN_DONT_USE", + "en": "DONT USE", + "de": "nicht benutzen" + }, + { + "token": "PIN_NOT_AVAIL", + "en": "not available", + "de": "nicht verfügbar" + }, + { + "token": "ETH_ENABLE", + "en": "Ethernet enable", + "de": "Ethernet aktivieren" } ] }, @@ -224,19 +259,9 @@ "de": "Netzwerke suchen" }, { - "token": "BTN_SCAN", - "en": "scan", - "de": "Suche starten" - }, - { - "token": "AVAIL_NETWORKS", - "en": "Avail Networks", - "de": "Verfügbare Netzwerke" - }, - { - "token": "NETWORK_NOT_SCANNED", - "en": "not scanned", - "de": "nicht gesucht" + "token": "SCAN_WIFI", + "en": "scan for WiFi networks", + "de": "nach WiFi Netzwerken suchen" }, { "token": "SSID_HIDDEN", @@ -596,7 +621,7 @@ { "token": "BTN_INV_ADD", "en": "add Inverter", - "de": "Wechselrichter hinzufuegen" + "de": "Wechselrichter hinzuf\u00FCgen" }, { "token": "INV_INPUT", @@ -621,7 +646,7 @@ { "token": "TAB_INPUTS", "en": "Inputs", - "de": "Eingaenge" + "de": "Eingänge" }, { "token": "TAB_RADIO", @@ -723,6 +748,11 @@ "en": "CMT2300A radio enable", "de": "CMT2300A Funkmodul aktivieren" }, + { + "token": "ETH_ENABLE", + "en": "Ethernet enable", + "de": "Ethernet aktivieren" + }, { "token": "DISP_NONE", "en": "None", @@ -1769,9 +1799,9 @@ "de": "Gesamtertrag pro Tag" }, { - "token": "MAX_DAY", - "en": "Maximum day", - "de": "Tagesmaximum" + "token": "MAXIMUM", + "en": "Maximum", + "de": "Maximum" }, { "token": "LAST_VALUE", diff --git a/src/web/web.h b/src/web/web.h index fe2b7b90..b8b7a51f 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -40,14 +40,19 @@ //#define WEB_SERIAL_BUF_SIZE 2048 #define WEB_SERIAL_BUF_SIZE 3072 -const char* const pinArgNames[] = {"pinCs", "pinCe", "pinIrq", "pinSclk", "pinMosi", "pinMiso", "pinLed0", "pinLed1", "pinLed2", "pinLedHighActive", "pinLedLum", "pinCmtSclk", "pinSdio", "pinCsb", "pinFcsb", "pinGpio3"}; +const char* const pinArgNames[] = { + "pinCs", "pinCe", "pinIrq", "pinSclk", "pinMosi", "pinMiso", "pinLed0", + "pinLed1", "pinLed2", "pinLedHighActive", "pinLedLum", "pinCmtSclk", + "pinSdio", "pinCsb", "pinFcsb", "pinGpio3" + #if defined (ETHERNET) + , "ethCs", "ethSclk", "ethMiso", "ethMosi", "ethIrq", "ethRst" + #endif +}; template class Web { public: - Web(void) : mWeb(80), mEvts("/events") { - memset(mSerialBuf, 0, WEB_SERIAL_BUF_SIZE); - } + Web(void) : mWeb(80), mEvts("/events") {} void setup(IApp *app, HMSYSTEM *sys, settings_t *config) { mApp = app; @@ -55,7 +60,8 @@ class Web { mConfig = config; 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("/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)); @@ -105,11 +111,17 @@ class Web { void tickSecond() { if (mSerialClientConnnected) { + if(nullptr == mSerialBuf) + return; + if (mSerialBufFill > 0) { mEvts.send(mSerialBuf, "serial", millis()); memset(mSerialBuf, 0, WEB_SERIAL_BUF_SIZE); mSerialBufFill = 0; } + } else if(nullptr != mSerialBuf) { + delete[] mSerialBuf; + mSerialBuf = nullptr; } } @@ -181,6 +193,9 @@ class Web { if (!mSerialClientConnnected) return; + if(nullptr == mSerialBuf) + return; + msg.replace("\r\n", ""); if (mSerialAddTime) { if ((13 + mSerialBufFill) < WEB_SERIAL_BUF_SIZE) { @@ -297,6 +312,10 @@ class Web { void onConnect(AsyncEventSourceClient *client) { DPRINTLN(DBG_VERBOSE, "onConnect"); + if(nullptr == mSerialBuf) { + mSerialBuf = new char[WEB_SERIAL_BUF_SIZE]; + memset(mSerialBuf, 0, WEB_SERIAL_BUF_SIZE); + } mSerialClientConnnected = true; if (client->lastId()) @@ -305,7 +324,11 @@ class Web { 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); } @@ -388,6 +411,7 @@ class Web { void showNotFound(AsyncWebServerRequest *request) { checkProtection(request); + //DBGPRINTLN(request->url()); request->redirect("/wizard"); } @@ -433,10 +457,10 @@ class Web { request->arg("ssid").toCharArray(mConfig->sys.stationSsid, SSID_LEN); if (request->arg("pwd") != "{PWD}") request->arg("pwd").toCharArray(mConfig->sys.stationPwd, PWD_LEN); - if (request->arg("ap_pwd") != "") - request->arg("ap_pwd").toCharArray(mConfig->sys.apPwd, 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") != "") request->arg("device").toCharArray(mConfig->sys.deviceName, DEVNAME_LEN); mConfig->sys.darkMode = (request->arg("darkMode") == "on"); @@ -486,7 +510,12 @@ class Web { // pinout - for (uint8_t i = 0; i < 16; i++) { + #if defined(ETHERNET) + for (uint8_t i = 0; i < 22; i++) + #else + for (uint8_t i = 0; i < 16; i++) + #endif + { uint8_t pin = request->arg(String(pinArgNames[i])).toInt(); switch(i) { case 0: mConfig->nrf.pinCs = ((pin != 0xff) ? pin : DEF_NRF_CS_PIN); break; @@ -505,11 +534,23 @@ class Web { case 13: mConfig->cmt.pinCsb = pin; break; case 14: mConfig->cmt.pinFcsb = pin; break; case 15: mConfig->cmt.pinIrq = pin; break; + + #if defined(ETHERNET) + case 16: mConfig->sys.eth.pinCs = pin; break; + case 17: mConfig->sys.eth.pinSclk = pin; break; + case 18: mConfig->sys.eth.pinMiso = pin; break; + case 19: mConfig->sys.eth.pinMosi = pin; break; + case 20: mConfig->sys.eth.pinIrq = pin; break; + case 21: mConfig->sys.eth.pinRst = pin; break; + #endif } } mConfig->nrf.enabled = (request->arg("nrfEnable") == "on"); mConfig->cmt.enabled = (request->arg("cmtEnable") == "on"); + #if defined(ETHERNET) + mConfig->sys.eth.enabled = (request->arg("ethEn") == "on"); + #endif // ntp if (request->arg("ntpAddr") != "") { @@ -953,7 +994,7 @@ class Web { settings_t *mConfig = nullptr; bool mSerialAddTime = true; - char mSerialBuf[WEB_SERIAL_BUF_SIZE]; + char *mSerialBuf = nullptr; uint16_t mSerialBufFill = 0; bool mSerialClientConnnected = false; diff --git a/src/wifi/ahoywifi.cpp b/src/wifi/ahoywifi.cpp deleted file mode 100644 index 95bf0b8a..00000000 --- a/src/wifi/ahoywifi.cpp +++ /dev/null @@ -1,490 +0,0 @@ -//----------------------------------------------------------------------------- -// 2024 Ahoy, https://ahoydtu.de -// Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed -//----------------------------------------------------------------------------- - -#if !defined(ETHERNET) -#if defined(ESP32) && defined(F) - #undef F - #define F(sl) (sl) -#endif -#include "ahoywifi.h" - -#if defined(ESP32) -#include -#else -#include -#endif - -// NTP CONFIG -#define NTP_PACKET_SIZE 48 - -//----------------------------------------------------------------------------- -ahoywifi::ahoywifi() : mApIp(192, 168, 4, 1) {} - - -/** - * TODO: ESP32 has native strongest AP support! - * WiFi.setScanMethod(WIFI_ALL_CHANNEL_SCAN); - WiFi.setSortMethod(WIFI_CONNECT_AP_BY_SIGNAL); -*/ - -//----------------------------------------------------------------------------- -void ahoywifi::setup(settings_t *config, uint32_t *utcTimestamp, appWifiCb cb, OnTimeCB onTimeCb) { - mConfig = config; - mUtcTimestamp = utcTimestamp; - mAppWifiCb = cb; - mOnTimeCb = onTimeCb; - - mGotDisconnect = false; - mStaConn = DISCONNECTED; - mCnt = 0; - mScanActive = false; - mScanCnt = 0; - mStopApAllowed = true; - - #if defined(ESP8266) - wifiConnectHandler = WiFi.onStationModeConnected(std::bind(&ahoywifi::onConnect, this, std::placeholders::_1)); - wifiGotIPHandler = WiFi.onStationModeGotIP(std::bind(&ahoywifi::onGotIP, this, std::placeholders::_1)); - wifiDisconnectHandler = WiFi.onStationModeDisconnected(std::bind(&ahoywifi::onDisconnect, this, std::placeholders::_1)); - #else - WiFi.onEvent(std::bind(&ahoywifi::onWiFiEvent, this, std::placeholders::_1)); - #endif - - setupWifi(true); -} - - -//----------------------------------------------------------------------------- -void ahoywifi::setupWifi(bool startAP = false) { - #if !defined(FB_WIFI_OVERRIDDEN) - if(startAP) { - setupAp(); - delay(1000); - } - #endif - #if !defined(AP_ONLY) - #if defined(FB_WIFI_OVERRIDDEN) - snprintf(mConfig->sys.stationSsid, SSID_LEN, "%s", FB_WIFI_SSID); - snprintf(mConfig->sys.stationPwd, PWD_LEN, "%s", FB_WIFI_PWD); - setupStation(); - #else - if(mConfig->valid) { - if(strncmp(mConfig->sys.stationSsid, FB_WIFI_SSID, 14) != 0) - setupStation(); - } - #endif - #endif -} - - -void ahoywifi::tickWifiLoop() { - static const uint8_t TIMEOUT = 20; - static const uint8_t SCAN_TIMEOUT = 10; - #if !defined(AP_ONLY) - - mCnt++; - - switch (mStaConn) { - case IN_STA_MODE: - // Nothing to do - if (mGotDisconnect) { - mStaConn = RESET; - } - #if !defined(ESP32) - MDNS.update(); - if(WiFi.channel() > 11) - mWasInCh12to14 = true; - #endif - return; - case IN_AP_MODE: - if ((WiFi.softAPgetStationNum() == 0) || (!mStopApAllowed)) { - mCnt = 0; - mDns.stop(); - WiFi.mode(WIFI_AP_STA); - mStaConn = DISCONNECTED; - } else { - mDns.processNextRequest(); - return; - } - break; - case DISCONNECTED: - if ((WiFi.softAPgetStationNum() > 0) && (mStopApAllowed)) { - mStaConn = IN_AP_MODE; - // first time switch to AP Mode - if (mScanActive) { - WiFi.scanDelete(); - mScanActive = false; - } - DBGPRINTLN(F("AP client connected")); - welcome(mApIp.toString(), ""); - WiFi.mode(WIFI_AP); - mDns.start(53, "*", mApIp); - mAppWifiCb(true); - mDns.processNextRequest(); - return; - } else if (!mScanActive) { - DBGPRINT(F("scanning APs with SSID ")); - DBGPRINTLN(String(mConfig->sys.stationSsid)); - mScanCnt = 0; - mCnt = 0; - mScanActive = true; -#if defined(ESP8266) - WiFi.scanNetworks(true, true, 0U, ([this]() { - if (mConfig->sys.isHidden) - return (uint8_t*)NULL; - return (uint8_t*)(mConfig->sys.stationSsid); - })()); -#else - WiFi.scanNetworks(true, true, false, 300U, 0U, ([this]() { - if (mConfig->sys.isHidden) - return (char*)NULL; - return (mConfig->sys.stationSsid); - })()); -#endif - return; - } else if(getBSSIDs()) { - // Scan ready - mStaConn = SCAN_READY; - } else { - // In case of a timeout, what do we do? - // For now we start scanning again as the original code did. - // Would be better to into PA mode - - if (isTimeout(SCAN_TIMEOUT)) { - WiFi.scanDelete(); - mScanActive = false; - } - } - break; - case SCAN_READY: - mStaConn = CONNECTING; - mCnt = 0; - DBGPRINT(F("try to connect to AP with BSSID:")); - uint8_t bssid[6]; - for (int j = 0; j < 6; j++) { - bssid[j] = mBSSIDList.front(); - mBSSIDList.pop_front(); - DBGPRINT(" " + String(bssid[j], HEX)); - } - DBGPRINTLN(""); - mGotDisconnect = false; - WiFi.begin(mConfig->sys.stationSsid, mConfig->sys.stationPwd, 0, &bssid[0]); - - break; - case CONNECTING: - if (isTimeout(TIMEOUT)) { - WiFi.disconnect(); - mStaConn = mBSSIDList.empty() ? DISCONNECTED : SCAN_READY; - } - break; - case CONNECTED: - // Connection but no IP yet - if (isTimeout(TIMEOUT) || mGotDisconnect) { - mStaConn = RESET; - } - break; - case GOT_IP: - welcome(WiFi.localIP().toString(), F(" (Station)")); - if(mStopApAllowed) { - WiFi.softAPdisconnect(); - WiFi.mode(WIFI_STA); - DBGPRINTLN(F("[WiFi] AP disabled")); - delay(100); - } - mAppWifiCb(true); - mGotDisconnect = false; - mStaConn = IN_STA_MODE; - - if (!MDNS.begin(mConfig->sys.deviceName)) { - DPRINTLN(DBG_ERROR, F("Error setting up MDNS responder!")); - } else { - DBGPRINT(F("mDNS established: ")); - DBGPRINT(mConfig->sys.deviceName); - DBGPRINTLN(F(".local")); - } - - break; - case RESET: - mGotDisconnect = false; - mStaConn = DISCONNECTED; - mCnt = 5; // try to reconnect in 5 sec - setupWifi(); // reconnect with AP / Station setup - mAppWifiCb(false); - DPRINTLN(DBG_INFO, "[WiFi] Connection Lost"); - break; - default: - DBGPRINTLN(F("Unhandled status")); - break; - } - -#endif -} - -//----------------------------------------------------------------------------- -void ahoywifi::setupAp(void) { - DPRINTLN(DBG_VERBOSE, F("wifi::setupAp")); - - DBGPRINTLN(F("\n---------\nAhoyDTU Info:")); - DBGPRINT(F("Version: ")); - DBGPRINT(String(VERSION_MAJOR)); - DBGPRINT(F(".")); - DBGPRINT(String(VERSION_MINOR)); - DBGPRINT(F(".")); - DBGPRINTLN(String(VERSION_PATCH)); - DBGPRINT(F("Github Hash: ")); - DBGPRINTLN(String(AUTO_GIT_HASH)); - - DBGPRINT(F("\n---------\nAP MODE\nSSID: ")); - DBGPRINTLN(WIFI_AP_SSID); - DBGPRINT(F("PWD: ")); - DBGPRINTLN(mConfig->sys.apPwd); - DBGPRINT(F("IP Address: http://")); - DBGPRINTLN(mApIp.toString()); - DBGPRINTLN(F("---------\n")); - - if(String(mConfig->sys.deviceName) != "") - WiFi.hostname(mConfig->sys.deviceName); - - WiFi.mode(WIFI_AP_STA); - WiFi.softAPConfig(mApIp, mApIp, IPAddress(255, 255, 255, 0)); - WiFi.softAP(WIFI_AP_SSID, mConfig->sys.apPwd); -} - - -//----------------------------------------------------------------------------- -void ahoywifi::setupStation(void) { - DPRINTLN(DBG_VERBOSE, F("wifi::setupStation")); - if(mConfig->sys.ip.ip[0] != 0) { - IPAddress ip(mConfig->sys.ip.ip); - IPAddress mask(mConfig->sys.ip.mask); - IPAddress dns1(mConfig->sys.ip.dns1); - IPAddress dns2(mConfig->sys.ip.dns2); - IPAddress gateway(mConfig->sys.ip.gateway); - if(!WiFi.config(ip, gateway, mask, dns1, dns2)) - DPRINTLN(DBG_ERROR, F("failed to set static IP!")); - } - mBSSIDList.clear(); - if(String(mConfig->sys.deviceName) != "") - WiFi.hostname(mConfig->sys.deviceName); - WiFi.mode(WIFI_AP_STA); - - DBGPRINT(F("connect to network '")); - DBGPRINT(mConfig->sys.stationSsid); - DBGPRINTLN(F("' ...")); -} - - -//----------------------------------------------------------------------------- -bool ahoywifi::updateNtpTime(void) { - if(IN_STA_MODE != mStaConn) - return false; - - IPAddress timeServer; - uint8_t buf[NTP_PACKET_SIZE]; - uint8_t retry = 0; - - if (WiFi.hostByName(mConfig->ntp.addr, timeServer) != 1) - return false; - - mUdp.begin(mConfig->ntp.port); - sendNTPpacket(timeServer); - - while(retry++ < 5) { - int wait = 150; - while(--wait) { - if(NTP_PACKET_SIZE <= mUdp.parsePacket()) { - uint64_t secsSince1900; - mUdp.read(buf, NTP_PACKET_SIZE); - secsSince1900 = ((uint64_t)buf[40] << 24); - secsSince1900 |= (buf[41] << 16); - secsSince1900 |= (buf[42] << 8); - secsSince1900 |= (buf[43] ); - - *mUtcTimestamp = secsSince1900 - 2208988800UL; // UTC time - DPRINTLN(DBG_INFO, "[NTP]: " + ah::getDateTimeStr(*mUtcTimestamp) + " UTC"); - mOnTimeCb(true); - return true; - } else - delay(10); - } - } - - DPRINTLN(DBG_INFO, F("[NTP]: getNtpTime failed")); - return false; -} - - -//----------------------------------------------------------------------------- -void ahoywifi::sendNTPpacket(IPAddress& address) { - //DPRINTLN(DBG_VERBOSE, F("wifi::sendNTPpacket")); - uint8_t buf[NTP_PACKET_SIZE] = {0}; - - buf[0] = B11100011; // LI, Version, Mode - buf[1] = 0; // Stratum - buf[2] = 6; // Max Interval between messages in seconds - buf[3] = 0xEC; // Clock Precision - // bytes 4 - 11 are for Root Delay and Dispersion and were set to 0 by memset - buf[12] = 49; // four-byte reference ID identifying - buf[13] = 0x4E; - buf[14] = 49; - buf[15] = 52; - - mUdp.beginPacket(address, 123); // NTP request, port 123 - mUdp.write(buf, NTP_PACKET_SIZE); - mUdp.endPacket(); -} - -//----------------------------------------------------------------------------- -void ahoywifi::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]); -} - -//----------------------------------------------------------------------------- -void ahoywifi::scanAvailNetworks(void) { - if(!mScanActive) { - mScanActive = true; - if(WIFI_AP == WiFi.getMode()) - WiFi.mode(WIFI_AP_STA); - WiFi.scanNetworks(true); - } -} - -//----------------------------------------------------------------------------- -bool ahoywifi::getAvailNetworks(JsonObject obj) { - JsonArray nets = obj.createNestedArray("networks"); - - int n = WiFi.scanComplete(); - if (n < 0) - return false; - if(n > 0) { - int sort[n]; - sortRSSI(&sort[0], n); - for (int i = 0; i < n; ++i) { - nets[i]["ssid"] = WiFi.SSID(sort[i]); - nets[i]["rssi"] = WiFi.RSSI(sort[i]); - } - } - mScanActive = false; - WiFi.scanDelete(); - if(mStaConn == IN_AP_MODE) - WiFi.mode(WIFI_AP); - - return true; -} - -//----------------------------------------------------------------------------- -bool ahoywifi::getBSSIDs() { - bool result = false; - int n = WiFi.scanComplete(); - if (n < 0) { - if (++mScanCnt < 20) - return false; - } - if(n > 0) { - mBSSIDList.clear(); - int sort[n]; - sortRSSI(&sort[0], n); - for (int i = 0; i < n; i++) { - DBGPRINT("BSSID " + String(i) + ":"); - uint8_t *bssid = WiFi.BSSID(sort[i]); - for (int j = 0; j < 6; j++){ - DBGPRINT(" " + String(bssid[j], HEX)); - mBSSIDList.push_back(bssid[j]); - } - DBGPRINTLN(""); - } - result = true; - } - mScanActive = false; - WiFi.scanDelete(); - return result; -} - -//----------------------------------------------------------------------------- -void ahoywifi::connectionEvent(WiFiStatus_t status) { - DPRINTLN(DBG_INFO, "connectionEvent"); - - switch(status) { - case CONNECTED: - if(mStaConn != CONNECTED) { - mStaConn = CONNECTED; - mGotDisconnect = false; - DBGPRINTLN(F("\n[WiFi] Connected")); - } - break; - - case GOT_IP: - mStaConn = GOT_IP; - break; - - case DISCONNECTED: - mGotDisconnect = true; - break; - - default: - break; - } -} - - -//----------------------------------------------------------------------------- -#if defined(ESP8266) - //------------------------------------------------------------------------- - void ahoywifi::onConnect(const WiFiEventStationModeConnected& event) { - connectionEvent(CONNECTED); - } - - //------------------------------------------------------------------------- - void ahoywifi::onGotIP(const WiFiEventStationModeGotIP& event) { - connectionEvent(GOT_IP); - } - - //------------------------------------------------------------------------- - void ahoywifi::onDisconnect(const WiFiEventStationModeDisconnected& event) { - connectionEvent(DISCONNECTED); - } - -#else - //------------------------------------------------------------------------- - void ahoywifi::onWiFiEvent(WiFiEvent_t event) { - DBGPRINT(F("Wifi event: ")); - DBGPRINTLN(String(event)); - - switch(event) { - case SYSTEM_EVENT_STA_CONNECTED: - connectionEvent(CONNECTED); - break; - - case SYSTEM_EVENT_STA_GOT_IP: - connectionEvent(GOT_IP); - break; - - case SYSTEM_EVENT_STA_DISCONNECTED: - connectionEvent(DISCONNECTED); - break; - - default: - break; - } - } -#endif - - -//----------------------------------------------------------------------------- -void ahoywifi::welcome(String ip, String mode) { - DBGPRINTLN(F("\n\n--------------------------------")); - DBGPRINTLN(F("Welcome to AHOY!")); - DBGPRINT(F("\npoint your browser to http://")); - DBGPRINT(ip); - DBGPRINTLN(mode); - DBGPRINTLN(F("to configure your device")); - DBGPRINTLN(F("--------------------------------\n")); -} - -#endif /* !defined(ETHERNET) */ diff --git a/src/wifi/ahoywifi.h b/src/wifi/ahoywifi.h deleted file mode 100644 index 78ec6ab1..00000000 --- a/src/wifi/ahoywifi.h +++ /dev/null @@ -1,100 +0,0 @@ -//------------------------------------//----------------------------------------------------------------------------- -// 2024 Ahoy, https://github.com/lumpapu/ahoy -// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/4.0/deed -//----------------------------------------------------------------------------- - -#if !defined(ETHERNET) -#ifndef __AHOYWIFI_H__ -#define __AHOYWIFI_H__ - -#include "../utils/dbg.h" -#include -#include -#include -#include -#include "ESPAsyncWebServer.h" - -#include "../config/settings.h" - -class app; - -class ahoywifi { - public: - typedef std::function appWifiCb; - typedef std::function OnTimeCB; - - ahoywifi(); - - - void setup(settings_t *config, uint32_t *utcTimestamp, appWifiCb cb, OnTimeCB onTimeCB); - void tickWifiLoop(void); - bool updateNtpTime(void); - void scanAvailNetworks(void); - bool getAvailNetworks(JsonObject obj); - void setStopApAllowedMode(bool allowed) { - mStopApAllowed = allowed; - } - String getStationIp(void) { - return WiFi.localIP().toString(); - } - void setupStation(void); - - bool getWasInCh12to14() const { - return mWasInCh12to14; - } - - private: - typedef enum WiFiStatus { - DISCONNECTED = 0, - SCAN_READY, - CONNECTING, - CONNECTED, - IN_AP_MODE, - GOT_IP, - IN_STA_MODE, - RESET - } WiFiStatus_t; - - void setupWifi(bool startAP); - void setupAp(void); - void sendNTPpacket(IPAddress& address); - void sortRSSI(int *sort, int n); - bool getBSSIDs(void); - void connectionEvent(WiFiStatus_t status); - bool isTimeout(uint8_t timeout) { return (mCnt % timeout) == 0; } - -#if defined(ESP8266) - void onConnect(const WiFiEventStationModeConnected& event); - void onGotIP(const WiFiEventStationModeGotIP& event); - void onDisconnect(const WiFiEventStationModeDisconnected& event); - #else - void onWiFiEvent(WiFiEvent_t event); - #endif - void welcome(String ip, String mode); - - - settings_t *mConfig = nullptr; - appWifiCb mAppWifiCb; - OnTimeCB mOnTimeCb; - - DNSServer mDns; - IPAddress mApIp; - WiFiUDP mUdp; // for time server - #if defined(ESP8266) - WiFiEventHandler wifiConnectHandler, wifiDisconnectHandler, wifiGotIPHandler; - #endif - - WiFiStatus_t mStaConn = DISCONNECTED; - uint8_t mCnt = 0; - uint32_t *mUtcTimestamp = nullptr; - - uint8_t mScanCnt = 0; - bool mScanActive = false; - bool mGotDisconnect = false; - std::list mBSSIDList; - bool mStopApAllowed = false; - bool mWasInCh12to14 = false; -}; - -#endif /*__AHOYWIFI_H__*/ -#endif /* !defined(ETHERNET) */