From 2a990978d86356dcbe5a43450e98c32481d810c1 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 22 Sep 2024 01:03:12 +0200 Subject: [PATCH] 0.8.145 * fix NTP related issues #1748 #1752 * fix MqTT discovery total #1715 * upgrade webserver version for ESP32 devices --- src/CHANGES.md | 5 ++ src/app.cpp | 111 ++++++++++++++-------------------- src/app.h | 9 ++- src/defines.h | 2 +- src/network/AhoyNetwork.h | 36 ++++++++--- src/network/AhoyWifiEsp32.h | 1 + src/network/AhoyWifiEsp8266.h | 1 + src/platformio.ini | 2 +- src/publisher/pubMqtt.h | 24 +++++--- src/utils/scheduler.h | 19 +++--- 10 files changed, 112 insertions(+), 98 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index de2d149d..97c0c595 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,10 @@ # Development Changes +## 0.8.145 - 2024-09-22 +* fix NTP related issues #1748 #1752 +* fix MqTT discovery total #1715 +* upgrade webserver version for ESP32 devices + ## 0.8.144 - 2024-09-14 * fix NTP lookup if internet connection is not there * added fallback for NTP to gateway IP diff --git a/src/app.cpp b/src/app.cpp index 35db3f31..5a992f74 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -13,7 +13,15 @@ //----------------------------------------------------------------------------- -app::app() : ah::Scheduler {} { +app::app() + : ah::Scheduler {} + , mSunrise {0} + , mSunset {0} + , idTickMqttSecond {MAX_NUM_TICKER} + , idTickMqttMinute {MAX_NUM_TICKER} + , idTickMidnight {MAX_NUM_TICKER} + , idTickReboot {MAX_NUM_TICKER} +{ memset(mVersion, 0, sizeof(char) * 12); memset(mVersionModules, 0, sizeof(char) * 12); } @@ -51,7 +59,7 @@ void app::setup() { #else mNetwork = static_cast(new AhoyWifi()); #endif - mNetwork->setup(mConfig, &mTimestamp, [this](bool gotIp) { this->onNetwork(gotIp); }, [this](bool gotTime) { this->onNtpUpdate(gotTime); }); + mNetwork->setup(mConfig, [this](bool gotIp) { this->onNetwork(gotIp); }, [this](uint32_t gotTime) { this->onNtpUpdate(gotTime); }); mNetwork->begin(); esp_task_wdt_reset(); @@ -151,15 +159,19 @@ void app::loop(void) { void app::onNetwork(bool gotIp) { mNetworkConnected = gotIp; if(gotIp) { - ah::Scheduler::resetTicker(); - regularTickers(); //reinstall regular tickers + mNetwork->updateNtpTime(); if(!mConfig->inst.startWithoutTime) // already set in regularTickers every(std::bind(&app::tickSend, this), mConfig->inst.sendInterval, "tSend"); - mTickerInstallOnce = true; - mSunrise = 0; // needs to be set to 0, to reinstall sunrise and ivComm tickers! - uint32_t nextTrig = (mTimestamp < 0x1337) ? 0 : (mConfig->ntp.interval * 60); - once(std::bind(&app::tickNtpUpdate, this), nextTrig, "ntp"); + #if defined(ENABLE_MQTT) + if (mMqttEnabled) { + if(MAX_NUM_TICKER == idTickMqttSecond) + idTickMqttSecond = everySec(std::bind(&PubMqttType::tickerSecond, &mMqtt), "mqttS"); + + if(MAX_NUM_TICKER == idTickMqttMinute) + idTickMqttMinute = everyMin(std::bind(&PubMqttType::tickerMinute, &mMqtt), "mqttM"); + } + #endif /*ENABLE_MQTT*/ } } @@ -170,9 +182,15 @@ void app::regularTickers(void) { everySec([this]() { mProtection->tickSecond(); }, "prot"); everySec([this]() {mNetwork->tickNetworkLoop(); }, "net"); - if(mConfig->inst.startWithoutTime && !mNetworkConnected) + if(mConfig->inst.startWithoutTime) every(std::bind(&app::tickSend, this), mConfig->inst.sendInterval, "tSend"); + + every([this]() { mNetwork->updateNtpTime(); }, mConfig->ntp.interval * 60, "ntp"); + + if (mConfig->inst.rstValsNotAvail) + everyMin(std::bind(&app::tickMinute, this), "tMin"); + // Plugins #if defined(PLUGIN_DISPLAY) if (DISP_TYPE_T0_NONE != mConfig->plugin.display.type) @@ -191,62 +209,32 @@ void app::regularTickers(void) { } //----------------------------------------------------------------------------- -void app::onNtpUpdate(bool gotTime) { - mNtpReceived = true; - if ((0 == mSunrise) && (0.0 != mConfig->sun.lat) && (0.0 != mConfig->sun.lon)) { - mCalculatedTimezoneOffset = (int8_t)((mConfig->sun.lon >= 0 ? mConfig->sun.lon + 7.5 : mConfig->sun.lon - 7.5) / 15) * 3600; - tickCalcSunrise(); - } - - if (mTickerInstallOnce) { - mTickerInstallOnce = false; - #if defined(ENABLE_MQTT) - if (mMqttEnabled) { - mMqtt.tickerSecond(); - everySec(std::bind(&PubMqttType::tickerSecond, &mMqtt), "mqttS"); - everyMin(std::bind(&PubMqttType::tickerMinute, &mMqtt), "mqttM"); +void app::onNtpUpdate(uint32_t utcTimestamp) { + if(0 == utcTimestamp) { + // try again in 5s + once([this]() { mNetwork->updateNtpTime(); }, 5, "ntp"); + } else { + mTimestamp = utcTimestamp; + DPRINTLN(DBG_INFO, "[NTP]: " + ah::getDateTimeStr(mTimestamp) + " UTC"); + + uint32_t localTime = gTimezone.toLocal(mTimestamp); + uint32_t midTrig = gTimezone.toUTC(localTime - (localTime % 86400) + 86400); // next midnight local time + resetById(idTickMidnight); + idTickMidnight = onceAt(std::bind(&app::tickMidnight, this), midTrig, "midNi"); + + if (mConfig->sys.schedReboot) { + resetById(idTickReboot); + uint32_t rebootTrig = gTimezone.toUTC(localTime - (localTime % 86400) + 86410); // reboot 10 secs after midnght + idTickReboot = onceAt(std::bind(&app::tickReboot, this), rebootTrig, "midRe"); } - #endif /*ENABLE_MQTT*/ - - if (mConfig->inst.rstValsNotAvail) - everyMin(std::bind(&app::tickMinute, this), "tMin"); - if(mNtpReceived) { - uint32_t localTime = gTimezone.toLocal(mTimestamp); - uint32_t midTrig = gTimezone.toUTC(localTime - (localTime % 86400) + 86400); // next midnight local time - onceAt(std::bind(&app::tickMidnight, this), midTrig, "midNi"); - - if (mConfig->sys.schedReboot) { - uint32_t rebootTrig = gTimezone.toUTC(localTime - (localTime % 86400) + 86410); // reboot 10 secs after midnght - onceAt(std::bind(&app::tickReboot, this), rebootTrig, "midRe"); - } + if ((0 == mSunrise) && (0.0 != mConfig->sun.lat) && (0.0 != mConfig->sun.lon)) { + mCalculatedTimezoneOffset = (int8_t)((mConfig->sun.lon >= 0 ? mConfig->sun.lon + 7.5 : mConfig->sun.lon - 7.5) / 15) * 3600; + tickCalcSunrise(); } } } -//----------------------------------------------------------------------------- -void app::updateNtp(void) { - if(mNtpReceived) - onNtpUpdate(true); -} - -//----------------------------------------------------------------------------- -void app::tickNtpUpdate(void) { - uint32_t nxtTrig = 5; // default: check again in 5 sec - - if (!mNtpReceived) - mNetwork->updateNtpTime(); - else { - nxtTrig = mConfig->ntp.interval * 60; // check again in configured interval - mNtpReceived = false; - } - yield(); - - updateNtp(); - - once(std::bind(&app::tickNtpUpdate, this), nxtTrig, "ntp"); -} - //----------------------------------------------------------------------------- void app::tickCalcSunrise(void) { if (mSunrise == 0) // on boot/reboot calc sun values for current time @@ -528,9 +516,6 @@ void app::resetSystem(void) { mAllIvNotAvail = true; - mSunrise = 0; - mSunset = 0; - mMqttEnabled = false; mSendLastIvId = 0; @@ -539,8 +524,6 @@ void app::resetSystem(void) { mSaveReboot = false; mNetworkConnected = false; - mNtpReceived = false; - mTickerInstallOnce = false; } //----------------------------------------------------------------------------- diff --git a/src/app.h b/src/app.h index c03251e0..5e460bb5 100644 --- a/src/app.h +++ b/src/app.h @@ -407,10 +407,7 @@ class app : public IApp, public ah::Scheduler { setRebootFlag(); } - void tickNtpUpdate(void); - void onNtpUpdate(bool gotTime); - bool mNtpReceived = false; - void updateNtp(void); + void onNtpUpdate(uint32_t utcTimestamp); void triggerTickSend(uint8_t id) override { once([this, id]() { @@ -465,9 +462,11 @@ class app : public IApp, public ah::Scheduler { #if defined(ENABLE_MQTT) PubMqttType mMqtt; #endif - bool mTickerInstallOnce = false; bool mMqttEnabled = false; + uint8_t idTickMqttSecond, idTickMqttMinute; + uint8_t idTickMidnight, idTickReboot; + // sun int32_t mCalculatedTimezoneOffset = 0; uint32_t mSunrise = 0, mSunset = 0; diff --git a/src/defines.h b/src/defines.h index 6921c720..025f6e30 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 144 +#define VERSION_PATCH 145 //------------------------------------- typedef struct { uint8_t ch; diff --git a/src/network/AhoyNetwork.h b/src/network/AhoyNetwork.h index 059d2603..1945fbb4 100644 --- a/src/network/AhoyNetwork.h +++ b/src/network/AhoyNetwork.h @@ -17,12 +17,11 @@ class AhoyNetwork { public: typedef std::function OnNetworkCB; - typedef std::function OnTimeCB; + typedef std::function OnTimeCB; public: - void setup(settings_t *config, uint32_t *utcTimestamp, OnNetworkCB onNetworkCB, OnTimeCB onTimeCB) { + void setup(settings_t *config, OnNetworkCB onNetworkCB, OnTimeCB onTimeCB) { mConfig = config; - mUtcTimestamp = utcTimestamp; mOnNetworkCB = onNetworkCB; mOnTimeCB = onTimeCB; @@ -53,6 +52,19 @@ class AhoyNetwork { #endif } + virtual void tickNetworkLoop() { + if(mDnsCallbackReady) { + mDnsCallbackReady = false; + startNtpUpdate(); + } + + if(mNtpTimeoutSec) { + mNtpTimeoutSec--; + if(!mNtpTimeoutSec) + mOnTimeCB(0); // timeout + } + } + bool isConnected() const { return ((mStatus == NetworkState::CONNECTED) || (mStatus == NetworkState::GOT_IP)); } @@ -66,6 +78,7 @@ class AhoyNetwork { obj->mNtpIp = ipaddr->addr; #endif } + obj->mDnsCallbackReady = true; } void updateNtpTime() { @@ -74,6 +87,8 @@ class AhoyNetwork { return; } + mNtpTimeoutSec = 30; + ip_addr_t ipaddr; mNtpIp = WiFi.gatewayIP(); // dns_gethostbyname runs asynchronous and sets the member mNtpIp which is then checked on @@ -94,8 +109,10 @@ class AhoyNetwork { void startNtpUpdate() { DPRINTLN(DBG_INFO, F("get time from: ") + mNtpIp.toString()); if (!mUdp.connected()) { - if (!mUdp.connect(mNtpIp, mConfig->ntp.port)) + if (!mUdp.connect(mNtpIp, mConfig->ntp.port)) { + mOnTimeCB(0); return; + } } mUdp.onPacket([this](AsyncUDPPacket packet) { @@ -109,7 +126,6 @@ class AhoyNetwork { public: virtual void begin() = 0; - virtual void tickNetworkLoop() = 0; virtual String getIp(void) = 0; virtual String getMac(void) = 0; @@ -242,10 +258,9 @@ class AhoyNetwork { // 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(); + mNtpTimeoutSec = 0; // clear timeout + mOnTimeCB(secsSince1900 - 2208988800UL); } protected: @@ -257,12 +272,15 @@ class AhoyNetwork { CONNECTING // ESP8266 }; + public: + bool mDnsCallbackReady = false; + protected: settings_t *mConfig = nullptr; - uint32_t *mUtcTimestamp = nullptr; bool mConnected = false; bool mScanActive = false; bool mWifiConnecting = false; + uint8_t mNtpTimeoutSec = 0; OnNetworkCB mOnNetworkCB; OnTimeCB mOnTimeCB; diff --git a/src/network/AhoyWifiEsp32.h b/src/network/AhoyWifiEsp32.h index 70017518..70d8119c 100644 --- a/src/network/AhoyWifiEsp32.h +++ b/src/network/AhoyWifiEsp32.h @@ -37,6 +37,7 @@ class AhoyWifi : public AhoyNetwork { } void tickNetworkLoop() override { + AhoyNetwork::tickNetworkLoop(); if(mAp.isEnabled()) mAp.tickLoop(); } diff --git a/src/network/AhoyWifiEsp8266.h b/src/network/AhoyWifiEsp8266.h index c72f06b5..03cd54b1 100644 --- a/src/network/AhoyWifiEsp8266.h +++ b/src/network/AhoyWifiEsp8266.h @@ -23,6 +23,7 @@ class AhoyWifi : public AhoyNetwork { } void tickNetworkLoop() override { + AhoyNetwork::tickNetworkLoop(); if(mAp.isEnabled()) mAp.tickLoop(); diff --git a/src/platformio.ini b/src/platformio.ini index 17031213..e6811e0b 100644 --- a/src/platformio.ini +++ b/src/platformio.ini @@ -154,7 +154,7 @@ platform = espressif32@6.7.0 board = lolin_d32 lib_deps = ${env.lib_deps} - https://github.com/mathieucarbou/ESPAsyncWebServer @ ^3.1.5 + https://github.com/mathieucarbou/ESPAsyncWebServer @ ^3.3.1 build_flags = ${env.build_flags} -DSPI_HAL monitor_filters = diff --git a/src/publisher/pubMqtt.h b/src/publisher/pubMqtt.h index 49b209f5..227a1310 100644 --- a/src/publisher/pubMqtt.h +++ b/src/publisher/pubMqtt.h @@ -409,20 +409,19 @@ class PubMqtt { bool total = (mDiscovery.lastIvId == MAX_NUM_INVERTERS); Inverter<> *iv = mSys->getInverterByPos(mDiscovery.lastIvId); - record_t<> *rec = NULL; - if (NULL != iv) { + record_t<> *rec = nullptr; + if (nullptr != iv) { rec = iv->getRecordStruct(RealTimeRunData_Debug); if(0 == mDiscovery.sub) - mDiscovery.foundIvCnt++; + mDiscovery.foundIvCnt++; } - if ((NULL != iv) || total) { + if ((nullptr != iv) || total) { if (!total) { doc[F("name")] = iv->config->name; doc[F("ids")] = String(iv->config->serial.u64, HEX); doc[F("mdl")] = iv->config->name; - } - else { + } else { doc[F("name")] = node_id; doc[F("ids")] = node_id; doc[F("mdl")] = node_id; @@ -441,6 +440,7 @@ class PubMqtt { uniq_id.fill(0); buf.fill(0); const char *devCls, *stateCls; + if (!total) { if (rec->assign[mDiscovery.sub].ch == CH0) snprintf(name.data(), name.size(), "%s", iv->getFieldName(mDiscovery.sub, rec)); @@ -468,20 +468,26 @@ class PubMqtt { doc2[F("unit_of_meas")] = ((!total) ? (iv->getUnit(mDiscovery.sub, rec)) : (unitTotal[mDiscovery.sub])); doc2[F("uniq_id")] = ((!total) ? (String(iv->config->serial.u64, HEX)) : (node_id)) + "_" + uniq_id.data(); doc2[F("dev")] = deviceObj; + if (!(String(stateCls) == String("total_increasing"))) doc2[F("exp_aft")] = MQTT_INTERVAL + 5; // add 5 sec if connection is bad or ESP too slow @TODO: stimmt das wirklich als expire!? - if (devCls != NULL) + if (devCls != nullptr) doc2[F("dev_cla")] = String(devCls); - if (stateCls != NULL) + if (stateCls != nullptr) doc2[F("stat_cla")] = String(stateCls); if (!total) snprintf(topic.data(), topic.size(), "%s/sensor/%s/ch%d_%s/config", MQTT_DISCOVERY_PREFIX, iv->config->name, rec->assign[mDiscovery.sub].ch, iv->getFieldName(mDiscovery.sub, rec)); else // total values snprintf(topic.data(), topic.size(), "%s/sensor/%s/total_%s/config", MQTT_DISCOVERY_PREFIX, node_id.c_str(), fields[fldTotal[mDiscovery.sub]]); + size_t size = measureJson(doc2) + 1; serializeJson(doc2, buf.data(), size); - if(FLD_EVT != rec->assign[mDiscovery.sub].fieldId) + + if(nullptr != rec) { + if(FLD_EVT != rec->assign[mDiscovery.sub].fieldId) + publish(topic.data(), buf.data(), true, false); + } else if(total) publish(topic.data(), buf.data(), true, false); if(++mDiscovery.sub == ((!total) ? (rec->length) : 4)) { diff --git a/src/utils/scheduler.h b/src/utils/scheduler.h index 5ce43a36..1f5ef7d7 100644 --- a/src/utils/scheduler.h +++ b/src/utils/scheduler.h @@ -73,21 +73,22 @@ namespace ah { } - void once(scdCb c, uint32_t timeout, const char *name) { addTicker(c, timeout, 0, false, name); } - void onceAt(scdCb c, uint32_t timestamp, const char *name) { addTicker(c, timestamp, 0, true, name); } - uint8_t every(scdCb c, uint32_t interval, const char *name){ return addTicker(c, interval, interval, false, name); } + uint8_t once(scdCb c, uint32_t timeout, const char *name) { return addTicker(c, timeout, 0, false, name); } + uint8_t onceAt(scdCb c, uint32_t timestamp, const char *name) { return addTicker(c, timestamp, 0, true, name); } + uint8_t every(scdCb c, uint32_t interval, const char *name) { return addTicker(c, interval, interval, false, name); } - void everySec(scdCb c, const char *name) { every(c, SCD_SEC, name); } - void everyMin(scdCb c, const char *name) { every(c, SCD_MIN, name); } - void everyHour(scdCb c, const char *name) { every(c, SCD_HOUR, name); } - void every12h(scdCb c, const char *name) { every(c, SCD_12H, name); } - void everyDay(scdCb c, const char *name) { every(c, SCD_DAY, name); } + uint8_t everySec(scdCb c, const char *name) { return every(c, SCD_SEC, name); } + uint8_t everyMin(scdCb c, const char *name) { return every(c, SCD_MIN, name); } + uint8_t everyHour(scdCb c, const char *name) { return every(c, SCD_HOUR, name); } + uint8_t every12h(scdCb c, const char *name) { return every(c, SCD_12H, name); } + uint8_t everyDay(scdCb c, const char *name) { return every(c, SCD_DAY, name); } virtual void setTimestamp(uint32_t ts) { mTimestamp = ts; } - bool resetEveryById(uint8_t id) { + bool resetById(uint8_t id) { + id = (id % (MAX_NUM_TICKER - 1)); if (mTickerInUse[id] == false) return false; mTicker[id].timeout = mTicker[id].reload;