-
Notifications
You must be signed in to change notification settings - Fork 433
To support PowerSaving for all ESP32-based repeaters and NRF52-based repeaters. #1353
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
To support PowerSaving for all ESP32-based repeaters and NRF52-based repeaters. #1353
Conversation
…es DIO0 to wakeup MCU instead of DIO1
fschrempf
left a comment
There was a problem hiding this 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?
src/helpers/NRF52Board.cpp
Outdated
| uint8_t sd_enabled; | ||
| sd_softdevice_is_enabled(&sd_enabled); // To set sd_enabled to 1 if the BLE stack is active. | ||
|
|
||
| if (!sd_enabled) { // BLE is off ~ No active OTA, safe to go to sleep |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of checking for the softdevice, I would rather implement a generic mechanism to prevent the sleep which can be used in other cases too. See fe17894.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would love to have consistent approach for ESP32 and NRF52.
In ESP32, we don't have "enterSleep" and "preventSleep".
I think we need to keep thing simple and effective.
This code works not only for OTA, but also for repeaters with WiFi or BLE active due to any reasons.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You seem to miss the point. The mentioned commit from my PR implements an easy and straight-forward way in the BaseBoard base class, that can be used by all board types. Your implementation is specific to ESP32 and can only be used from inside the board class.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would have same "sleep" methods for ESP32 and NRF52.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In #1238 I floated the idea to use safeToSleep. This could easily be implemented in a generic manner by adding it to MeshCore.h and overriding it in ESP32 as well as NRF52 (or even specific variants if necessary ). Pseudo patch:
diff --git a/src/MeshCore.h b/src/MeshCore.h
index b52ac21..a0ea11b 100644
--- a/src/MeshCore.h
+++ b/src/MeshCore.h
@@ -59,6 +59,11 @@ public:
virtual void enterSleep(uint32_t secs) {
if (!prevent_sleep) sleep(secs);
}
+ virtual bool safeToSleep() { return true; }
virtual void preventSleep() { prevent_sleep = true; }
virtual uint32_t getGpio() { return 0; }
virtual void setGpio(uint32_t values) {}With your changes moving the DIO1 pin configuration from the header files into platform.io the safeToSleep method should probably only require implementation in the NRF52Board.h and ESP32Board.h. Pseudo patch:
diff --git a/src/helpers/NRF52Board.h b/src/helpers/NRF52Board.h
index f187242..fac7fc3 100644
--- a/src/helpers/NRF52Board.h
+++ b/src/helpers/NRF52Board.h
@@ -16,6 +16,11 @@ public:
virtual void reboot() override { NVIC_SystemReset(); }
virtual void sleep(uint32_t secs) override;
virtual void onRXInterrupt() override;
virtual bool safeToSleep() override { return digitalRead(P_LORA_DIO_1) == LOW; }
};|
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'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. |
|
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 have pushed the change to implement power saving for NRF52 to use System-Idle On instead. |
fschrempf
left a comment
There was a problem hiding this 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.
7b0546a to
c8e7727
Compare
c8e7727 to
67a4398
Compare
|
I have put in changes to implement light sleep for ESP32 without changing setFlag at all. |
To put back missing code board->onAfterTransmit();
9879bd4 to
f988eb3
Compare
…es DIO0 to wakeup MCU instead of DIO1
To put back missing code board->onAfterTransmit();
fschrempf
left a comment
There was a problem hiding this 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.
src/helpers/NRF52Board.cpp
Outdated
| uint8_t sd_enabled; | ||
| sd_softdevice_is_enabled(&sd_enabled); // To set sd_enabled to 1 if the BLE stack is active. | ||
|
|
||
| if (!sd_enabled) { // BLE is off ~ No active OTA, safe to go to sleep |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok
I did force-push to fix some simple missing codes. And clean PRs are usually approved faster. :D
Well, if you don't like then I will not include the "To..." |
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.
Ok, good idea. I think we can do it like this. |
Ok, maybe. To me it sounds awkward and I've never seen this style elsewhere. But maybe that's just me... |
Ok, do as you like. |
|
@fschrempf Thanks a lot for your comprehensive reviews. Since, the code for lightsleep for esp32 and NRF52 have changed. Then I will make a final clean push. |
Maybe Jorijn's polling based MeshCore Stats project could be useful for monitoring power consumption. |
|
@4np Please help to review. :) |
|
@IoTThinks Thanks for your work. Here is what I would change: fschrempf@2c2e9e5.
|
|
Let me take a look. |
|
Other than what @fschrempf said I have no other points 👍 |
|
Thanks for the work on this, what is the current status of this PR? I take it that this supercedes #1238 is that correct? I must be blind, but I can't see where sleep actually gets called, maybe this PR is dependant on #1238? edit: If this is dependant on the #1238 can I request that the PRs be combined so that the overall change is easier to quantify? What is the situation with clock drift, is that still an issue? I noticed that this sets the lora interrupt pin as a wakeup source on ESP32 but seemingly not on NRF52, is there any reason for the difference? |
|
@oltaco The parts for esp32 work solid. For NRF52, still in testing and revising phase. ESP32 and NRF52 are a bit different on how they sleep. |
|
@oltaco #1238 provides an alternative approach and additional fixes. I switched #1238 to draft now as we decided to first get this one ready. There is no dependency between the PRs. The sleep approach for NRF52 is to put in in idle and wakeup on every interrupt event. This includes the systick interrupt every millisecond and the GPIO interrupt from the radio module. There is no need to explicitly enable the wakeup sources. |
|
For NRF52, I have put in some improvements locally to avoid deadlock or livelock in high LoRa traffic. Let me see how to simulate to generate around 20K packets / days. |
|
I just ran into an unresponsive repeater (RAK19007 / RAK4631 - Jan 14 build). Honestly, I am unsure if it's a genuine issue as it could just be that the battery drained, but after putting it back onto power I was also unable to access it. Only after reset. I'm going to uptake the latest changes and re-flash my spare repeater. |
@IoTThinks Please share what exactly the problems are and how your changes look like so we can understand what is going on and how to make it work.
What do you mean with this? |
|
For NRF52, I have committed a fix to poll wakeupPin correctly. 26339a7 The old code may hang after a few days after logining into Remote Management and click around for a while. |
|
I guess I ran into that. Running the latest changes now. |
Yes, this is what I was getting at when I asked why you weren't setting the pin as a wake-up source like you were for esp32 😉 |
|
@4np Please help to monitor and update us. @oltaco They are similar now. |
|
It seems no visible time drift on NRF52 due to sleep. On ESP32, the main MCU sleeps all the way and the ULP (Ultra low processor) wakes and keep the time using slow RTC which causes time drift forward. |
|
@4np I have put in the getIRQDio and safeToSleep as you suggested. Thanks a lot. |
|
@IoTThinks , thank you for your work on this!
Yeah there's quite a lot of traffic here. ps. I don't see South East Asia on the map, perhaps it's worth considering adding an observer. |
|
@4np Is your NRF52 repeater with new powersaving code still alive?
Let me see how to add in. Well, there are always interesting stuffs in MeshCore everyday to me. |
|
GPS vs. Powersaving is interesting. When in sleep, the MCU will ignore the data from Serial1 (for GPS). So the repeaters will get stale GPS data and timing. At least, Powersaving code will not break GPS sync. -- |





Hi all,
This PR is to add PowerSaving for all ESP32-based repeaters and NRF52-based repeaters including 4 boards with old SX1276.
Credits:
(12 Jan 2026) In latest approach, I use hardware and software events instead of SuspendLoop and ResumeLoop to avoid deadlock issue.
SuspendLoopandResumeLoopfrom Mr. Fschrempf and the check of HIGH-level DIO1 to prevent deadlock from Mr. 4np at NRF52 Repeater Powersaving. Thanks a lot.Known issue:
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 and RAK 4631 in PowerSaving mode

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