What are the Power Saving modes for RAK3172?

I’m currently comparing various lora boards for use in my project. I recently found RAK3172 and liked a lot about what I read about the unit. But there is one thing I need to find out more about before ordring. That is how I can use RAK3172 in a mode where it is listening for incoming lora messages and at the same time is using as little power as possible. Earlier I came across the RYLR998 module from REYAX. If you look at page 9 on the datasheet for the RYLR998: https://reyax.com//upload/products_download/download_file/RYLR998_EN.pdf
it show a way to put the unit in smart receiving power saving mode. If using:
AT+MODE=2,1000,1000 it will use 2.65mA in average.
If: AT+MODE=2,100,1000 it will use 0.525mA in average.
MODE=2,100,1000 means it will actively listen for lora messages in 100ms and sleep for 1000ms, then start over and do 100ms listening and 1000ms sleep.
So my question is this: Is it possible to do something similar with the RAK3172 so my receiving battery powered unit can listen for incoming messages at a predefined interval e.g. listen for 30ms and then sleep for 100ms, and continue doing this until either an incoming message or that my ESP32 actively put the RAK3172 in another modus. I have looked at a lot of documents for the RAK3172 but could not see any documentation for how to do something similar. In the datasheet for RAK3172:
RAK3172 WisDuo LoRaWAN Module Datasheet | Specs & Features
I found this:
RX Mode 5.22mA (minimum)
but what criteria for this minimum current usage in RX mode? is this when RAK3172 is powered with 3.3V or perhaps much less (2.2V?)
and this:
Sleep current: 1.69μA
So if someone could tell me if it is possible to get a similar smart receiving power mode current usage for the RAK3172 (or perhaps even better in comparison to the RYLR998 module) it would be great, and how this is achieved?

Welcome to RAK forum @rakbubba ,

I am not familiar with REYAX but it seems it is plain LoRa-to-LoRa and not LoRaWAN.

In that case, having a 100ms RX mode (listening) and 1000ms sleep is possible but you have to write the firmware for that. For example, write a code for setting up RX mode - RUI3 LoRaWAN API | Key Management, Data Transmission, & Configuration

Here’s a pseudocode. I didn’t test it. But in principle, this is how you can possible do it.

/*
 * RUI3 LoRa P2P Duty-Cycle: 100ms RX / 1000ms Sleep
 */

// Global variable to store the last received uplink
uint8_t last_received_data[256];
uint16_t last_received_len = 0;

// Forward declarations for timer callbacks
void start_rx();
void start_sleep();

void recv_cb(rui_lora_p2p_recv_t data) {
    last_received_len = data.BufferSize;
    memcpy(last_received_data, data.Buffer, data.BufferSize);
    
    Serial.printf("P2P Revcv - RSSI: %d, SNR: %d, Length: %d\r\n", data.Rssi, data.Snr, data.BufferSize);
}

void start_rx() {
    // Open RX window for 100ms
    api.lora.precv(100); 
    // Schedule the next sleep cycle to start in 100ms
    api.system.timer.start(RAK_TIMER_0, 100, NULL);
}

void start_sleep() {
    // Put the device to sleep for 1000ms
    // This will trigger the start_rx callback after the duration
    api.system.sleep.all(1000);
    api.system.timer.start(RAK_TIMER_1, 1000, NULL);
}

void setup() {
    Serial.begin(115200);
    delay(2000);
    Serial.println("RUI3 P2P Duty Cycle Initializing...");

    // 1. Set mode to P2P
    if(api.lora.nwm.get() != 0)
    {
        Serial.printf("Set Node device work mode %s\r\n",
            api.lora.nwm.set() ? "Success" : "Fail");
        api.system.reboot();
    }
    
    // 2. Configure P2P Parameters (Frequency, SF, BW, etc.)
    // Ensure these match your transmitter!
    api.lora.pfreq.set(868000000);
    api.lora.psf.set(7);
    api.lora.pbw.set(125);
    
    // 3. Register the receive callback
    api.lora.registerPRecvCallback(recv_cb);

    // 4. Initialize Timers
    // Timer 0 triggers the start of sleep after RX ends
    api.system.timer.create(RAK_TIMER_0, (RAK_TIMER_HANDLER)start_sleep, RAK_TIMER_ONESHOT);
    // Timer 1 triggers the start of RX after sleep ends
    api.system.timer.create(RAK_TIMER_1, (RAK_TIMER_HANDLER)start_rx, RAK_TIMER_ONESHOT);
}

void loop() {
    // loop() is kept empty to allow the RUI3 scheduler to handle sleep and timers
}

Thank you so much for your quick and detailed reply. In my project I will handle the incoming P2P lora message via the UART on an external microcontroller.
But if I add my own custom AT command to RAK3172 and use that to run e.g. the start_sleep() function in your example code, then I should be able to put the RAK3172 module in the custom low power listening mode I described in my original question, whenever I want.

When an incoming P2P lora message is detected by the RAK3172 I need to make sure that the custom low power listening mode is turned off. Could I e.g. use this function :
void recv_cb(rui_lora_p2p_recv_t data)
and add some code in that function to stop the timer related to start_sleep and start_rx functions from your example, like this:
api.system.timer.stop(RAK_TIMER_1);
api.system.timer.start(RAK_TIMER_0);
if I do that, will the RAK3172 module automatically go into sleep mode without a timeout?
… and then it’s just for me to call my custom AT command to again set the RAK3172 in the wanted custom low power listening mode?
Is this a good way to do this?

I also wonder if you could say anything about the time used (in microseconds) for the RAK3172 module, to go from
sleep.all mode to api.lora.precv(100) mode?
and time used to go from
api.lora.precv(100) mode to sleep.all mode?

I am not aware of any implementation of this kind of modified sleep mode. Maybe @beegee has more idea.

But implementing a custom ATC command to have 100ms listening and 1000ms sleep should be possible.

You can enable and disable it. This will depend on how you wrote the custom AT command.

I am not sure though how you will sync your tx device to the rx device.

But on the rx device main loop you can stop and start the TIMER that handles the 100ms RX - 1000ms sleep mode via ATC+CUSTOM_SLEEP that you will create. Maybe there is flag that will be enable/disabled by this custom sleep mode. Then it will be captured/service in the main loop to start (or stop) the 100ms and 1000ms TIMERs.

What do you mean by this?

If you mean how do I make sure the rx device actually get the sent lora packet from the tx device - then I was thinking of making sure the sleep period is a bit shorter than the preamble air time - at least a couple of preamble symbols shorter in time. This way the rx device should be able to get the lora packet from the tx device without much problem. I have been testing this modus on the RYLR998 at it is working fine in this mode: MODE=2,30,80 making sure the preamble time is at least two preamble symbols longer in time than the sleep period (here 80ms). Since I like the form factor of your RAK3172 and the fact that it has castellated soldering points on the board - will make the RAK3172 better for my project… as well as more flexible antenna configuration.
Seeing how practical the MODE=2,RX-time,SLEEP-time on the RYLR998 works, maybe you could make it so that a similar functionality is added to the RAK3172 via AT built in AT command? I’m sure more users would appreciate this feature.

A little more information on this smart power saving mode and how it will affect battery life without having to syncronize the rx and tx unit - and still receiving all sent lora messages:
Looking at the datasheet for the RAK3172 it gives this information (at least the one I’m considering testing):

  • minimum current consumption in RX mode (listening but not receiving I guess): 5.22mA
  • current consumption in sleep mode: 1.69uA
    So, if using a similar smart power mode as described here, (and in my first post) one can save a lot of battery power if implementing this the right way.

Now, lets assume a battery can deliver 2000mAh
If rx unit is in constant listening mode then it consumes those 2000mAh in about 383 hours (assuming 5.22 mA current consumption in RX mode not receiving anything).

Then… if implementing a smart power saving mode like:
rx listen for 500ms and rx unit sleep for 500ms (for simplicity I say 1.69uA equals to zero ampere: then the rx unit can, if preamble air time is longer than sleep period, still catch every incoming lora message - but now rx unit can last for double time: 766 hours on the same battery. If you do not want preamble time to last as long than e.g. 510ms to 515ms (to work for 500ms sleep time), but let say only 65ms, then we could use rx time of 50ms and sleep time of 50ms, and still get every incoming lora message, and operating for the same time (766 hours).
But by adjusting rx time and sleep time to let say 30ms (rx time), 120ms (sleep time), and and ajusting preamble airtime to be a little over 120ms (let say 130ms, probably at least 2 preamble symbols longer), we can achieve dramatically better up time for the rx unit, while still being able to catch every incoming lora packet (assuming P2P communication) - and without any syncronization between rx and tx unit. Pretty cool in my opinion. So for those running on battery and not wanting to syncronize rx and tx unit - implementing this "smart power saving mode) is one simple way to save a lot of power while maintaining the ability to receive any incoming lora message.

A few questions in relation to your suggested code:

  1. How is the UART2 affected by this code. Will UART2 be active after waking up after: api.system.sleep.all? If not, how to activate the UART2 again - and how long in microseconds will the eventual reactivation of UART2 be?
  2. When using api.system.sleep.all(1000), when it goes from active RX mode (just listening), and to this sleep all mode: how long does the unit use (in microseconds) to go from RX mode to sleep all mode?
  3. When unit goes from sleep all mode to active listening in RX mode, how long (in microseconds) does the unit use to go from sleep all mode to RX mode?