From a4d59d4be185a4dd85400079af1d25888b1e244b Mon Sep 17 00:00:00 2001 From: IoTThinks Date: Sun, 16 Nov 2025 12:39:02 +0700 Subject: [PATCH 01/25] To support powersaving mode with lightsleep at 9mA --- examples/simple_repeater/main.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/examples/simple_repeater/main.cpp b/examples/simple_repeater/main.cpp index 7387e77e7..b080a5f87 100644 --- a/examples/simple_repeater/main.cpp +++ b/examples/simple_repeater/main.cpp @@ -19,6 +19,11 @@ void halt() { static char command[160]; +#ifdef POWERSAVING_MODE + unsigned long lastActive = millis(); // mark last active time + unsigned long nextSleepinSecs = 30; // when to go to next sleep in seconds. First time is 30s to allow first advert +#endif + void setup() { Serial.begin(115200); delay(1000); @@ -117,4 +122,12 @@ void loop() { ui_task.loop(); #endif rtc_clock.tick(); + +#ifdef POWERSAVING_MODE + if (millis() - lastActive > nextSleepinSecs * 1000) { + board.sleep(); // To sleep and wake up when receiving a LoRa packet + lastActive = millis(); + nextSleepinSecs = 5; // Back to default. To sleep every 5s + } +#endif } From 2d9077bd9fce872b32241766b251cecca5d8fbee Mon Sep 17 00:00:00 2001 From: IoTThinks Date: Sun, 16 Nov 2025 12:40:31 +0700 Subject: [PATCH 02/25] To support lightsleep --- src/MeshCore.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/MeshCore.h b/src/MeshCore.h index 94bf351d8..e6e6505f8 100644 --- a/src/MeshCore.h +++ b/src/MeshCore.h @@ -47,6 +47,7 @@ class MainBoard { virtual void onAfterTransmit() { } virtual void reboot() = 0; virtual void powerOff() { /* no op */ } + virtual void sleep() { /* no op */ } virtual uint32_t getGpio() { return 0; } virtual void setGpio(uint32_t values) {} virtual uint8_t getStartupReason() const = 0; @@ -86,4 +87,4 @@ class RTCClock { } }; -} \ No newline at end of file +} From 6988834a8605b5d3a0fb00f650bfdbc446e9e3e2 Mon Sep 17 00:00:00 2001 From: IoTThinks Date: Sun, 16 Nov 2025 12:42:28 +0700 Subject: [PATCH 03/25] To support powersaving mode with lightsleep at 9mA --- variants/heltec_v3/HeltecV3Board.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/variants/heltec_v3/HeltecV3Board.h b/variants/heltec_v3/HeltecV3Board.h index afdaf6398..1234c75d6 100644 --- a/variants/heltec_v3/HeltecV3Board.h +++ b/variants/heltec_v3/HeltecV3Board.h @@ -15,6 +15,7 @@ #define PIN_ADC_CTRL_INACTIVE HIGH #include +#include class HeltecV3Board : public ESP32Board { private: @@ -76,6 +77,23 @@ class HeltecV3Board : public ESP32Board { enterDeepSleep(0); } + void enterLightSleep (uint32_t secs) { + esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); + esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1), ESP_EXT1_WAKEUP_ANY_HIGH); // To wake up when receiving a LoRa packet + + if (secs > 0) { + esp_sleep_enable_timer_wakeup(secs * 1000000); // To wake up every hour to do periodically jobs + } + + esp_light_sleep_start(); // CPU enters light sleep + } + + void sleep() override { + if (WiFi.getMode() == WIFI_MODE_NULL) { // WiFi is off ~ No active OTA, can go to sleep + enterLightSleep(1800); // To wake up every 30 minutes or when receiving a LoRa packet + } + } + uint16_t getBattMilliVolts() override { analogReadResolution(10); digitalWrite(PIN_ADC_CTRL, adc_active_state); From 9e9b280b657bc80d2a3c32f5148e8dcd42daad62 Mon Sep 17 00:00:00 2001 From: IoTThinks Date: Sun, 16 Nov 2025 12:43:17 +0700 Subject: [PATCH 04/25] To support powersaving mode with lightsleep at 9mA --- variants/heltec_v3/platformio.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/variants/heltec_v3/platformio.ini b/variants/heltec_v3/platformio.ini index 36c6386f6..fea0acf74 100644 --- a/variants/heltec_v3/platformio.ini +++ b/variants/heltec_v3/platformio.ini @@ -48,6 +48,7 @@ build_flags = -D MAX_NEIGHBOURS=50 ; -D MESH_PACKET_LOGGING=1 ; -D MESH_DEBUG=1 + -D POWERSAVING_MODE=1 build_src_filter = ${Heltec_lora32_v3.build_src_filter} + +<../examples/simple_repeater> From c16102b81339697db9c5746ffafe9e7161a4bb5e Mon Sep 17 00:00:00 2001 From: IoTThinks Date: Sun, 16 Nov 2025 12:44:51 +0700 Subject: [PATCH 05/25] To support powersaving mode with lightsleep at 9mA --- variants/heltec_v4/HeltecV4Board.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/variants/heltec_v4/HeltecV4Board.cpp b/variants/heltec_v4/HeltecV4Board.cpp index f143db36f..66dcc4ade 100644 --- a/variants/heltec_v4/HeltecV4Board.cpp +++ b/variants/heltec_v4/HeltecV4Board.cpp @@ -1,4 +1,5 @@ #include "HeltecV4Board.h" +#include void HeltecV4Board::begin() { ESP32Board::begin(); @@ -70,6 +71,23 @@ void HeltecV4Board::begin() { enterDeepSleep(0); } + void HeltecV4Board::enterLightSleep (uint32_t secs) { + esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); + esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1), ESP_EXT1_WAKEUP_ANY_HIGH); // To wake up when receiving a LoRa packet + + if (secs > 0) { + esp_sleep_enable_timer_wakeup(secs * 1000000); // To wake up every hour to do periodically jobs + } + + esp_light_sleep_start(); // CPU enters light sleep + } + + void HeltecV4Board::sleep() { + if (WiFi.getMode() == WIFI_MODE_NULL) { // WiFi is off ~ No active OTA, can go to sleep + enterLightSleep(1800); // To wake up every 30 minutes or when receiving a LoRa packet + } + } + uint16_t HeltecV4Board::getBattMilliVolts() { analogReadResolution(10); digitalWrite(PIN_ADC_CTRL, HIGH); From d0c342fc14341f9bdac1c9f09ada3e2151b2a486 Mon Sep 17 00:00:00 2001 From: IoTThinks Date: Sun, 16 Nov 2025 12:45:18 +0700 Subject: [PATCH 06/25] To support powersaving mode with lightsleep at 9mA --- variants/heltec_v4/HeltecV4Board.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/variants/heltec_v4/HeltecV4Board.h b/variants/heltec_v4/HeltecV4Board.h index 745e8d8f3..83eea5ef3 100644 --- a/variants/heltec_v4/HeltecV4Board.h +++ b/variants/heltec_v4/HeltecV4Board.h @@ -17,6 +17,8 @@ class HeltecV4Board : public ESP32Board { void onAfterTransmit(void) override; void enterDeepSleep(uint32_t secs, int pin_wake_btn = -1); void powerOff() override; + void enterLightSleep (uint32_t secs); + void sleep() override; uint16_t getBattMilliVolts() override; const char* getManufacturerName() const override ; From 1f9806c6b0b931e6acc8e20cb1dce8588a9eba3b Mon Sep 17 00:00:00 2001 From: IoTThinks Date: Sun, 16 Nov 2025 12:45:44 +0700 Subject: [PATCH 07/25] To support powersaving mode with lightsleep at 9mA --- variants/heltec_v4/platformio.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/variants/heltec_v4/platformio.ini b/variants/heltec_v4/platformio.ini index c26a5bc69..f1d2ef9ae 100644 --- a/variants/heltec_v4/platformio.ini +++ b/variants/heltec_v4/platformio.ini @@ -59,6 +59,7 @@ build_flags = -D MAX_NEIGHBOURS=50 ; -D MESH_PACKET_LOGGING=1 ; -D MESH_DEBUG=1 + -D POWERSAVING_MODE=1 build_src_filter = ${Heltec_lora32_v4.build_src_filter} + +<../examples/simple_repeater> From b54028e5daa171457c7f3e862c6637f4ac4c87c3 Mon Sep 17 00:00:00 2001 From: IoTThinks Date: Wed, 19 Nov 2025 17:09:18 +0700 Subject: [PATCH 08/25] To awake for 2 minutes in first boot / restart to support Repeater setup via USB --- examples/simple_repeater/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/simple_repeater/main.cpp b/examples/simple_repeater/main.cpp index b080a5f87..d802f562d 100644 --- a/examples/simple_repeater/main.cpp +++ b/examples/simple_repeater/main.cpp @@ -21,7 +21,7 @@ static char command[160]; #ifdef POWERSAVING_MODE unsigned long lastActive = millis(); // mark last active time - unsigned long nextSleepinSecs = 30; // when to go to next sleep in seconds. First time is 30s to allow first advert + unsigned long nextSleepinSecs = 120; // next sleep in seconds. First time is 2m to send advert and do repeater setup. #endif void setup() { From 0e77f9e373add0e539754da33ed87b9225d385a3 Mon Sep 17 00:00:00 2001 From: IoTThinks Date: Sat, 22 Nov 2025 10:00:51 +0700 Subject: [PATCH 09/25] Modify sleep duration and wake-up behavior Updated sleep duration and wake-up conditions for power saving. --- examples/simple_repeater/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/simple_repeater/main.cpp b/examples/simple_repeater/main.cpp index d802f562d..a0e277f97 100644 --- a/examples/simple_repeater/main.cpp +++ b/examples/simple_repeater/main.cpp @@ -125,9 +125,9 @@ void loop() { #ifdef POWERSAVING_MODE if (millis() - lastActive > nextSleepinSecs * 1000) { - board.sleep(); // To sleep and wake up when receiving a LoRa packet + board.sleep(1800); // To sleep. Wake up after 30 minutes or when receiving a LoRa packet lastActive = millis(); - nextSleepinSecs = 5; // Back to default. To sleep every 5s + nextSleepinSecs = 5; // Default: To work for 5s and sleep again } #endif } From 56df774990cc8d381172081cb2be6253d8f64c9d Mon Sep 17 00:00:00 2001 From: IoTThinks Date: Sat, 22 Nov 2025 10:02:25 +0700 Subject: [PATCH 10/25] Modify sleep method to accept seconds parameter --- src/MeshCore.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MeshCore.h b/src/MeshCore.h index e6e6505f8..2282f7231 100644 --- a/src/MeshCore.h +++ b/src/MeshCore.h @@ -47,7 +47,7 @@ class MainBoard { virtual void onAfterTransmit() { } virtual void reboot() = 0; virtual void powerOff() { /* no op */ } - virtual void sleep() { /* no op */ } + virtual void sleep(uint32_t secs) { /* no op */ } virtual uint32_t getGpio() { return 0; } virtual void setGpio(uint32_t values) {} virtual uint8_t getStartupReason() const = 0; From 3599a26e0146330b7db7571dba94c75a38651373 Mon Sep 17 00:00:00 2001 From: IoTThinks Date: Sat, 22 Nov 2025 10:03:12 +0700 Subject: [PATCH 11/25] Modify sleep function to take seconds as parameter Updated sleep function to accept a duration parameter for light sleep. --- variants/heltec_v3/HeltecV3Board.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/variants/heltec_v3/HeltecV3Board.h b/variants/heltec_v3/HeltecV3Board.h index 1234c75d6..0950cbaae 100644 --- a/variants/heltec_v3/HeltecV3Board.h +++ b/variants/heltec_v3/HeltecV3Board.h @@ -88,9 +88,9 @@ class HeltecV3Board : public ESP32Board { esp_light_sleep_start(); // CPU enters light sleep } - void sleep() override { - if (WiFi.getMode() == WIFI_MODE_NULL) { // WiFi is off ~ No active OTA, can go to sleep - enterLightSleep(1800); // To wake up every 30 minutes or when receiving a LoRa packet + void sleep(uint32_t secs) override { + if (WiFi.getMode() == WIFI_MODE_NULL) { // WiFi is off ~ No active OTA, safe to go to sleep + enterLightSleep(secs); // To wake up after "secs" seconds or when receiving a LoRa packet } } From c33cd2b1f06a753c54ae8734d5ded8502fcbd6d9 Mon Sep 17 00:00:00 2001 From: IoTThinks Date: Sat, 22 Nov 2025 10:04:25 +0700 Subject: [PATCH 12/25] Modify sleep function to accept duration parameter --- variants/heltec_v4/HeltecV4Board.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/variants/heltec_v4/HeltecV4Board.cpp b/variants/heltec_v4/HeltecV4Board.cpp index 66dcc4ade..4c8e557da 100644 --- a/variants/heltec_v4/HeltecV4Board.cpp +++ b/variants/heltec_v4/HeltecV4Board.cpp @@ -82,9 +82,9 @@ void HeltecV4Board::begin() { esp_light_sleep_start(); // CPU enters light sleep } - void HeltecV4Board::sleep() { - if (WiFi.getMode() == WIFI_MODE_NULL) { // WiFi is off ~ No active OTA, can go to sleep - enterLightSleep(1800); // To wake up every 30 minutes or when receiving a LoRa packet + void HeltecV4Board::sleep(uint32_t secs) { + if (WiFi.getMode() == WIFI_MODE_NULL) { // WiFi is off ~ No active OTA, safe to go to sleep + enterLightSleep(secs); // To wake up after "secs" seconds or when receiving a LoRa packet } } From d86f5961e054faef2a8f5e3febd4d180344e2b1c Mon Sep 17 00:00:00 2001 From: IoTThinks Date: Sat, 22 Nov 2025 10:04:49 +0700 Subject: [PATCH 13/25] Modify sleep function to accept duration parameter --- variants/heltec_v4/HeltecV4Board.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/variants/heltec_v4/HeltecV4Board.h b/variants/heltec_v4/HeltecV4Board.h index 83eea5ef3..28331118d 100644 --- a/variants/heltec_v4/HeltecV4Board.h +++ b/variants/heltec_v4/HeltecV4Board.h @@ -18,7 +18,7 @@ class HeltecV4Board : public ESP32Board { void enterDeepSleep(uint32_t secs, int pin_wake_btn = -1); void powerOff() override; void enterLightSleep (uint32_t secs); - void sleep() override; + void sleep(uint32_t secs) override; uint16_t getBattMilliVolts() override; const char* getManufacturerName() const override ; From d8954faa77af2f4b463bf6153da7e9577dfab5dc Mon Sep 17 00:00:00 2001 From: IoTThinks Date: Mon, 24 Nov 2025 22:06:22 +0700 Subject: [PATCH 14/25] Refactor HeltecV3Board: Remove light sleep methods Removed light sleep functionality and WiFi dependency. --- variants/heltec_v3/HeltecV3Board.h | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/variants/heltec_v3/HeltecV3Board.h b/variants/heltec_v3/HeltecV3Board.h index 0950cbaae..afdaf6398 100644 --- a/variants/heltec_v3/HeltecV3Board.h +++ b/variants/heltec_v3/HeltecV3Board.h @@ -15,7 +15,6 @@ #define PIN_ADC_CTRL_INACTIVE HIGH #include -#include class HeltecV3Board : public ESP32Board { private: @@ -77,23 +76,6 @@ class HeltecV3Board : public ESP32Board { enterDeepSleep(0); } - void enterLightSleep (uint32_t secs) { - esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); - esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1), ESP_EXT1_WAKEUP_ANY_HIGH); // To wake up when receiving a LoRa packet - - if (secs > 0) { - esp_sleep_enable_timer_wakeup(secs * 1000000); // To wake up every hour to do periodically jobs - } - - esp_light_sleep_start(); // CPU enters light sleep - } - - void sleep(uint32_t secs) override { - if (WiFi.getMode() == WIFI_MODE_NULL) { // WiFi is off ~ No active OTA, safe to go to sleep - enterLightSleep(secs); // To wake up after "secs" seconds or when receiving a LoRa packet - } - } - uint16_t getBattMilliVolts() override { analogReadResolution(10); digitalWrite(PIN_ADC_CTRL, adc_active_state); From adae43bc55beac70fa07369a1dba1eca3a5cf4e7 Mon Sep 17 00:00:00 2001 From: IoTThinks Date: Mon, 24 Nov 2025 22:07:10 +0700 Subject: [PATCH 15/25] Remove light sleep functions Removed light sleep functions from HeltecV4Board. --- variants/heltec_v4/HeltecV4Board.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/variants/heltec_v4/HeltecV4Board.h b/variants/heltec_v4/HeltecV4Board.h index 28331118d..745e8d8f3 100644 --- a/variants/heltec_v4/HeltecV4Board.h +++ b/variants/heltec_v4/HeltecV4Board.h @@ -17,8 +17,6 @@ class HeltecV4Board : public ESP32Board { void onAfterTransmit(void) override; void enterDeepSleep(uint32_t secs, int pin_wake_btn = -1); void powerOff() override; - void enterLightSleep (uint32_t secs); - void sleep(uint32_t secs) override; uint16_t getBattMilliVolts() override; const char* getManufacturerName() const override ; From 745566ee017e9ffb32c6be43e763b26d65cb163f Mon Sep 17 00:00:00 2001 From: IoTThinks Date: Mon, 24 Nov 2025 22:07:37 +0700 Subject: [PATCH 16/25] Refactor HeltecV4Board by removing light sleep methods Removed unused WiFi include and light sleep functions. --- variants/heltec_v4/HeltecV4Board.cpp | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/variants/heltec_v4/HeltecV4Board.cpp b/variants/heltec_v4/HeltecV4Board.cpp index 4c8e557da..f143db36f 100644 --- a/variants/heltec_v4/HeltecV4Board.cpp +++ b/variants/heltec_v4/HeltecV4Board.cpp @@ -1,5 +1,4 @@ #include "HeltecV4Board.h" -#include void HeltecV4Board::begin() { ESP32Board::begin(); @@ -71,23 +70,6 @@ void HeltecV4Board::begin() { enterDeepSleep(0); } - void HeltecV4Board::enterLightSleep (uint32_t secs) { - esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); - esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1), ESP_EXT1_WAKEUP_ANY_HIGH); // To wake up when receiving a LoRa packet - - if (secs > 0) { - esp_sleep_enable_timer_wakeup(secs * 1000000); // To wake up every hour to do periodically jobs - } - - esp_light_sleep_start(); // CPU enters light sleep - } - - void HeltecV4Board::sleep(uint32_t secs) { - if (WiFi.getMode() == WIFI_MODE_NULL) { // WiFi is off ~ No active OTA, safe to go to sleep - enterLightSleep(secs); // To wake up after "secs" seconds or when receiving a LoRa packet - } - } - uint16_t HeltecV4Board::getBattMilliVolts() { analogReadResolution(10); digitalWrite(PIN_ADC_CTRL, HIGH); From e63699696fb4e6e1a09730f7f9430805dde74bfd Mon Sep 17 00:00:00 2001 From: IoTThinks Date: Mon, 24 Nov 2025 22:10:08 +0700 Subject: [PATCH 17/25] Implement light sleep and sleep methods Added light sleep functionality to ESP32Board class. --- src/helpers/ESP32Board.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/helpers/ESP32Board.h b/src/helpers/ESP32Board.h index e566f9293..58a83c2f1 100644 --- a/src/helpers/ESP32Board.h +++ b/src/helpers/ESP32Board.h @@ -8,6 +8,7 @@ #include #include #include +#include class ESP32Board : public mesh::MainBoard { protected: @@ -42,6 +43,23 @@ class ESP32Board : public mesh::MainBoard { #endif } + void enterLightSleep (uint32_t secs) { + esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); + esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1), ESP_EXT1_WAKEUP_ANY_HIGH); // To wake up when receiving a LoRa packet + + if (secs > 0) { + esp_sleep_enable_timer_wakeup(secs * 1000000); // To wake up every hour to do periodically jobs + } + + esp_light_sleep_start(); // CPU enters light sleep + } + + void sleep(uint32_t secs) override { + if (WiFi.getMode() == WIFI_MODE_NULL) { // WiFi is off ~ No active OTA, safe to go to sleep + enterLightSleep(secs); // To wake up after "secs" seconds or when receiving a LoRa packet + } + } + uint8_t getStartupReason() const override { return startup_reason; } #if defined(P_LORA_TX_LED) @@ -78,6 +96,8 @@ class ESP32Board : public mesh::MainBoard { #endif } + + const char* getManufacturerName() const override { return "Generic ESP32"; } From f94412b24de2d5113eac1003798e7bb085d2d793 Mon Sep 17 00:00:00 2001 From: IoTThinks Date: Mon, 24 Nov 2025 22:11:16 +0700 Subject: [PATCH 18/25] Enable power saving mode in platformio.ini --- variants/xiao_s3_wio/platformio.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/variants/xiao_s3_wio/platformio.ini b/variants/xiao_s3_wio/platformio.ini index 95a54012d..8250f6cd8 100644 --- a/variants/xiao_s3_wio/platformio.ini +++ b/variants/xiao_s3_wio/platformio.ini @@ -40,6 +40,7 @@ build_flags = -D MAX_NEIGHBOURS=50 ; -D MESH_PACKET_LOGGING=1 ; -D MESH_DEBUG=1 + -D POWERSAVING_MODE=1 lib_deps = ${Xiao_S3_WIO.lib_deps} ${esp32_ota.lib_deps} From 97d7eeb1fc80dac4d1414154a546182e52178aa6 Mon Sep 17 00:00:00 2001 From: IoTThinks Date: Sun, 30 Nov 2025 16:35:15 +0700 Subject: [PATCH 19/25] To support ESP32S3 and validate RTC GPIO Add support for RTC GPIO validation in light sleep mode. --- src/helpers/ESP32Board.h | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/helpers/ESP32Board.h b/src/helpers/ESP32Board.h index 58a83c2f1..8042dc8e8 100644 --- a/src/helpers/ESP32Board.h +++ b/src/helpers/ESP32Board.h @@ -9,6 +9,7 @@ #include #include #include +#include "driver/rtc_io.h" class ESP32Board : public mesh::MainBoard { protected: @@ -43,15 +44,19 @@ class ESP32Board : public mesh::MainBoard { #endif } - void enterLightSleep (uint32_t secs) { - esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); - esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1), ESP_EXT1_WAKEUP_ANY_HIGH); // To wake up when receiving a LoRa packet + void enterLightSleep(uint32_t secs) { +#if defined(CONFIG_IDF_TARGET_ESP32S3) // Supported ESP32 variants + if (rtc_gpio_is_valid_gpio((gpio_num_t)P_LORA_DIO_1)) { // Only enter sleep mode if P_LORA_DIO_1 is RTC pin + esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); + esp_sleep_enable_ext1_wakeup((1L << P_LORA_DIO_1), ESP_EXT1_WAKEUP_ANY_HIGH); // To wake up when receiving a LoRa packet - if (secs > 0) { - esp_sleep_enable_timer_wakeup(secs * 1000000); // To wake up every hour to do periodically jobs - } + if (secs > 0) { + esp_sleep_enable_timer_wakeup(secs * 1000000); // To wake up every hour to do periodically jobs + } - esp_light_sleep_start(); // CPU enters light sleep + esp_light_sleep_start(); // CPU enters light sleep + } +#endif } void sleep(uint32_t secs) override { From 822c249f484c70c205dbb7f785314ccba2d6186b Mon Sep 17 00:00:00 2001 From: IoTThinks Date: Sun, 30 Nov 2025 16:37:59 +0700 Subject: [PATCH 20/25] Disable powersaving mode in platformio.ini Comment out POWERSAVING_MODE in platformio.ini --- variants/xiao_s3_wio/platformio.ini | 1 - 1 file changed, 1 deletion(-) diff --git a/variants/xiao_s3_wio/platformio.ini b/variants/xiao_s3_wio/platformio.ini index 8250f6cd8..95a54012d 100644 --- a/variants/xiao_s3_wio/platformio.ini +++ b/variants/xiao_s3_wio/platformio.ini @@ -40,7 +40,6 @@ build_flags = -D MAX_NEIGHBOURS=50 ; -D MESH_PACKET_LOGGING=1 ; -D MESH_DEBUG=1 - -D POWERSAVING_MODE=1 lib_deps = ${Xiao_S3_WIO.lib_deps} ${esp32_ota.lib_deps} From 20ab10fa4e8237deaae6bc3dcb2f231caac22262 Mon Sep 17 00:00:00 2001 From: IoTThinks Date: Fri, 5 Dec 2025 09:55:01 +0700 Subject: [PATCH 21/25] To get the current pending outbound packets at Dispatcher --- examples/simple_repeater/MyMesh.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/simple_repeater/MyMesh.h b/examples/simple_repeater/MyMesh.h index d8a20486a..0c53667ed 100644 --- a/examples/simple_repeater/MyMesh.h +++ b/examples/simple_repeater/MyMesh.h @@ -225,4 +225,7 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks { bridge.begin(); } #endif + + // To get the current pending outbound packets at Dispatcher + int getOutboundCount (uint32_t now) const; }; From acee014587dc0fea8764f9ce31911e8a21124f77 Mon Sep 17 00:00:00 2001 From: IoTThinks Date: Fri, 5 Dec 2025 09:55:41 +0700 Subject: [PATCH 22/25] To get the current pending outbound packets at Dispatcher --- examples/simple_repeater/MyMesh.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/examples/simple_repeater/MyMesh.cpp b/examples/simple_repeater/MyMesh.cpp index 4136818ce..c5b4594e1 100644 --- a/examples/simple_repeater/MyMesh.cpp +++ b/examples/simple_repeater/MyMesh.cpp @@ -1101,3 +1101,8 @@ void MyMesh::loop() { uptime_millis += now - last_millis; last_millis = now; } + +// To get the current pending outbound packets at Dispatcher +int MyMesh::getOutboundCount (uint32_t now) const { + return _mgr->getOutboundCount(0xFFFFFFFF); +} From b97fb20131d40a05a44365d28696dabe70781d22 Mon Sep 17 00:00:00 2001 From: IoTThinks Date: Fri, 5 Dec 2025 09:57:45 +0700 Subject: [PATCH 23/25] To postpone sleep to further 5s if there is pending outbound --- examples/simple_repeater/main.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/examples/simple_repeater/main.cpp b/examples/simple_repeater/main.cpp index a0e277f97..f7c354837 100644 --- a/examples/simple_repeater/main.cpp +++ b/examples/simple_repeater/main.cpp @@ -125,9 +125,13 @@ void loop() { #ifdef POWERSAVING_MODE if (millis() - lastActive > nextSleepinSecs * 1000) { - board.sleep(1800); // To sleep. Wake up after 30 minutes or when receiving a LoRa packet - lastActive = millis(); - nextSleepinSecs = 5; // Default: To work for 5s and sleep again + if(the_mesh.getOutboundCount(0xFFFFFFFF) == 0) { // Nothing more to send. Safe to sleep + board.sleep(1800); // To sleep. Wake up after 30 minutes or when receiving a LoRa packet + lastActive = millis(); + nextSleepinSecs = 5; // Default: To work for 5s and sleep again + } else { + nextSleepinSecs += 5; // To give 5 more seconds to send + } } #endif } From dd18ae7a3ed5d362055e91c46cabf42f6f1439d8 Mon Sep 17 00:00:00 2001 From: Kevin Le Date: Mon, 22 Dec 2025 11:22:56 +0700 Subject: [PATCH 24/25] Renamed getOutboundCount in MyMesh to hasPendingWork() Put lastActive to initialise in setup() Checked next sleep with millisHasNowPassed --- examples/simple_repeater/MyMesh.cpp | 2 +- examples/simple_repeater/MyMesh.h | 2 +- examples/simple_repeater/main.cpp | 10 +++++++--- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/examples/simple_repeater/MyMesh.cpp b/examples/simple_repeater/MyMesh.cpp index c5b4594e1..7376f2424 100644 --- a/examples/simple_repeater/MyMesh.cpp +++ b/examples/simple_repeater/MyMesh.cpp @@ -1103,6 +1103,6 @@ void MyMesh::loop() { } // To get the current pending outbound packets at Dispatcher -int MyMesh::getOutboundCount (uint32_t now) const { +int MyMesh::hasPendingWork(uint32_t now) const { return _mgr->getOutboundCount(0xFFFFFFFF); } diff --git a/examples/simple_repeater/MyMesh.h b/examples/simple_repeater/MyMesh.h index 0c53667ed..17765dc4a 100644 --- a/examples/simple_repeater/MyMesh.h +++ b/examples/simple_repeater/MyMesh.h @@ -227,5 +227,5 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks { #endif // To get the current pending outbound packets at Dispatcher - int getOutboundCount (uint32_t now) const; + int hasPendingWork(uint32_t now) const; }; diff --git a/examples/simple_repeater/main.cpp b/examples/simple_repeater/main.cpp index f7c354837..0765ec668 100644 --- a/examples/simple_repeater/main.cpp +++ b/examples/simple_repeater/main.cpp @@ -20,7 +20,7 @@ void halt() { static char command[160]; #ifdef POWERSAVING_MODE - unsigned long lastActive = millis(); // mark last active time + unsigned long lastActive = 0; // mark last active time unsigned long nextSleepinSecs = 120; // next sleep in seconds. First time is 2m to send advert and do repeater setup. #endif @@ -30,6 +30,10 @@ void setup() { board.begin(); +#ifdef POWERSAVING_MODE + lastActive = millis(); // mark last active time at boot +#endif + #ifdef DISPLAY_CLASS if (display.begin()) { display.startFrame(); @@ -124,8 +128,8 @@ void loop() { rtc_clock.tick(); #ifdef POWERSAVING_MODE - if (millis() - lastActive > nextSleepinSecs * 1000) { - if(the_mesh.getOutboundCount(0xFFFFFFFF) == 0) { // Nothing more to send. Safe to sleep + if (the_mesh.millisHasNowPassed(lastActive + nextSleepinSecs * 1000)) { // Try to sleep every nextSleepinSecs seconds + if(the_mesh.hasPendingWork(0xFFFFFFFF) == 0) { // Has no pending work. Safe to sleep board.sleep(1800); // To sleep. Wake up after 30 minutes or when receiving a LoRa packet lastActive = millis(); nextSleepinSecs = 5; // Default: To work for 5s and sleep again From 79be9ca56653539513028d6a42fbc433a5ee0e45 Mon Sep 17 00:00:00 2001 From: IoTThinks Date: Mon, 22 Dec 2025 20:19:48 +0700 Subject: [PATCH 25/25] Update src/helpers/ESP32Board.h Removed blank lines due to merge of conflict. Co-authored-by: Frieder Schrempf <34034373+fschrempf@users.noreply.github.com> --- src/helpers/ESP32Board.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/helpers/ESP32Board.h b/src/helpers/ESP32Board.h index 6f5b45ce7..d010f322c 100644 --- a/src/helpers/ESP32Board.h +++ b/src/helpers/ESP32Board.h @@ -104,8 +104,6 @@ class ESP32Board : public mesh::MainBoard { #endif } - - const char* getManufacturerName() const override { return "Generic ESP32"; }