Skip to content

Conversation

@fschrempf
Copy link
Contributor

In order to reduce the power consumption of repeaters in general, this introduces a new CLI parameter idle.interval. The default value is zero which results in unchanged behavior. Setting it to a non-zero value causes the processing loop to be halted for the given amount of seconds.

During the idle interval the CLI and the UI (if available) will be unresponsive. The RF module will be kept in RX mode and upon receiving a packet, the interrupt will cause the processing loop to continue immediately before going back to idle after all outgoing packets have been transferred.

On a RAK4631 repeater this can reduce the power consumption during RX mode from around 12 mA to around 7.5 mA.

This can be extended later to use CPU sleep modes (if the platform allows it) to reduce the power consumption further similar to what is proposed in #1107.

I will let this run on my test repeater for some days and then remove the draft status of this PR if everything looks good.

Feedback, tests, reviews and questions welcome!

@IoTThinks
Copy link

I intended to do the same before.
But it is quite hard to power down NRF52 and be waken up by RX events. The power consumption will be around 6mA.
NRF52 does not handle Rising High well.
Your PR looks complex. May be due to this issue.

So I ended up just do some power saving trick to keep the power down to 8.5mA with few code changes only.
The MCU is still running.

Hope we can push the power down more for NRF52

@fschrempf
Copy link
Contributor Author

fschrempf commented Dec 17, 2025

But it is quite hard to power down NRF52 and be waken up by RX events.

Yes, there is no real sleep mode for NRF52 so either put the CPU in idle to save power or shut it down completely. The latter requires full reinit at wakeup.

The power consumption will be around 6mA.

In which case? With the MCU shut down and only the RF module running in RX mode? That would be in that ballpark, yes.

NRF52 does not handle Rising High well.

Sorry, I don't get what you mean here.

Your PR looks complex. May be due to this issue.

Actually it doesn't look complex to me at all. It's pretty straight forward. Instead of letting the CPU run continuously, it stops it and resumes it after the idle interval is over or a packet is received. What exactly looks complex to you?

So I ended up just do some power saving trick to keep the power down to 8.5mA with few code changes only.

What "trick" would that be? Do you mean waitForEvent() here? It doesn't work for me. I'm still seeing around 14 mA @ 3.3V with your PowerSaving07 branch.

And if it would work, it would do the same thing: put the CPU in idle, right? My approach does it in a platform-agnostic way, which is better IMHO.

@ngavars
Copy link
Contributor

ngavars commented Dec 17, 2025

This feature has been long overdue. I tested it a bit with Heltec t114 (no screen) repeater. With stock FW I am seeing around 12 mA idle current on my cheap usb power meter. It is actually quite good - it used to be around 17 mA with stock FW not so long ago.

Then I flashed FW from this branch and immediately went for "set idle.interval 10000". Now my cheapo usb meter shows current at 0 mA, which occasionally jumps briefly to 10 mA while idling. If I send a message from my companion then the repeater wakes, repeats and then goes back to idling. Now, the 0mA is probably just an artifact of my usb meter. I will try some additional tests tomorrow, but what I see so far - the power consumption at idle is noticeably lower and repeater still seems to be repeating messages and responding to admin commands etc

What is the intended reasonable idle interval? Something like 1 to 3 seconds?

@IoTThinks
Copy link

May be I will add the CLI for esp32 based boards.

Should we share the same CLI to enable/disable power saving to both esp32 and nrf52?

Like set powersave 1?

In your PR, you set the idle period? How about wake up period?

@IoTThinks
Copy link

@ngavars You have to measure the current at the battery cable by power meter.

A usbc, it needs to turn on unneccessary components like uart chip, led...

@fschrempf
Copy link
Contributor Author

May be I will add the CLI for esp32 based boards.
Should we share the same CLI to enable/disable power saving to both esp32 and nrf52?

In my opinion we should use the same approach for ESP32 and NRF52 altogether. You should be able to take my generic implementation and simply add the board.sleep() implementation for ESP32 to be called before the loop is halted.

Like set powersave 1?

What would that be good for? A single parameter that sets the length of the sleep/idle interval is enough. If set to zero (default) there is no change compared to the current implementation in the main branch. Repeater admins can then decide if they want to save power by increasing the interval.

In your PR, you set the idle period? How about wake up period?

The idle interval is the time the CPU is idling/sleeping. The wake interval is hardcoded to five seconds or three minutes after reboot or after CLI activity. I don't think this needs to be a parameter for the user to change.

@fschrempf
Copy link
Contributor Author

What is the intended reasonable idle interval? Something like 1 to 3 seconds?

The idle.interval setting is in seconds, so 10000 will give you around 2.8 hours. I'm currently running my test repeater with 1800 (30 minutes), but I'm not yet sure what would be a good value. If you have the value set very high, the automatic adverts of the repeater might be delayed accordingly (until the next wakeup happens). Apart from that I currently don't see any other downsides.

@fschrempf
Copy link
Contributor Author

@ngavars Thanks for testing by the way!

Copy link

@mtlynch mtlynch left a comment

Choose a reason for hiding this comment

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

I'm just a user sharing my thoughts and have no authority in this project.

@fschrempf
Copy link
Contributor Author

fschrempf commented Dec 19, 2025

I'm just a user sharing my thoughts and have no authority in this project.

Thanks for your review anyway! Very much appreciated!

@fschrempf fschrempf marked this pull request as ready for review December 19, 2025 09:31
@fschrempf
Copy link
Contributor Author

I've had this running on my test repeater (RAK4630) for 3 days now and I can't see any negative or unexpected results. I currently do not have any ESP32 hardware to test, so if someone would be willing to help out that would be very much appreciated! 😃

@SaschaKt
Copy link

I've had this running on my test repeater (RAK4630) for 3 days now and I can't see any negative or unexpected results. I currently do not have any ESP32 hardware to test, so if someone would be willing to help out that would be very much appreciated! 😃

Can you attach/upload somewhere an bin file for v3 for testing?

@fschrempf
Copy link
Contributor Author

fschrempf commented Dec 22, 2025

@SaschaKt You can find an archive with all repeater firmwares built by the GitHub CI here: https://github.com/fschrempf/MeshCore/actions/runs/20347701758/artifacts/4916433935

@SaschaKt
Copy link

SaschaKt commented Dec 22, 2025

@SaschaKt You can find an archive with all repeater firmwares built by the GitHub CI here: https://github.com/fschrempf/MeshCore/actions/runs/20347701758/artifacts/4916433935

I flashed it. Sorry for feedback after a few seconds. for v3 the powersaving is not so efficient like Iotthinks solution. I'm measuring over Usb-C and the consumption goes down from 48mA to 39mA with your solution, with Iotthinks solution it goes down to 13mA measured over Usb-C. Measuring on battery input pins will be a few mA less. I don't think that the combination of both solutions will give more power saving because I think that Lightsleep at esp's with iotthink solution also reduce CPU activity

@fschrempf
Copy link
Contributor Author

@SaschaKt Thanks for testing! This is the expected behavior. This PR does not (yet) include the code for ESP32 sleep. And yes, the combination of both solutions won't give more power savings for ESP32 than #1107.

The reason for my PR is that it provides a generic approach that is also applicable for other platforms than ESP32 while still providing the possibility to be extended by platform-specific sleep.

If your test shows a slightly reduced power consumption and the repeater still works fine that's a success.

@SaschaKt
Copy link

@SaschaKt Thanks for testing! This is the expected behavior. This PR does not (yet) include the code for ESP32 sleep. And yes, the combination of both solutions won't give more power savings for ESP32 than #1107.

The reason for my PR is that it provides a generic approach that is also applicable for other platforms than ESP32 while still providing the possibility to be extended by platform-specific sleep.

If your test shows a slightly reduced power consumption and the repeater still works fine that's a success.

It works, I could go normal to cli and start OTA and flash with Iotthink variant again. Now again 13mA. 39mA is still too much. nrF have per default enabled power saving internally and are at the small consumption level, with tweaking maybe a few mA savings. But esp's needs an enabled lightsleep to be useful as a repeater. The advantage of an nrF is that still with enabled BT the power consumption is not noticeable higher then without. Where is the problem to have two power routines, one for esp's and one for NRFs? Also Iotthink made powersavings for nrF too which will reduce from 12.5 to 8.5mA, that's about 32%

@fschrempf
Copy link
Contributor Author

Where is the problem to have two power routines, one for esp's and one for NRFs

@SaschaKt I think we are talking past each other. There is no problem here. What I want to achieve is a two step solution:

  1. A platform-independent solution (with some power savings) with idling the CPU (without any sleep) that works in all cases and also for any future boards and platforms.
  2. Additionally platform-specific sleep functions (with more power savings) if available.

Apart from the differences mentioned in #1107 (review) this is purely a strategic difference from what #1107 does.

@SaschaKt
Copy link

Where is the problem to have two power routines, one for esp's and one for NRFs

@SaschaKt I think we are talking past each other. There is no problem here. What I want to achieve is a two step solution:

  1. A platform-independent solution (with some power savings) with idling the CPU (without any sleep) that works in all cases and also for any future boards and platforms.
  2. Additionally platform-specific sleep functions (with more power savings) if available.

Apart from the differences mentioned in #1107 (review) this is purely a strategic difference from what #1107 does.

You're right. I can confirm that with v3 the powerconsumption goes from 48mA to 39mA. That's an improvement..I hope that it would not interfere with hardware specific power saving ontop like iotthink has made..this has to be tested

@ngavars
Copy link
Contributor

ngavars commented Dec 23, 2025

I did some additional testing with power profiler and Heltec V3 board on stock firmware and on your firmware. Both measurements were captured after the initial boot/advert sequence, when the board starts idling. Heltec was powered through its battery connector with voltage set at 3307 mV.

With stock firmware the avg current is 45 mA.
With power option firmware the avg current is also around 45 mA until approx. 3 minute mark, when it drops down to around 35 mA.

With stock firmware (latest from web flasher):
image

With power option firmware, idle.interval=1800:
image

Hope this helps. I can also test it with Promicro board if you want.

Copy link

@4np 4np left a comment

Choose a reason for hiding this comment

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

Thanks for working on this @fschrempf 👍 It would be good to see some more power saving for my Solar RAK19003 node :)

Having said that, I wonder if if would be better if the idle interval would be computed automatically rather than using a fixed duration. For example, in The Netherlands the mesh has grown exponentially. Where 2 months ago the mesh saw some activity, now I see hundreds of daily messages (let alone adverts) and (some parts of) Belgium and Germany have been connected. I wouldn't be surprised to see more of Germany and France starting to appear. An idle interval that worked a couple of weeks ago (maybe even days ago) may not work as well today.

Additionally, if CPU idling is triggered, how would one be able to enter remote management mode? IMHO when trying to use remote management or fetching telemetry, idling should be cancelled and the idle timer should be reset.

_prefs.advert_loc_policy = ADVERT_LOC_PREFS;

_prefs.adc_multiplier = 0.0f; // 0.0f means use default board multiplier
_prefs.idle_interval = 0;
Copy link

@4np 4np Dec 30, 2025

Choose a reason for hiding this comment

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

Perhaps add a comment to better explain what this means:

Suggested change
_prefs.idle_interval = 0;
// CPU Idle Interval (in seconds).
//
// If enabled (> 0), the CPU will start idling if there has not been any radio activity for
// the specified number of seconds.
//
// Note: When the CPU is idling, remote management and / or UI will cease to function!
_prefs.idle_interval = 0;

Or shorter:

Suggested change
_prefs.idle_interval = 0;
_prefs.idle_interval = 0; // CPU will idle when no RF activity during this interval (in sec, 0 = disabled)

@ngavars
Copy link
Contributor

ngavars commented Dec 30, 2025

Additionally, if CPU idling is triggered, how would one be able to enter remote management mode? IMHO when trying to use remote management or fetching telemetry, idling should be cancelled and the idle timer should be reset.

It will wake up on any RX event. Remote management works nicely, at least in all my tests so far.

@ngavars
Copy link
Contributor

ngavars commented Dec 30, 2025

I did some more testing with Xiao NRF52840. Here's a comparison of stock firmware (dev branch) and power option firmware (idle.interval=1800). In both cases the board is idling for 1 minute and there are no radio events.

Stock FW
image

idle.interval=1800
image

@fschrempf
Copy link
Contributor Author

An idle interval that worked a couple of weeks ago (maybe even days ago) may not work as well today.

@4np How is the idle interval related to the mesh activity? During idle the repeater will still respond to incoming packets. Only outgoing packets will be left waiting until the timeout expires.

@fschrempf
Copy link
Contributor Author

I did some more testing with Xiao NRF52840.

Thanks for the additional tests. This corresponds pretty nicely to the results of my own tests on RAK4631.

@4np
Copy link

4np commented Dec 31, 2025

@4np How is the idle interval related to the mesh activity? During idle the repeater will still respond to incoming packets. Only outgoing packets will be left waiting until the timeout expires.

@fschrempf , what I meant is an idle interval that works today, may not work tomorrow. If I read the PR, and correct me if I'm wrong, in your case you set the idle interval to 30 mins. So if there's no rx during a 30 min window, the CPU will start idling.

To illustrate the issue, this summer I didn't hear anything at all on MeshCore and there were almost no repeaters or companions. In September / October, we had a small regional mesh with several messages per hour. Today, we have most of The Netherlands covered with the one of the most dense meshes in Europe and I receive several packets per second.

So an idle timeout of, in your case, 30 mins that in my case would have been valid in September or summer would never trigger today.

As such IMHO it would be better to have an algorithm compute the best idle interval and have it adjust automatically on changing conditions. New repeaters pop up every single day.

ps. I think ill configured repeaters doing flood adverts at short intervals are the primary cause of the many packets per second, and putting a strain on the mesh. Reducing the number of configuration options could be beneficial as well.

@SaschaKt
Copy link

@4np How is the idle interval related to the mesh activity? During idle the repeater will still respond to incoming packets. Only outgoing packets will be left waiting until the timeout expires.

@fschrempf , what I meant is an idle interval that works today, may not work tomorrow. If I read the PR, and correct me if I'm wrong, in your case you set the idle interval to 30 mins. So if there's no rx during a 30 min window, the CPU will start idling.

To illustrate the issue, this summer I didn't hear anything at all on MeshCore and there were almost no repeaters or companions. In September / October, we had a small regional mesh with several messages per hour. Today, we have most of The Netherlands covered with the one of the most dense meshes in Europe and I receive several packets per second.

So an idle timeout of, in your case, 30 mins that in my case would have been valid in September or summer would never trigger today.

As such IMHO it would be better to have an algorithm compute the best idle interval and have it adjust automatically on changing conditions. New repeaters pop up every single day.

ps. I think ill configured repeaters doing flood adverts at short intervals are the primary cause of the many packets per second, and putting a strain on the mesh. Reducing the number of configuration options could be beneficial as well.

Idle time is how long the CPU should be idle and then wake up for doing stuff, or it is waken before throw an rx. After a Rx/tx I have measured on my own a fast falloff of the current and on Rx a short time normal state, repeat, idle again.

@fschrempf
Copy link
Contributor Author

@4np I think you misread the PR. The idle interval just determines how long the CPU will be in idle and therefore no processing of outgoing packets, serial user input or UI takes place. This interval can be interrupted at any time by incoming packets.

The time after which the idling starts is hardcoded to 3 minutes after startup and 5 seconds during normal operation.

So the worst that will happen in a busy mesh is that it will never go to idle because there are always incoming packets within the 5 second interval. But it will not affect the performance of the repeater or anything.

@4np
Copy link

4np commented Dec 31, 2025

Thank you for the clarification @fschrempf and @SaschaKt 👍

There is no reason to not use the reset pin as the RAK4630/31 module
has it connected internally.

Signed-off-by: Frieder Schrempf <frieder@fris.de>
This makes the code easier to read and allows for easier changing of
the hardcoded values.

Signed-off-by: Frieder Schrempf <frieder@fris.de>
When a CLI command is issued through the serial interface, extend the
timeout for going to sleep to give the user more time for issuing more
commands.

Signed-off-by: Frieder Schrempf <frieder@fris.de>
This uses the core functions suspendLoop() and resumeLoop() to suspend
the main task and put the CPU in a low power idle mode.

The wakeup occurs either through the specified timeout using a timer
interrupt or through an RX interrupt from the radio module.

Signed-off-by: Frieder Schrempf <frieder@fris.de>
@fschrempf
Copy link
Contributor Author

fschrempf commented Jan 2, 2026

With #1266 being merged in dev, this has now been reworked to work on top of this. I will let the new version run on my RAK4630 test repeater. Here is a link to the repeater firmware archive from the CI for any of you who want to do another test themselves.

As a reminder, the new version requires powersaving to be turned on via CLI command powersaving on.

@fschrempf fschrempf changed the title Repeater CPU Idling NTF52 Repeater Powersaving Jan 2, 2026
@fschrempf fschrempf changed the title NTF52 Repeater Powersaving NRF52 Repeater Powersaving Jan 2, 2026
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.

6 participants