From a6b95f8851ff760bf9ca7cae0f483a4f5a8f4cb8 Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 18 Sep 2026 00:26:28 +0200 Subject: [PATCH 1/5] [1Wire] Fix caching issue + multiple attempts scan sensors after save --- src/src/Helpers/Dallas1WireHelper.cpp | 101 ++++++++++++++------------ src/src/Helpers/Dallas1WireHelper.h | 2 +- src/src/Helpers/ESPEasy_Storage.cpp | 7 +- 3 files changed, 57 insertions(+), 53 deletions(-) diff --git a/src/src/Helpers/Dallas1WireHelper.cpp b/src/src/Helpers/Dallas1WireHelper.cpp index eb2c2372f..0a7602e3a 100644 --- a/src/src/Helpers/Dallas1WireHelper.cpp +++ b/src/src/Helpers/Dallas1WireHelper.cpp @@ -34,18 +34,18 @@ # endif // ifdef ESP32 -# ifndef DALLAS_RESET_RETRIES +# ifndef DALLAS_RETRIES // Reset may fail if a -# define DALLAS_RESET_RETRIES 3 -# endif // ifndef DALLAS_RESET_RETRIES +# define DALLAS_RETRIES 3 +# endif // ifndef DALLAS_RETRIES # include unsigned char ROM_NO[8]{ 0 }; uint8_t LastDiscrepancy{}; uint8_t LastFamilyDiscrepancy{}; -uint8_t LastDeviceFlag{}; +bool LastDeviceFlag{}; int32_t usec_release{}; int32_t presence_start{}; @@ -199,6 +199,28 @@ void Dallas_addr_selector_webform_load(taskIndex_t TaskIndex, int8_t gpio_pin_rx nrVariables = VARS_PER_TASK; } + // find all suitable devices + std::vector scan_res; + std::vector fixed_res; + + for (uint8_t attempt = 0; attempt < DALLAS_RETRIES && scan_res.size() == 0; ++attempt) + { + Dallas_reset_search(); + uint8_t tmpAddress[8]{}; + + while (Dallas_search(tmpAddress, gpio_pin_rx, gpio_pin_tx)) + { + scan_res.push_back(Dallas_addr_to_uint64(tmpAddress)); + bool hasFixedResolution = false; + Dallas_getResolution(tmpAddress, gpio_pin_rx, gpio_pin_tx, hasFixedResolution); + fixed_res.push_back(hasFixedResolution); + } + + if (scan_res.size() == 0) { + delay(5); + } + } + std::map addr_task_map; for (taskIndex_t task = 0; validTaskIndex(task); ++task) { @@ -226,20 +248,6 @@ void Dallas_addr_selector_webform_load(taskIndex_t TaskIndex, int8_t gpio_pin_rx } } - // find all suitable devices - std::vector scan_res; - std::vector fixed_res; - - Dallas_reset_search(); - uint8_t tmpAddress[8]{}; - - while (Dallas_search(tmpAddress, gpio_pin_rx, gpio_pin_tx)) - { - scan_res.push_back(Dallas_addr_to_uint64(tmpAddress)); - bool hasFixedResolution = false; - Dallas_getResolution(tmpAddress, gpio_pin_rx, gpio_pin_tx, hasFixedResolution); - fixed_res.push_back(hasFixedResolution); - } for (uint8_t var_index = 0; var_index < nrVariables; ++var_index) { String rowLabel = F("Device Address"); @@ -250,15 +258,21 @@ void Dallas_addr_selector_webform_load(taskIndex_t TaskIndex, int8_t gpio_pin_rx } addRowLabel(rowLabel); addSelector_Head(concat(F("dallas_addr"), static_cast(var_index))); - addSelector_Item(F("- None -"), -1, false); // Empty choice + addSelector_Item(F("- None -"), 0, false); // Empty choice + // get currently saved address - uint8_t savedAddress[8]; - Dallas_plugin_get_addr(savedAddress, TaskIndex, var_index); // Need to fetch only once? + uint64_t saved_addr64{}; + { + uint8_t savedAddress[8]; + Dallas_plugin_get_addr(savedAddress, TaskIndex, var_index); // Need to fetch only once? + saved_addr64 = Dallas_addr_to_uint64(savedAddress); + } for (uint8_t index = 0; index < scan_res.size(); ++index) { + const uint64_t scan_addr = scan_res[index]; uint8_t tmpAddress[8]{}; - Dallas_uint64_to_addr(scan_res[index], tmpAddress); + Dallas_uint64_to_addr(scan_addr, tmpAddress); String option; # ifndef LIMIT_BUILD_SIZE @@ -270,14 +284,14 @@ void Dallas_addr_selector_webform_load(taskIndex_t TaskIndex, int8_t gpio_pin_rx } # endif // ifndef LIMIT_BUILD_SIZE option += Dallas_format_address(tmpAddress, fixed_res[index]); - auto it = addr_task_map.find(scan_res[index]); + auto it = addr_task_map.find(scan_addr); if (it != addr_task_map.end()) { option += it->second; } - const bool selected = (memcmp(tmpAddress, savedAddress, 8) == 0); - addSelector_Item_index64(option, scan_res[index], selected); + const bool selected = scan_addr == saved_addr64; + addSelector_Item_index64(option, scan_addr, selected); } addSelector_Foot(); } @@ -793,7 +807,7 @@ bool Dallas_setResolution(const uint8_t ROM[8], uint8_t res, int8_t gpio_pin_rx, \*********************************************************************************************/ uint8_t Dallas_reset(int8_t gpio_pin_rx, int8_t gpio_pin_tx) { - for (uint8_t attempt = 0; attempt < DALLAS_RESET_RETRIES; ++attempt) { + for (uint8_t attempt = 0; attempt < DALLAS_RETRIES; ++attempt) { presence_start = 0; presence_end = 0; @@ -902,14 +916,12 @@ uint8_t Dallas_reset(int8_t gpio_pin_rx, int8_t gpio_pin_tx) ISR_interrupts(); } + delay(1); } return 0; } -# define FALSE 0 -# define TRUE 1 - /*********************************************************************************************\ * Dallas Reset Search \*********************************************************************************************/ @@ -917,7 +929,7 @@ void Dallas_reset_search() { // reset the search state LastDiscrepancy = 0; - LastDeviceFlag = FALSE; + LastDeviceFlag = false; LastFamilyDiscrepancy = 0; for (uint8_t i = 0; i < 8; i++) { @@ -930,16 +942,14 @@ void Dallas_reset_search() \*********************************************************************************************/ uint8_t Dallas_search(uint8_t *newAddr, int8_t gpio_pin_rx, int8_t gpio_pin_tx) { - uint8_t id_bit_number; - uint8_t last_zero, rom_byte_number, search_result; - unsigned char rom_byte_mask, search_direction; + unsigned char search_direction; // initialize for search - id_bit_number = 1; - last_zero = 0; - rom_byte_number = 0; - rom_byte_mask = 1; - search_result = 0; + uint8_t id_bit_number = 1; + uint8_t last_zero = 0; + uint8_t rom_byte_number = 0; + unsigned char rom_byte_mask = 1; + bool search_result = false; // if the last call was not the last one if (!LastDeviceFlag) @@ -949,9 +959,9 @@ uint8_t Dallas_search(uint8_t *newAddr, int8_t gpio_pin_rx, int8_t gpio_pin_tx) { // reset the search LastDiscrepancy = 0; - LastDeviceFlag = FALSE; + LastDeviceFlag = false; LastFamilyDiscrepancy = 0; - return FALSE; + return false; } // issue the search command @@ -1035,10 +1045,10 @@ uint8_t Dallas_search(uint8_t *newAddr, int8_t gpio_pin_rx, int8_t gpio_pin_tx) // check for last device if (LastDiscrepancy == 0) { - LastDeviceFlag = TRUE; + LastDeviceFlag = true; } - search_result = TRUE; + search_result = true; } } @@ -1046,9 +1056,9 @@ uint8_t Dallas_search(uint8_t *newAddr, int8_t gpio_pin_rx, int8_t gpio_pin_tx) if (!search_result || !ROM_NO[0]) { LastDiscrepancy = 0; - LastDeviceFlag = FALSE; + LastDeviceFlag = false; LastFamilyDiscrepancy = 0; - search_result = FALSE; + search_result = false; } for (int i = 0; i < 8; i++) { @@ -1058,9 +1068,6 @@ uint8_t Dallas_search(uint8_t *newAddr, int8_t gpio_pin_rx, int8_t gpio_pin_tx) return search_result; } -# undef FALSE -# undef TRUE - /*********************************************************************************************\ * Dallas Read byte \*********************************************************************************************/ diff --git a/src/src/Helpers/Dallas1WireHelper.h b/src/src/Helpers/Dallas1WireHelper.h index 308c9c226..9c5766464 100644 --- a/src/src/Helpers/Dallas1WireHelper.h +++ b/src/src/Helpers/Dallas1WireHelper.h @@ -63,7 +63,7 @@ struct Dallas_SensorData { extern unsigned char ROM_NO[8]; extern uint8_t LastDiscrepancy; extern uint8_t LastFamilyDiscrepancy; -extern uint8_t LastDeviceFlag; +extern bool LastDeviceFlag; /*********************************************************************************************\ diff --git a/src/src/Helpers/ESPEasy_Storage.cpp b/src/src/Helpers/ESPEasy_Storage.cpp index c31fd6ad1..edc455120 100644 --- a/src/src/Helpers/ESPEasy_Storage.cpp +++ b/src/src/Helpers/ESPEasy_Storage.cpp @@ -1480,17 +1480,14 @@ String LoadTaskSettings(taskIndex_t TaskIndex) START_TIMER ExtraTaskSettings.clear(); + Cache.clearTaskCache(TaskIndex); + const deviceIndex_t DeviceIndex = getDeviceIndex_from_TaskIndex(TaskIndex); if (!validDeviceIndex(DeviceIndex)) { // No need to load from storage, as there is no plugin assigned to this task. ExtraTaskSettings.TaskIndex = TaskIndex; // Needed when an empty task was requested - // FIXME TD-er: Do we need to keep a cache of an empty task? - // Maybe better to do this? - Cache.clearTaskCache(TaskIndex); - - // Cache.updateExtraTaskSettingsCache_afterLoad_Save(); return EMPTY_STRING; } #ifndef BUILD_NO_RAM_TRACKER From 2c53b7b82a4e12c1eeed6564faf1c32cd7e19470 Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 22 Sep 2026 23:51:29 +0200 Subject: [PATCH 2/5] [Time] Speedup getting first NTP time sync --- .github/workflows/build.yml | 2 +- .github/workflows/release.yml | 30 ++- platformio_core_defs.ini | 5 +- src/src/CustomBuild/define_plugin_sets.h | 10 + src/src/ESPEasyCore/ESPEasy_loop.cpp | 8 + src/src/ESPEasyCore/ESPEasy_setup.cpp | 7 +- src/src/Helpers/ESPEasy_time.cpp | 48 +++- src/src/Helpers/Networking.cpp | 36 ++- src/src/Helpers/PeriodicalActions.cpp | 262 ++++++++++++-------- src/src/Helpers/Scheduler_IntervalTimer.cpp | 1 + 10 files changed, 265 insertions(+), 144 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 22ca3e11f..fbf71b6ad 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -82,7 +82,7 @@ jobs: - name: Install dependencies run: | uv pip install --system pioarduino - uv pip install --system pygit2>=1.10.1 + uv pip install --system -r requirements.txt - name: Get current date id: date run: | diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e7fff86e0..2a2fa26de 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -41,28 +41,34 @@ jobs: - uses: actions/setup-python@v7 with: python-version: '3.13' - - name: Dependencies + - name: Install uv + uses: astral-sh/setup-uv@v7 + with: + version: "latest" + enable-cache: false + - name: Install dependencies run: | - sudo apt install binutils build-essential libffi-dev libgit2-dev - pip install uv + uv pip install --system pioarduino uv pip install --system -r requirements.txt - pio pkg update -e ${{ matrix.env }} - - name: Build and archive - id: build-and-archive - env: - CHIP: ${{ matrix.chip }} - ENV: ${{ matrix.env }} + - name: Get current date + id: date run: | - python tools/ci/build-and-archive.py + echo "builddate=$(date +'%Y%m%d')" >> $GITHUB_OUTPUT + - name: Run PlatformIO + env: + PYTHONIOENCODING: utf-8 + PYTHONUTF8: '1' + run: platformio run -e ${{ matrix.env }} - id: string uses: Entepotenz/change-string-case-action-min-dependencies@v1 with: string: ${{ matrix.chip }} - uses: actions/upload-artifact@v7 with: - name: Bin-${{ steps.string.outputs.uppercase }}-${{ matrix.env }} + # FIXME Workaround to (temporarily) not use # in the artifact name, see https://github.com/actions/upload-artifact/issues/473 + name: Bin-${{ steps.string.outputs.uppercase }}-${{ matrix.env }}-${{ steps.date.outputs.builddate }}_PR_${{ github.event.number }}_${{ github.run_id }} # Sort by ESP type path: | - bin + ./build_output/bin if-no-files-found: ignore prepare-dist: diff --git a/platformio_core_defs.ini b/platformio_core_defs.ini index 9f4134b3b..f888fceef 100644 --- a/platformio_core_defs.ini +++ b/platformio_core_defs.ini @@ -191,9 +191,8 @@ extra_scripts = ${esp82xx_common.extra_scripts} ;platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/2904-2115-5.5/framework-arduinoespressif32-release_v5.5-f2a3fa2b.tar.xz platform = https://github.com/Jason2866/platform-espressif32.git#Arduino/IDF55_gcc152 -;platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/1807-0842-5.5/framework-arduinoespressif32-release_v5.5-67336dba.tar.xz -;platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/2805-1324-5.5/framework-arduinoespressif32-release_v5.5-f3cdb9d0.tar.xz -platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/2708-1939-5.5.5/framework-arduinoespressif32-v5.5.5-a63b839f.tar.xz +;platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/2708-1939-5.5.5/framework-arduinoespressif32-v5.5.5-a63b839f.tar.xz +platform_packages = custom_remove_include = true diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index 343b463d4..10565a9a1 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -39,6 +39,16 @@ To create/register a plugin, you have to : \******************************************************************************/ // FIXME TD-er: Make useful selections for these pages to be included. (e.g. view only) + +// FIXME TD-er: Disable Arduino OTA for now, seems to cause crashes/bootloop on some ESP32-variants (C3/C6, maybe more) +// No idea why, disabled on 2026/09/22 +#ifdef FEATURE_ARDUINO_OTA + #undef FEATURE_ARDUINO_OTA +#endif +#define FEATURE_ARDUINO_OTA 0 + + + #ifndef WEBSERVER_CUSTOM_BUILD_DEFINED #ifndef WEBSERVER_TIMINGSTATS #define WEBSERVER_TIMINGSTATS diff --git a/src/src/ESPEasyCore/ESPEasy_loop.cpp b/src/src/ESPEasyCore/ESPEasy_loop.cpp index 1ecf979cb..8eaef522b 100644 --- a/src/src/ESPEasyCore/ESPEasy_loop.cpp +++ b/src/src/ESPEasyCore/ESPEasy_loop.cpp @@ -11,6 +11,7 @@ #include "../ESPEasyCore/ESPEasy_Log.h" #include "../ESPEasyCore/ESPEasy_backgroundtasks.h" #include "../Globals/ESPEasy_Scheduler.h" +#include "../Globals/ESPEasy_time.h" #include "../Globals/EventQueue.h" #include "../Globals/RTC.h" #include "../Globals/Settings.h" @@ -84,6 +85,7 @@ void ESPEasy_loop() #endif firstLoop = false; timerAwakeFromDeepSleep = millis(); // Allow to run for "awake" number of seconds, now we have wifi. + Scheduler.sendGratuitousARP_now(); // schedule_all_task_device_timers(); // Disabled for now, since we are now using queues for controllers. if (Settings.UseRules && isDeepSleepEnabled()) @@ -103,6 +105,7 @@ void ESPEasy_loop() #if FEATURE_ESPEASY_P2P sendSysInfoUDP(1); #endif + node_time.initTime(); } setWebserverRunning(ESPEasy::net::NWPluginCall(NWPlugin::Function::NWPLUGIN_WEBSERVER_SHOULD_RUN)); @@ -187,4 +190,9 @@ void ESPEasy_loop() // deepsleep will never return, its a special kind of reboot } + + if (firstLoopConnectionsEstablished) { + // FIXME TD-er: First NTP call may fail, so we make several here. + node_time.initTime(); + } } diff --git a/src/src/ESPEasyCore/ESPEasy_setup.cpp b/src/src/ESPEasyCore/ESPEasy_setup.cpp index 948c13f6e..fd90b1386 100644 --- a/src/src/ESPEasyCore/ESPEasy_setup.cpp +++ b/src/src/ESPEasyCore/ESPEasy_setup.cpp @@ -317,6 +317,8 @@ void ESPEasy_setup() RTC.bootFailedCount++; RTC.bootCounter++; lastMixedSchedulerId_beforereboot.mixed_id = RTC.lastMixedSchedulerId; + + node_time.restoreFromRTC(); readUserVarFromRTC(); log = concat(F("INIT : "), getLastBootCauseString()) + concat(F(" #"), RTC.bootCounter); @@ -359,6 +361,9 @@ void ESPEasy_setup() // progMemMD5check(); LoadSettings(); +#if FEATURE_EXT_RTC + node_time.restoreFromRTC(); +#endif #if FEATURE_DEFINE_SERIAL_CONSOLE_PORT ESPEasy_Console.reInit(); #endif // if FEATURE_DEFINE_SERIAL_CONSOLE_PORT @@ -398,8 +403,6 @@ void ESPEasy_setup() logMemUsageAfter(F("hardwareInit()")); #endif // ifndef BUILD_NO_RAM_TRACKER - node_time.restoreFromRTC(); - Settings.UseRTOSMultitasking = false; // For now, disable it, we experience heap corruption. if ((RTC.bootFailedCount > 10) && (RTC.bootCounter > 10)) { diff --git a/src/src/Helpers/ESPEasy_time.cpp b/src/src/Helpers/ESPEasy_time.cpp index 4922613d0..2bdeedb89 100644 --- a/src/src/Helpers/ESPEasy_time.cpp +++ b/src/src/Helpers/ESPEasy_time.cpp @@ -30,6 +30,7 @@ #include "../Helpers/Convert.h" +#include "../Helpers/ESPEasyRTC.h" #include "../Helpers/Hardware.h" #include "../Helpers/Hardware_I2C.h" #include "../Helpers/Misc.h" @@ -45,6 +46,14 @@ # include #endif // if FEATURE_EXT_RTC +#ifndef BUILD_NO_DEBUG +#define ESPEASY_NTP_DEBUG 1 +#else +#define ESPEASY_NTP_DEBUG 0 +#endif + + +#define ESPEASY_NTP_TIMEOUT 1000 ESPEasy_time::ESPEasy_time() { memset(&local_tm, 0, sizeof(tm)); @@ -258,6 +267,7 @@ uint32_t ESPEasy_time::now_() { _timeSource = extTimeSource; } else { if (!isExternalTimeSource(_timeSource) + || lastSyncTime_ms == 0 || (timePassedSince(lastSyncTime_ms) > static_cast(1000 * syncInterval))) { externalUnixTime_offset_usec = 0; @@ -439,6 +449,7 @@ uint32_t ESPEasy_time::now_() { } RTC.lastSysTime = getUnixTime(); uint32_t localSystime = time_zone.toLocal(RTC.lastSysTime); + saveToRTC(); breakTime(localSystime, local_tm); calcSunRiseAndSet(timeSynced); @@ -509,7 +520,7 @@ bool ESPEasy_time::systemTimePresent() const { bool ESPEasy_time::getNtpTime(double& unixTime_d) { - if (!Settings.UseNTP() || !ESPEasy::net::NetworkConnected(true)) { + if (!Settings.UseNTP() || !ESPEasy::net::NetworkConnected()) { return false; } @@ -549,7 +560,7 @@ bool ESPEasy_time::getNtpTime(double& unixTime_d) if (!hostReachable(timeServerIP)) { log += F(" unreachable"); - addLogMove(LOG_LEVEL_INFO, log); + addLogMove(LOG_LEVEL_ERROR, log); STOP_TIMER(NTP_FAIL); return false; } @@ -557,6 +568,10 @@ bool ESPEasy_time::getNtpTime(double& unixTime_d) WiFiUDP udp; if (!beginWiFiUDP_randomPort(udp)) { +#if ESPEASY_NTP_DEBUG + log += F(" failed beginWiFiUDP_randomPort"); + addLogMove(LOG_LEVEL_ERROR, log); +#endif return false; } @@ -567,8 +582,8 @@ bool ESPEasy_time::getNtpTime(double& unixTime_d) addLog(LOG_LEVEL_DEBUG_MORE, log); #endif // ifndef BUILD_NO_DEBUG - while (udp.parsePacket() > 0) { // discard any previously received packets - } +// while (udp.parsePacket() > 0) { // discard any previously received packets +// } FeedSW_watchdog(); @@ -576,6 +591,10 @@ bool ESPEasy_time::getNtpTime(double& unixTime_d) FeedSW_watchdog(); udp.stop(); STOP_TIMER(NTP_FAIL); +#if ESPEASY_NTP_DEBUG + log += F(" failed beginPacket"); + addLogMove(LOG_LEVEL_ERROR, log); +#endif return false; } constexpr int NTP_packet_size = sizeof(NTP_packet); @@ -590,7 +609,7 @@ bool ESPEasy_time::getNtpTime(double& unixTime_d) addLog(LOG_LEVEL_DEBUG, concat(F("NTP : before\n"), ntp_packet.toDebugString())); #endif // ifndef BUILD_NO_DEBUG - while (!timeOutReached(beginWait + 1000)) { + while (!timeOutReached(beginWait + ESPEASY_NTP_TIMEOUT)) { const int size = udp.parsePacket(); const int remotePort = udp.remotePort(); @@ -601,6 +620,10 @@ bool ESPEasy_time::getNtpTime(double& unixTime_d) #endif // ifndef BUILD_NO_DEBUG udp.stop(); STOP_TIMER(NTP_FAIL); +#if ESPEASY_NTP_DEBUG + log += concat(F(" Reply from wrong port: "), remotePort); + addLogMove(LOG_LEVEL_ERROR, log); +#endif return false; } udp.read(ntp_packet.data, NTP_packet_size); // read packet into the buffer @@ -626,6 +649,10 @@ bool ESPEasy_time::getNtpTime(double& unixTime_d) nextSyncTime = getUptime_in_sec() + 120; } STOP_TIMER(NTP_FAIL); +#if ESPEASY_NTP_DEBUG + log += F(" isUnsynchronized"); + addLogMove(LOG_LEVEL_ERROR, log); +#endif return false; } @@ -664,6 +691,10 @@ bool ESPEasy_time::getNtpTime(double& unixTime_d) // or no valid timestamps from the NTP server. nextSyncTime = getUptime_in_sec() + 60; STOP_TIMER(NTP_FAIL); +#if ESPEASY_NTP_DEBUG + log += F(" failed compute_usec"); + addLogMove(LOG_LEVEL_ERROR, log); +#endif return false; } @@ -707,10 +738,15 @@ bool ESPEasy_time::getNtpTime(double& unixTime_d) // Timeout. if (!useNTPpool) { // Retry again in a minute. - nextSyncTime = getUptime_in_sec() + 60; + nextSyncTime = getUptime_in_sec() + 10; } #ifndef BUILD_NO_DEBUG +#if ESPEASY_NTP_DEBUG + log += strformat(F(" No reply, duration: %d ms"), timePassedSince(beginWait)); + addLogMove(LOG_LEVEL_ERROR, log); +#endif + addLog(LOG_LEVEL_DEBUG_MORE, F("NTP : No reply")); #endif // ifndef BUILD_NO_DEBUG udp.stop(); diff --git a/src/src/Helpers/Networking.cpp b/src/src/Helpers/Networking.cpp index faeb85b5e..7f6f2ab1a 100644 --- a/src/src/Helpers/Networking.cpp +++ b/src/src/Helpers/Networking.cpp @@ -1211,7 +1211,7 @@ bool setDNS(int index, const IPAddress& dns) { bool resolveHostByName(const char *aHostname, IPAddress& aResult, uint32_t timeout_ms) { START_TIMER; - if (!ESPEasy::net::NetworkConnected(true)) { + if (!ESPEasy::net::NetworkConnected()) { return false; } @@ -1220,16 +1220,32 @@ bool resolveHostByName(const char *aHostname, IPAddress& aResult, uint32_t timeo // FIXME TD-er: Must try to restore DNS server entries. scrubDNS(); -#if defined(ARDUINO_ESP8266_RELEASE_2_3_0) || defined(ESP32) - bool resolvedIP = WiFi.hostByName(aHostname, aResult) == 1; -#else // if defined(ARDUINO_ESP8266_RELEASE_2_3_0) || defined(ESP32) - bool resolvedIP = WiFi.hostByName(aHostname, aResult, timeout_ms) == 1; -#endif // if defined(ARDUINO_ESP8266_RELEASE_2_3_0) || defined(ESP32) - delay(0); - FeedSW_watchdog(); + bool resolvedIP{}; + String host(aHostname); + host.trim(); - if (!resolvedIP) { - Scheduler.sendGratuitousARP_now(); + uint32_t start = millis(); + + for (int attempt = 0; + attempt < 2 && !resolvedIP && timePassedSince(start) < timeout_ms; + ++attempt) { + +#if defined(ARDUINO_ESP8266_RELEASE_2_3_0) + resolvedIP = WiFi.hostByName(host.c_str(), aResult) == 1; +#elif defined(ESP32) + resolvedIP = Network.hostByName(host.c_str(), aResult) == 1; +#else // if defined(ARDUINO_ESP8266_RELEASE_2_3_0) || defined(ESP32) + resolvedIP = WiFi.hostByName(host.c_str(), aResult, timeout_ms) == 1; +#endif // if defined(ARDUINO_ESP8266_RELEASE_2_3_0) || defined(ESP32) + delay(0); + FeedSW_watchdog(); + + if (!resolvedIP && attempt == 0) { + #ifdef ESP32 + dns_clear_cache(); + #endif + Scheduler.sendGratuitousARP_now(); + } } STOP_TIMER(HOST_BY_NAME_STATS); return resolvedIP; diff --git a/src/src/Helpers/PeriodicalActions.cpp b/src/src/Helpers/PeriodicalActions.cpp index 35266815f..59b874b63 100644 --- a/src/src/Helpers/PeriodicalActions.cpp +++ b/src/src/Helpers/PeriodicalActions.cpp @@ -42,39 +42,41 @@ #ifdef USES_C015 -#include "../../ESPEasy_fdwdecl.h" +# include "../../ESPEasy_fdwdecl.h" #endif #if FEATURE_MDNS -#include "../Helpers/MDNS_Helper.h" +# include "../Helpers/MDNS_Helper.h" #endif #define PLUGIN_ID_MQTT_IMPORT 37 - /*********************************************************************************************\ - * Tasks that run 50 times per second +* Tasks that run 50 times per second \*********************************************************************************************/ - void run50TimesPerSecond() { String dummy; { - // Do network calls first, so any needed checks or updates are done + // Do network calls first, so any needed checks or updates are done // before any controller may need to use the network #ifdef ESP32 static const NetworkInterface *lastDefaultInterface = nullptr; - NetworkInterface * currentDefaultInterface = Network.getDefaultInterface(); - if (nonDefaultNetworkInterface_gotIP || - networkConnectionFailed || - lastDefaultInterface != currentDefaultInterface) { + NetworkInterface *currentDefaultInterface = Network.getDefaultInterface(); + + if (nonDefaultNetworkInterface_gotIP || + networkConnectionFailed || + (lastDefaultInterface != currentDefaultInterface)) { nonDefaultNetworkInterface_gotIP = false; // TODO TD-er: Must do something else here on failed connect? networkConnectionFailed = false; - ESPEasy::net::NWPluginCall(NWPlugin::Function::NWPLUGIN_PRIORITY_ROUTE_CHANGED, 0, dummy); + + if (lastDefaultInterface != currentDefaultInterface) { + ESPEasy::net::NWPluginCall(NWPlugin::Function::NWPLUGIN_PRIORITY_ROUTE_CHANGED, 0, dummy); + } lastDefaultInterface = currentDefaultInterface; } -#endif +#endif // ifdef ESP32 START_TIMER; ESPEasy::net::NWPluginCall(NWPlugin::Function::NWPLUGIN_FIFTY_PER_SECOND, 0, dummy); @@ -98,11 +100,12 @@ void run50TimesPerSecond() { } /*********************************************************************************************\ - * Tasks that run 10 times per second +* Tasks that run 10 times per second \*********************************************************************************************/ void run10TimesPerSecond() { String dummy; - //@giig19767g: WARNING: Monitor10xSec must run before PLUGIN_TEN_PER_SECOND + + // @giig19767g: WARNING: Monitor10xSec must run before PLUGIN_TEN_PER_SECOND { START_TIMER; GPIO_Monitor10xSec(); @@ -120,7 +123,8 @@ void run10TimesPerSecond() { } { START_TIMER; -// PluginCall(PLUGIN_UNCONDITIONAL_POLL, 0, dummyString); + + // PluginCall(PLUGIN_UNCONDITIONAL_POLL, 0, dummyString); PluginCall(PLUGIN_MONITOR, 0, dummy); STOP_TIMER(PLUGIN_CALL_10PSU); } @@ -129,14 +133,16 @@ void run10TimesPerSecond() { CPluginCall(CPlugin::Function::CPLUGIN_TEN_PER_SECOND, 0, dummy); STOP_TIMER(CPLUGIN_CALL_10PS); } - + #ifdef USES_C015 + if (ESPEasy::net::NetworkConnected()) { Blynk_Run_c015(); } - #endif - if (!UseRTOSMultitasking && - (ESPEasy::net::NetworkConnected() || ESPEasy::net::wifi::wifiAPmodeActivelyUsed())) { + #endif // ifdef USES_C015 + + if (!UseRTOSMultitasking && + (ESPEasy::net::NetworkConnected() || ESPEasy::net::wifi::wifiAPmodeActivelyUsed())) { // FIXME TD-er: What about client connected via AP? START_TIMER web_server.handleClient(); @@ -144,20 +150,20 @@ void run10TimesPerSecond() { } } - /*********************************************************************************************\ - * Tasks each second +* Tasks each second \*********************************************************************************************/ void runOncePerSecond() { START_TIMER; updateLogLevelCache(); dailyResetCounter++; + if (dailyResetCounter > 86400) // 1 day elapsed... //86400 { - RTC.flashDayCounter=0; + RTC.flashDayCounter = 0; saveToRTC(); - dailyResetCounter=0; + dailyResetCounter = 0; #ifndef LIMIT_BUILD_SIZE addLog(LOG_LEVEL_INFO, F("SYS : Reset 24h counters")); #endif @@ -165,37 +171,42 @@ void runOncePerSecond() if (Settings.ConnectionFailuresThreshold) { auto data = ESPEasy::net::getDefaultRoute_NWPluginData_static_runtime(); - if (data && data->getConnectionFailures() > Settings.ConnectionFailuresThreshold) + + if (data && (data->getConnectionFailures() > Settings.ConnectionFailuresThreshold)) { delayedReboot(60, IntendedRebootReason_e::DelayedReboot); + } } + if (cmd_within_mainloop != 0) { switch (cmd_within_mainloop) { case CMD_WIFI_DISCONNECT: - { - ESPEasy::net::wifi::WifiDisconnect(); - break; - } + { + ESPEasy::net::wifi::WifiDisconnect(); + break; + } case CMD_REBOOT: - { - reboot(IntendedRebootReason_e::CommandReboot); - break; - } + { + reboot(IntendedRebootReason_e::CommandReboot); + break; + } } cmd_within_mainloop = 0; } + // clock events if (node_time.reportNewMinute()) { String dummy; PluginCall(PLUGIN_CLOCK_IN, 0, dummy); + if (Settings.UseRules) { // FIXME TD-er: What to do when the system time is not (yet) present? if (node_time.systemTimePresent()) { // TD-er: Do not add to the eventQueue, but execute right now. const String event = strformat( - F("Clock#Time=%s,%s"), + F("Clock#Time=%s,%s"), node_time.weekday_str().c_str(), node_time.getTimeString(':', false).c_str()); rulesProcessing(event); @@ -203,12 +214,14 @@ void runOncePerSecond() } } -// uint32_t start = micros(); + // uint32_t start = micros(); String dummy; PluginCall(PLUGIN_ONCE_A_SECOND, 0, dummy); -// uint32_t elapsed = micros() - start; + + // uint32_t elapsed = micros() - start; #if FEATURE_NETWORK_STATS + for (ESPEasy::net::networkIndex_t x = 0; x < NETWORK_MAX; x++) { if (Settings.getNetworkEnabled(x)) { EventStruct tempEvent; @@ -216,26 +229,28 @@ void runOncePerSecond() ESPEasy::net::NWPluginCall(NWPlugin::Function::NWPLUGIN_RECORD_STATS, &tempEvent); } } -#endif +#endif // if FEATURE_NETWORK_STATS // I2C Watchdog feed #if FEATURE_I2C + if (Settings.WDI2CAddress != 0) { - #if FEATURE_I2C_MULTIPLE + # if FEATURE_I2C_MULTIPLE I2CSelectHighClockSpeed(Settings.getI2CInterfaceWDT()); // Select bus - #endif // if FEATURE_I2C_MULTIPLE + # endif // if FEATURE_I2C_MULTIPLE I2C_write8(Settings.WDI2CAddress, 0xA5); } -#endif +#endif // if FEATURE_I2C #if FEATURE_MDNS - #ifdef ESP8266 + # ifdef ESP8266 + // Allow MDNS processing if (ESPEasy::net::NetworkConnected()) { MDNS.announce(); } - #endif + # endif // ifdef ESP8266 #endif // if FEATURE_MDNS #if FEATURE_INTERNAL_TEMPERATURE && defined(ESP32_CLASSIC) @@ -247,21 +262,22 @@ void runOncePerSecond() } /*********************************************************************************************\ - * Tasks each 30 seconds +* Tasks each 30 seconds \*********************************************************************************************/ void runEach30Seconds() { #ifndef BUILD_NO_RAM_TRACKER checkRAMtoLog(); #endif - wdcounter++; - if (loglevelActiveFor(LOG_LEVEL_INFO)) { + + if (loglevelActiveFor(LOG_LEVEL_INFO)) { auto data = ESPEasy::net::getDefaultRoute_NWPluginData_static_runtime(); + if (!data) { addLogMove(LOG_LEVEL_INFO, strformat( - F("WD : Uptime %d FreeMem %u"), - getUptimeMinutes(), - FreeMem())); + F("WD : Uptime %d FreeMem %u"), + getUptimeMinutes(), + FreeMem())); } else { String log = strformat( F("WD : Uptime %d ConnectFailures %u FreeMem %u"), @@ -270,14 +286,17 @@ void runEach30Seconds() FreeMem()); bool logWiFiStatus = true; #if FEATURE_ETHERNET - if(active_network_medium == ESPEasy::net::NetworkMedium_t::Ethernet) { + + if (active_network_medium == ESPEasy::net::NetworkMedium_t::Ethernet) { logWiFiStatus = false; - log += F( " EthSpeedState "); - log += getValue(LabelType::ETH_SPEED_STATE); -// log += F(" ETH status: "); -// log += EthEventData.ESPEasyEthStatusToString(); + log += F(" EthSpeedState "); + log += getValue(LabelType::ETH_SPEED_STATE); + + // log += F(" ETH status: "); + // log += EthEventData.ESPEasyEthStatusToString(); } #endif // if FEATURE_ETHERNET + if (logWiFiStatus) { log += strformat( F(" WiFiStatus: %s ESPeasy internal wifi status: %s (%s)"), @@ -285,35 +304,41 @@ void runEach30Seconds() FsP(ESPEasy::net::wifi::toString(ESPEasyWiFi.getState())), data->statusToString().c_str()); } - // log += F(" ListenInterval "); - // log += WiFi.getListenInterval(); + + // log += F(" ListenInterval "); + // log += WiFi.getListenInterval(); addLogMove(LOG_LEVEL_INFO, log); #if FEATURE_DEFINE_SERIAL_CONSOLE_PORT - // addLogMove(LOG_LEVEL_INFO, ESPEASY_SERIAL_CONSOLE_PORT.getLogString()); -#endif + + // addLogMove(LOG_LEVEL_INFO, ESPEASY_SERIAL_CONSOLE_PORT.getLogString()); +#endif // if FEATURE_DEFINE_SERIAL_CONSOLE_PORT } } ESPEasy::net::wifi::WiFi_AP_Candidates.purge_expired(); #if FEATURE_ESPEASY_P2P sendSysInfoUDP(1); refreshNodeList(); - #endif + #endif // if FEATURE_ESPEASY_P2P // sending $stats to homie controller CPluginCall(CPlugin::Function::CPLUGIN_INTERVAL, 0); #if defined(ESP8266) - #if FEATURE_SSDP - if (Settings.UseSSDP) - SSDP_update(); + # if FEATURE_SSDP - #endif // if FEATURE_SSDP - #endif + if (Settings.UseSSDP) { + SSDP_update(); + } + + # endif // if FEATURE_SSDP + #endif // if defined(ESP8266) #if FEATURE_ADC_VCC -// if (!WiFiEventData.wifiConnectInProgress) { - vcc = ESP.getVcc() / 1000.0f; -// } -#endif + + // if (!WiFiEventData.wifiConnectInProgress) { + vcc = ESP.getVcc() / 1000.0f; + + // } +#endif // if FEATURE_ADC_VCC #if FEATURE_REPORTING ReportStatus(); @@ -323,7 +348,6 @@ void runEach30Seconds() #if FEATURE_MQTT - void scheduleNextMQTTdelayQueue() { if (MQTTDelayHandler != nullptr) { Scheduler.scheduleNextDelayQueue(SchedulerIntervalTimer_e::TIMER_MQTT_DELAY_QUEUE, MQTTDelayHandler->getNextScheduleTime()); @@ -334,6 +358,7 @@ void schedule_all_MQTTimport_tasks() { constexpr pluginID_t PLUGIN_MQTT_IMPORT(PLUGIN_ID_MQTT_IMPORT); deviceIndex_t DeviceIndex = getDeviceIndex(PLUGIN_MQTT_IMPORT); // Check if P037_MQTTimport is present in the build + if (validDeviceIndex(DeviceIndex)) { for (taskIndex_t task = 0; task < TASKS_MAX; task++) { if ((Settings.getPluginID_for_task(task) == PLUGIN_MQTT_IMPORT) && @@ -343,7 +368,7 @@ void schedule_all_MQTTimport_tasks() { event.Par1 = MQTTclient_connected ? 1 : 0; Scheduler.schedule_plugin_task_event_timer( task, - PLUGIN_MQTT_CONNECTION_STATE, + PLUGIN_MQTT_CONNECTION_STATE, std::move(event)); } } @@ -355,6 +380,7 @@ void processMQTTdelayQueue() { return; } runPeriodicalMQTT(); // Update MQTT connected state. + if (!MQTTclient_connected) { scheduleNextMQTTdelayQueue(); return; @@ -372,8 +398,8 @@ void processMQTTdelayQueue() { String dummy; // FIXME TD-er: Do we need anything from the element in the event? -// TempEvent.String1 = element->_topic; -// TempEvent.String2 = element->_payload; + // TempEvent.String1 = element->_topic; + // TempEvent.String2 = element->_payload; if (PluginCall(PLUGIN_PROCESS_CONTROLLER_DATA, &TempEvent, dummy)) { handled = true; MQTTDelayHandler->markProcessed(true); @@ -384,13 +410,14 @@ void processMQTTdelayQueue() { if (!handled) { if (MQTTclient.publish(element->_topic.c_str(), element->_payload.c_str(), element->_retained)) { auto data = ESPEasy::net::getDefaultRoute_NWPluginData_static_runtime(); + if (data) { data->markPublishSuccess(); } MQTTDelayHandler->markProcessed(true); } else { MQTTDelayHandler->markProcessed(false); -#ifndef BUILD_NO_DEBUG +# ifndef BUILD_NO_DEBUG if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { String log = F("MQTT : process MQTT queue not published, "); @@ -398,40 +425,46 @@ void processMQTTdelayQueue() { log += F(" items left in queue"); addLogMove(LOG_LEVEL_DEBUG, log); } -#endif // ifndef BUILD_NO_DEBUG +# endif // ifndef BUILD_NO_DEBUG } } - Scheduler.setIntervalTimerOverride(SchedulerIntervalTimer_e::TIMER_MQTT, 10); // Make sure the MQTT is being processed as soon as possible. + Scheduler.setIntervalTimerOverride(SchedulerIntervalTimer_e::TIMER_MQTT, 10); // Make sure the MQTT is being processed as soon as + // possible. scheduleNextMQTTdelayQueue(); STOP_TIMER(MQTT_DELAY_QUEUE); } void updateMQTTclient_connected() { const bool actual_MQTTclient_connected = ESPEasy::net::NetworkConnected(true) && MQTTclient.connected(); + if (MQTTclient_connected != actual_MQTTclient_connected) { MQTTclient_connected = actual_MQTTclient_connected; + if (!actual_MQTTclient_connected) { // Make sure PubSubClient isn't trying to do a graceful disconnect // FIXME TD-er: This seems to cause a crash on ESP32-xx, though no idea how to fix. // See also: https://github.com/espressif/arduino-esp32/issues/12517 - mqtt.stop(); + mqtt.stop(); } MQTTclient_connected_stats.set(actual_MQTTclient_connected); + if (!MQTTclient_connected) { if (loglevelActiveFor(LOG_LEVEL_ERROR)) { String connectionError = F("MQTT : Connection lost, state: "); connectionError += getMQTT_state(); -#ifndef BUILD_NO_DEBUG +# ifndef BUILD_NO_DEBUG auto duration_ms = MQTTclient_connected_stats.getLastOnDuration_ms(); + if (duration_ms > 0) { connectionError += concat(F(" Connected duration: "), format_msec_duration_HMS(duration_ms)); connectionError += concat(F(" (successful) Reconnect Count: "), MQTTclient_connected_stats.getCycleCount()); } -#endif +# endif // ifndef BUILD_NO_DEBUG addLogMove(LOG_LEVEL_ERROR, connectionError); } MQTTclient_must_send_LWT_connected = false; } + if (Settings.UseRules) { if (MQTTclient_connected) { eventQueue.add(F("MQTT#Connected")); @@ -439,9 +472,11 @@ void updateMQTTclient_connected() { eventQueue.add(F("MQTT#Disconnected")); } } + // Now schedule all tasks using the MQTT Import plugin. schedule_all_MQTTimport_tasks(); } + if (!MQTTclient_connected) { // As suggested here: https://github.com/letscontrolit/ESPEasy/issues/1356 if (timermqtt_interval < 30000) { @@ -452,36 +487,41 @@ void updateMQTTclient_connected() { } Scheduler.setIntervalTimer(SchedulerIntervalTimer_e::TIMER_MQTT); scheduleNextMQTTdelayQueue(); - #if FEATURE_MQTT_CONNECT_BACKGROUND + # if FEATURE_MQTT_CONNECT_BACKGROUND MQTTConnectInBackground(CONTROLLER_MAX, true); // Report state - #endif // if FEATURE_MQTT_CONNECT_BACKGROUND + # endif // if FEATURE_MQTT_CONNECT_BACKGROUND } void runPeriodicalMQTT() { START_TIMER + // MQTT_KEEPALIVE = 15 seconds. if (!ESPEasy::net::NetworkConnected()) { updateMQTTclient_connected(); return; } - //dont do this in backgroundtasks(), otherwise causes crashes. (https://github.com/letscontrolit/ESPEasy/issues/683) + + // dont do this in backgroundtasks(), otherwise causes crashes. (https://github.com/letscontrolit/ESPEasy/issues/683) controllerIndex_t enabledMqttController = firstEnabledMQTT_ControllerIndex(); + if (validControllerIndex(enabledMqttController)) { if (!MQTTclient.loop()) { updateMQTTclient_connected(); + if (MQTTCheck(enabledMqttController)) { updateMQTTclient_connected(); } } } else { if (MQTTclient.connected()) { - #if FEATURE_MQTT_CONNECT_BACKGROUND + # if FEATURE_MQTT_CONNECT_BACKGROUND + if (MQTT_task_data.taskHandle) { vTaskDelete(MQTT_task_data.taskHandle); MQTT_task_data.taskHandle = NULL; } MQTT_task_data.status = MQTT_connect_status_e::Disconnected; - #endif // if FEATURE_MQTT_CONNECT_BACKGROUND + # endif // if FEATURE_MQTT_CONNECT_BACKGROUND MQTTclient.disconnect(); updateMQTTclient_connected(); } @@ -489,40 +529,40 @@ void runPeriodicalMQTT() { STOP_TIMER(PERIODICAL_MQTT); } - -#endif //if FEATURE_MQTT - - +#endif // if FEATURE_MQTT void logTimerStatistics() { + // This function is called every 30 seconds. + wdcounter++; loopCounterLast = loopCounter; - loopCounter = 0; - if (loopCounterLast > loopCounterMax) + loopCounter = 0; + + if (loopCounterLast > loopCounterMax) { loopCounterMax = loopCounterLast; + } Scheduler.updateIdleTimeStats(); #ifndef BUILD_NO_DEBUG const uint8_t loglevel = LOG_LEVEL_DEBUG; + if (loglevelActiveFor(loglevel)) { addLogMove(loglevel, strformat( - F("LoopStats: shortest: %u longest: %u avg: %.2f LC_Max: %u LC_Last: %u"), - shortestLoop, - longestLoop, - loop_usec_duration_total / loopCounter_full, - loopCounterMax, - loopCounterLast)); + F("LoopStats: shortest: %u longest: %u avg: %.2f LC_Max: %u LC_Last: %u"), + shortestLoop, + longestLoop, + loop_usec_duration_total / loopCounter_full, + loopCounterMax, + loopCounterLast)); addLogMove(loglevel, concat( - F("Scheduler stats: (called/tasks/max_length/idle%) "), - Scheduler.getQueueStats())); + F("Scheduler stats: (called/tasks/max_length/idle%) "), + Scheduler.getQueueStats())); } -#endif +#endif // ifndef BUILD_NO_DEBUG loop_usec_duration_total = 0; - loopCounter_full = 1; + loopCounter_full = 1; } - - /********************************************************************************************\ Clean up all before going to sleep or reboot. \*********************************************************************************************/ @@ -530,30 +570,34 @@ void flushAndDisconnectAllClients() { if (anyControllerEnabled()) { #if FEATURE_MQTT bool mqttControllerEnabled = validControllerIndex(firstEnabledMQTT_ControllerIndex()); -#endif //if FEATURE_MQTT +#endif // if FEATURE_MQTT uint32_t timer = millis() + 1000; + while (!timeOutReached(timer)) { // call to all controllers (delay queue) to flush all data. CPluginCall(CPlugin::Function::CPLUGIN_FLUSH, 0); -#if FEATURE_MQTT +#if FEATURE_MQTT + if (mqttControllerEnabled && MQTTclient.connected()) { MQTTclient.loop(); } -#endif //if FEATURE_MQTT +#endif // if FEATURE_MQTT } #if FEATURE_MQTT + if (mqttControllerEnabled && MQTTclient.connected()) { - #if FEATURE_MQTT_CONNECT_BACKGROUND + # if FEATURE_MQTT_CONNECT_BACKGROUND + if (MQTT_task_data.taskHandle) { vTaskDelete(MQTT_task_data.taskHandle); MQTT_task_data.taskHandle = NULL; } MQTT_task_data.status = MQTT_connect_status_e::Disconnected; - #endif // if FEATURE_MQTT_CONNECT_BACKGROUND + # endif // if FEATURE_MQTT_CONNECT_BACKGROUND MQTTclient.disconnect(); updateMQTTclient_connected(); } -#endif //if FEATURE_MQTT +#endif // if FEATURE_MQTT saveToRTC(); delay(100); // Flush anything in the network buffers. } @@ -561,14 +605,13 @@ void flushAndDisconnectAllClients() { process_serialWriteBuffer(); } - void prepareShutdown(IntendedRebootReason_e reason) { #if FEATURE_MDNS end_mDNS(); #endif -// WiFiEventData.intent_to_reboot = true; + // WiFiEventData.intent_to_reboot = true; #if FEATURE_MQTT runPeriodicalMQTT(); // Flush outstanding MQTT messages #endif // if FEATURE_MQTT @@ -577,7 +620,8 @@ void prepareShutdown(IntendedRebootReason_e reason) saveUserVarToRTC(); CPluginCall(CPlugin::Function::CPLUGIN_EXIT_ALL, 0); ESPEasy::net::NWPluginCall(NWPlugin::Function::NWPLUGIN_EXIT_ALL, 0); -// ESPEasy::net::wifi::setWifiMode(WIFI_OFF); + + // ESPEasy::net::wifi::setWifiMode(WIFI_OFF); ESPEASY_FS.end(); process_serialWriteBuffer(); delay(100); // give the node time to flush all before reboot or sleep @@ -585,5 +629,3 @@ void prepareShutdown(IntendedRebootReason_e reason) Scheduler.markIntendedReboot(reason); saveToRTC(); } - - diff --git a/src/src/Helpers/Scheduler_IntervalTimer.cpp b/src/src/Helpers/Scheduler_IntervalTimer.cpp index 0ff4790e5..5a67e51e0 100644 --- a/src/src/Helpers/Scheduler_IntervalTimer.cpp +++ b/src/src/Helpers/Scheduler_IntervalTimer.cpp @@ -141,6 +141,7 @@ void ESPEasy_Scheduler::setIntervalTimer(SchedulerIntervalTimer_e intervalTimer, } void ESPEasy_Scheduler::sendGratuitousARP_now() { + if (!ESPEasy::net::NetworkConnected(true)) return; sendGratuitousARP(); if (Settings.gratuitousARP()) { From 488cb70ba9e20fa1e1c2b7422867433044889abd Mon Sep 17 00:00:00 2001 From: TD-er Date: Wed, 7 Oct 2026 08:23:54 +0200 Subject: [PATCH 3/5] [WiFi] Fix setting TX power on ESP32 when not exactly matching pwr value --- .../net/wifi/ESPEasyWifi_abstracted_ESP32.cpp | 41 +++++++++++++++---- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/src/ESPEasy/net/wifi/ESPEasyWifi_abstracted_ESP32.cpp b/src/ESPEasy/net/wifi/ESPEasyWifi_abstracted_ESP32.cpp index cb98c3b84..893196975 100644 --- a/src/ESPEasy/net/wifi/ESPEasyWifi_abstracted_ESP32.cpp +++ b/src/ESPEasy/net/wifi/ESPEasyWifi_abstracted_ESP32.cpp @@ -47,11 +47,11 @@ bool WiFi_pre_STA_setup() void doWiFiDisconnect() { uint8_t retry = 3; - #ifdef BOARD_HAS_SDIO_ESP_HOSTED + # ifdef BOARD_HAS_SDIO_ESP_HOSTED bool wifioff = true; - #else + # else bool wifioff = Settings.WiFiRestart_connection_lost(); - #endif + # endif // ifdef BOARD_HAS_SDIO_ESP_HOSTED while (!WiFi.disconnect(wifioff) && retry) { --retry; @@ -402,13 +402,40 @@ WiFiConnectionProtocol doGetConnectionProtocol() void doSetWiFiTXpower(float& dBm) { - int8_t power = dBm * 4; + if (WiFi.STA.started() || WiFi.AP.started()) { + int8_t power = std::min(static_cast(dBm * 4), static_cast(WIFI_POWER_21dBm)); - esp_wifi_set_max_tx_power(power); + constexpr wifi_power_t options[] = { + WIFI_POWER_21dBm, + WIFI_POWER_20_5dBm, + WIFI_POWER_20dBm, + WIFI_POWER_19_5dBm, + WIFI_POWER_19dBm, + WIFI_POWER_18_5dBm, + WIFI_POWER_17dBm, + WIFI_POWER_15dBm, + WIFI_POWER_13dBm, + WIFI_POWER_11dBm, + WIFI_POWER_8_5dBm, + WIFI_POWER_7dBm, + WIFI_POWER_5dBm, + WIFI_POWER_2dBm, + WIFI_POWER_MINUS_1dBm + }; - if (esp_wifi_get_max_tx_power(&power) == ESP_OK) { - dBm = static_cast(power) / 4.0f; + for (size_t i = 0; i < NR_ELEMENTS(options); ++i) { + if (power <= options[i]) { + power = options[i]; + esp_wifi_set_max_tx_power(power); + + if (esp_wifi_get_max_tx_power(&power) == ESP_OK) { + dBm = static_cast(power) / 4.0f; + } + return; + } + } } + dBm = 0; } float doGetWiFiTXpower() From 050017b2b00e1512e46ccc9bc3e2d0568a8c15d7 Mon Sep 17 00:00:00 2001 From: TD-er Date: Wed, 7 Oct 2026 08:27:40 +0200 Subject: [PATCH 4/5] [DNS] Fix hostByName returning negative values when lookup failed `hostByName` does only return `1` on success, however it may return a negative value when lookup failed. So need to check for the exact return value and not consider it a boolean return type. --- lib/ESPping/src/ESPping.cpp | 2 +- lib/HttpClientLight/src/HttpClientLight.cpp | 2 +- lib/lib_ssl/tls_mini/src/WiFiClientSecureLightBearSSL.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/ESPping/src/ESPping.cpp b/lib/ESPping/src/ESPping.cpp index 2d151fd6e..e8bbd33ae 100644 --- a/lib/ESPping/src/ESPping.cpp +++ b/lib/ESPping/src/ESPping.cpp @@ -72,7 +72,7 @@ bool PingClass::ping(IPAddress dest, int16_t count) { bool PingClass::ping(const char* host, int16_t count) { IPAddress remote_addr; - if (WiFi.hostByName(host, remote_addr)) + if (WiFi.hostByName(host, remote_addr) == 1) return ping(remote_addr, count); return false; diff --git a/lib/HttpClientLight/src/HttpClientLight.cpp b/lib/HttpClientLight/src/HttpClientLight.cpp index a6809035f..efb8af6f1 100644 --- a/lib/HttpClientLight/src/HttpClientLight.cpp +++ b/lib/HttpClientLight/src/HttpClientLight.cpp @@ -1173,7 +1173,7 @@ bool HTTPClientLight::connect(void) } else { IPAddress remote_addr; // Add include "ESP8266WiFi.h" for this to work - if (!WiFi.hostByName(_host.c_str(), remote_addr)) { + if (Network.hostByName(_host.c_str(), remote_addr) != 1) { return false; } if(!_client->connect(remote_addr, _port, _connectTimeout)) { diff --git a/lib/lib_ssl/tls_mini/src/WiFiClientSecureLightBearSSL.cpp b/lib/lib_ssl/tls_mini/src/WiFiClientSecureLightBearSSL.cpp index 06cc2bf2b..0308e0510 100755 --- a/lib/lib_ssl/tls_mini/src/WiFiClientSecureLightBearSSL.cpp +++ b/lib/lib_ssl/tls_mini/src/WiFiClientSecureLightBearSSL.cpp @@ -335,7 +335,7 @@ int WiFiClientSecure_light::connect(const char* name, uint16_t port, int32_t tim DEBUG_BSSL("connect(%s,%d)\n", name, port); IPAddress remote_addr; clearLastError(); - if (!WiFi.hostByName(name, remote_addr)) { + if (Network.hostByName(name, remote_addr) != 1) { DEBUG_BSSL("connect: Name loopup failure\n"); setLastError(ERR_CANT_RESOLVE_IP); return 0; From 02b8acc73e629547b2f2252613b5a444c611fcfc Mon Sep 17 00:00:00 2001 From: TD-er Date: Wed, 7 Oct 2026 09:34:54 +0200 Subject: [PATCH 5/5] [WiFi] Fix wrong sign check in set TX power (ESP32) --- src/ESPEasy/net/wifi/ESPEasyWifi_abstracted_ESP32.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ESPEasy/net/wifi/ESPEasyWifi_abstracted_ESP32.cpp b/src/ESPEasy/net/wifi/ESPEasyWifi_abstracted_ESP32.cpp index 893196975..dc7753711 100644 --- a/src/ESPEasy/net/wifi/ESPEasyWifi_abstracted_ESP32.cpp +++ b/src/ESPEasy/net/wifi/ESPEasyWifi_abstracted_ESP32.cpp @@ -403,8 +403,6 @@ WiFiConnectionProtocol doGetConnectionProtocol() void doSetWiFiTXpower(float& dBm) { if (WiFi.STA.started() || WiFi.AP.started()) { - int8_t power = std::min(static_cast(dBm * 4), static_cast(WIFI_POWER_21dBm)); - constexpr wifi_power_t options[] = { WIFI_POWER_21dBm, WIFI_POWER_20_5dBm, @@ -423,8 +421,10 @@ void doSetWiFiTXpower(float& dBm) WIFI_POWER_MINUS_1dBm }; + int8_t power = std::min(static_cast(dBm * 4), static_cast(options[0])); + for (size_t i = 0; i < NR_ELEMENTS(options); ++i) { - if (power <= options[i]) { + if (power >= options[i]) { power = options[i]; esp_wifi_set_max_tx_power(power);