Skip to content

Conversation

@IoTThinks
Copy link

@IoTThinks IoTThinks commented Jan 9, 2026

Hi all,
This PR is to add PowerSaving for all ESP32-based repeaters and NRF52-based repeaters including 4 boards with old SX1276.

  • To support PowerSaving for all ESP32-based repeaters and NRF52-based repeaters.
  • To add flag RADIO_SX1276 to support PowerSaving for SX1276. SX1276 uses DIO0 to wakeup MCU instead of DIO1
  • To expose LoRa pins at platformio.ini instead of header files
  • When BLE is enabled on NRF52, Powersaving will be skipped as same as when enabling WiFi on ESP32. This is to allow OTA in powersaving mode.

Credits:
(12 Jan 2026) In latest approach, I use hardware and software events instead of SuspendLoop and ResumeLoop to avoid deadlock issue.

  • I have adopted neat sleep/wakeup using SuspendLoop and ResumeLoop from Mr. Fschrempf and the check of HIGH-level DIO1 to prevent deadlock from Mr. 4np at NRF52 Repeater Powersaving. Thanks a lot.
  • However, I implemented our own style as same as PowerSaving for ESP32 to have a similar architecture for powersaving. The code should be simple, effective and consistent for all ESP32 and NRF52 boards.

Known issue:

  • ESP32-based repeaters may have the clock drift forward while NRF52-based repeaters may have the clock slowdown. This is due to inaccurate / slow clock during sleep. We will improve on this issue, however it may be a cosmetic bug for now.

Testing:
I have tested the change with main branch and achieve 10mA for ESP32-based repeaters and 6mA for NRF52-based repeaters.
Some kind friends have tested boards with SX1276 working.

After the merge to dev, I have compiled 29 boards and confirm no compilation error. I have tested the merged code and it worked for Heltec v3, v4 and RAK4631.

  • Heltec_v3_repeater Heltec_WSL3_repeater heltec_v4_repeater LilyGo_T3S3_sx1262_repeater
  • T_Beam_S3_Supreme_SX1262_repeater Tbeam_SX1262_repeater Station_G2_repeater Station_G2_logging_repeater
  • Xiao_C3_repeater Xiao_S3_WIO_repeater Heltec_Wireless_Tracker_repeater heltec_tracker_v2_repeater
  • RAK_4631_repeater SenseCap_Solar_repeater Heltec_t114_repeater t1000e_repeater
  • Xiao_nrf52_repeater LilyGo_T-Echo_repeater LilyGo_T-Echo-Lite_repeater ProMicro_repeater
  • WioTrackerL1_repeater Heltec_mesh_solar_repeater RAK_WisMesh_Tag_repeater ThinkNode_M1_repeater
  • Mesh_pocket_repeater
  • Heltec_v2_repeater LilyGo_T3S3_sx1276_repeater Tbeam_SX1276_repeater LilyGo_TLora_V2_1_1_6_repeater

Heltec v3 and RAK 4631 in PowerSaving mode
image image

This is a RAK4631 repeater with PowerSaving in action: Sleep at 6mA, wakeup when a LoRa packet comes, process it, wake up for 5s and go to sleep again.

Power.Saving.for.RAK4631.in.action.mp4

Copy link
Contributor

@fschrempf fschrempf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@IoTThinks Thanks for your work! As I have already posted a solution for the sleep implementation for NRF52 in #1238 before, would you mind rebasing your work onto the latest version of this PR?

@IoTThinks IoTThinks marked this pull request as draft January 12, 2026 04:53
@IoTThinks
Copy link
Author

IoTThinks commented Jan 12, 2026

To fix the memory leaking for SoftwareTimer, to perform internal testing and to let the community to do beta test for NRF52-based repeaters.
I will push the fix to this PR this week.

@fschrempf
Copy link
Contributor

fschrempf commented Jan 12, 2026

Ok, let me try to put wakeupTimer in NRF52Board as you suggested.

I've already done that work in #1238. There is no reason to reimplement my suggestions. Please, just use my branch and add your commits on top.

@IoTThinks
Copy link
Author

Let me and some friends in busy-traffic areas test to use a simpler but more robust implementation without SuspendLoop, ResumeLoop and not touching setFlag for NRF52 repeaters.
I will push another implementation here in a few days.

@IoTThinks IoTThinks marked this pull request as ready for review January 13, 2026 15:05
@IoTThinks
Copy link
Author

I have pushed the change to implement power saving for NRF52 to use System-Idle On instead.

Copy link
Contributor

@fschrempf fschrempf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As you are somehow seeking to provide an alternative solution for #1238, can you at least mention in the description how your solution works and what benefits it has over the one in my PR? Thanks!

Also, can you please try to separate your changes logically into multiple commits and not chronologically stack each improvement as new commit on top of the previous one? As I mentioned before this is what git rebase --interactive and git push --force are made for.

I know that a lot of people do it like this, but this is not how git is intended to be used and it makes it impossible to have useful history in the end. And it leads you to copy code from my branch discarding the authorship (which can be seen as somewhat disrespectful among developers) instead of just doing git cherry-pick from my branch.

This is also something I wish the maintainers would take more into account when reviewing/merging PRs.

@IoTThinks IoTThinks force-pushed the MCdev-PowerSaving-for-all-ESP32-NRF52-repeaters branch from 7b0546a to c8e7727 Compare January 14, 2026 00:32
@IoTThinks IoTThinks force-pushed the MCdev-PowerSaving-for-all-ESP32-NRF52-repeaters branch from c8e7727 to 67a4398 Compare January 14, 2026 00:50
@IoTThinks
Copy link
Author

IoTThinks commented Jan 14, 2026

can you at least mention in the description how your solution works and what benefits it has over the one in my PR? Thanks!

I did mention in the PR. Thanks a lot.
image

However, in my yesterday proposed solution, I don't use these methods any more.
I have changed the solution approach to use safer hardware / software events instead.

@IoTThinks IoTThinks requested a review from fschrempf January 14, 2026 02:34
@IoTThinks
Copy link
Author

I have put in changes to implement light sleep for ESP32 without changing setFlag at all.

To put back missing code board->onAfterTransmit();
@IoTThinks IoTThinks force-pushed the MCdev-PowerSaving-for-all-ESP32-NRF52-repeaters branch from 9879bd4 to f988eb3 Compare January 14, 2026 07:31
Copy link
Contributor

@fschrempf fschrempf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see you did a force-push, but the commits are still not separated properly. If you need help doing it, feel free to ask.

One more thing: You always begin your comments end commit subjects with "To ...". This doesn't really makes sense. Just leave out the "to" and state your changes in an imperative way.

-D WIFI_DEBUG_LOGGING=1
-D WIFI_SSID='"myssid"'
-D WIFI_PWD='"mypwd"'
-D OFFLINE_QUEUE_SIZE=256
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This shouldn't be removed, right?

-D WIFI_SSID='"ssid"'
-D WIFI_PWD='"password"'
-D WIFI_DEBUG_LOGGING=1
-D OFFLINE_QUEUE_SIZE=256
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This shouldn't be removed, right?

}
// To configure GPIO wakeup
esp_sleep_enable_gpio_wakeup();
gpio_wakeup_enable((gpio_num_t) wakeupPin, GPIO_INTR_HIGH_LEVEL); // To wake up when receiving a LoRa packet
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove the gpio_num_t cast. It's not needed.

Comment on lines +85 to 89
#if defined(ESP32) && defined(RADIO_SX1276) && defined(P_LORA_DIO_0) // SX1276
gpio_set_intr_type((gpio_num_t)P_LORA_DIO_0, GPIO_INTR_POSEDGE);
#elif defined(ESP32) && defined(P_LORA_DIO_1) // SX1262
gpio_set_intr_type((gpio_num_t)P_LORA_DIO_1, GPIO_INTR_POSEDGE);
#endif
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This whole block can be replaced with a single line

Suggested change
#if defined(ESP32) && defined(RADIO_SX1276) && defined(P_LORA_DIO_0) // SX1276
gpio_set_intr_type((gpio_num_t)P_LORA_DIO_0, GPIO_INTR_POSEDGE);
#elif defined(ESP32) && defined(P_LORA_DIO_1) // SX1262
gpio_set_intr_type((gpio_num_t)P_LORA_DIO_1, GPIO_INTR_POSEDGE);
#endif
gpio_set_intr_type(wakeupPin, GPIO_INTR_POSEDGE);

gpio_set_intr_type((gpio_num_t)P_LORA_DIO_1, GPIO_INTR_POSEDGE);
#endif

// To disable CPU interrupt servicing
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// To disable CPU interrupt servicing
// To enable CPU interrupt servicing

#if defined(NRF52_PLATFORM)
#include "NRF52Board.h"

#include "nrf_sdm.h"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need this, do we?

uint32_t startTime = millis();

// To wake up when a LoRa packet comes or sleep timeout. Safe to 49-day overflow
while (digitalRead(P_LORA_DIO_1) == LOW && (millis() - startTime < secs*1000)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about the boards with DIO0 interrupt instead of DIO1? The digitalRead(P_LORA_DIO_1) would be incorrect in this case, right?

As mentioned above we could use a getIrqPin() function to retrieve the correct pin.

@IoTThinks
Copy link
Author

I see you did a force-push, but the commits are still not separated properly. If you need help doing it, feel free to ask.

I did force-push to fix some simple missing codes.
Let the code being reviewed for a while, then we can start over clean.
I don't like rebase actually.
Startover from heavily reviewed and commented code is faster and cleaner.

And clean PRs are usually approved faster. :D

One more thing: You always begin your comments end commit subjects with "To ...". This doesn't really makes sense. Just leave out the "to" and state your changes in an imperative way.

Well, if you don't like then I will not include the "To..."
It is the style rather than sense.

@fschrempf
Copy link
Contributor

I did mention in the PR. Thanks a lot.

I know, thanks. If FOSS developers work on the same topic and take over work from each other they usually credit by taking the commits with the original authorship.

I have put in changes to implement light sleep for ESP32 without changing setFlag at all.

Ok, good idea. I think we can do it like this.

@fschrempf
Copy link
Contributor

It is the style rather than sense.

Ok, maybe. To me it sounds awkward and I've never seen this style elsewhere. But maybe that's just me...

@fschrempf
Copy link
Contributor

Let the code being reviewed for a while, then we can start over clean.

Ok, do as you like.

@IoTThinks
Copy link
Author

@fschrempf Thanks a lot for your comprehensive reviews.
I appreciate your great effort.

Since, the code for lightsleep for esp32 and NRF52 have changed.
I will let my boards to run a while this week to make sure they are stable.
And wait for reviews from other friends here.

Then I will make a final clean push.
Thanks a lot.

@4np
Copy link

4np commented Jan 14, 2026

@IoTThinks , thanks for the work here :) I'll test this out on my RAK repeater.

I was thinking if it would be good to show how much the repeater has slept on the repeater stats to get some insight. Could very well be added in some other PR of course.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants