Electron won't process Function calls post-sleep

Hi,
I’m running into an issue when trying to use Stop Mode Sleep on Electron. My goal is power savings, so I’ve chosen Stop Mode Sleep with SLEEP_NETWORK_STANDBY. I’d like to go to sleep for 60 seconds, and upon waking up, process any Particle API function calls. I see a lot of forum posts touch on this, but they’re always with respect to Particle API publish calls.

The issue I’m running into is it takes a solid 120 seconds or so for the Particle Cloud to establish re-connectivity with the Electron. I can’t wake from sleep and immediately receive commands on the Electron through the API function calls. I have to wait a considerable amount of time (~120 seconds). And I think a handshake is involved, which uses data.

This only happens if API function commands are sent while the Electron is asleep. If no commands are sent when the device is asleep, I can immediately receive API function commands without waiting for re-connectivity.

Am I missing something? See a simplified version of my code below:


//Defines Pins
const int LED_PIN = D0;

void setup() {
    pinMode(LED_PIN, OUTPUT); 
    Particle.function("turn_led_on", led_on);
}

void loop() {
   delay(120000);

   System.sleep(D6, FALLING, 60, SLEEP_NETWORK_STANDBY);
}

int led_on(String command)
{
    //Toggle LED
    digitalWrite(LED_PIN, HIGH);
}

In your simplified code, the delay(120000); is likely causing that.

But if there’s no delay then it’s never awake :smile:

Instead of delay(), try this line:

    for (uint32_t ms = millis(); millis() - ms < 120000; Particle.process());   // safe delay for 2 min 

Using SYSTEM_THREAD(ENABLED); might also help, depending on what all you’re doing in your Full Code.

I appreciate the help, unfortunately the suggestions didn’t work :frowning:

Here’s my updated code

//Defines Pins
const int LED_PIN = D0;
SYSTEM_THREAD(ENABLED);
SYSTEM_MODE(SEMI_AUTOMATIC);

void setup() {
    pinMode(LED_PIN, OUTPUT); 
    Particle.function("turn_led_on", led_on);
    Particle.connect();
}

void loop() {
   for (uint32_t ms = millis(); millis() - ms < 120000; Particle.process());   // safe delay for 2 min 
   //delay(120000);
   
   System.sleep(D6, FALLING, 60, SLEEP_NETWORK_STANDBY);
}

int led_on(String command)
{
    //Toggle LED
    digitalWrite(LED_PIN, HIGH);
}

A couple of observations:

  1. In setup() and after Particle.connect(); insert waitFor(Particle.connected, 25000); This will at least give the electron 25 seconds to connect to the cloud - at the moment you jump into the loop() without giving the electron any time to connect.
  2. In loop() you will have the same issue immediately after System.sleep() which I believe is what you have described above. So another waitFor(Particle.connected, 25000);
  3. The use of delay() and even the for loop will effectively make your loop cadence zero. A better approach is to use a timer or a test of (millis() - startmillis >= period of wait) that allows the loop() to turn at a high rate.

The use of Particle.function() requires the device to be cloud connected, thus whatever you are using to make the request from needs to wait until the device has signalled that it has woken and is connected i.e. there needs to be a handshake. Often this is done using a publish by the device to say “just woken waiting for commands for”. If it doesn’t receive a command then it goes back to sleep after a period. There is a data overhead with this.

1 Like

I'm missing the purpose of SEMI_Automatic Mode in your code.
If you remove that, the Electron will manage the Connection on it's own when it wakes up.

+1 for waitFor

Thank you both for the code suggestions, I will try them tonight.

Can anyone explain, though, why I only lose cloud connectivity when commands are sent during sleep? If no commands are sent during sleep, it is able to process them immediately after coming out of sleep. Why does this impact it? I've measured the current draw of the device, and when you send a command while it's in sleep, the current spikes. It seems the cellular modem is accepting the commands, but then they get lost. And the connection becomes corrupted.

I'd like to avoid the data overhead- especially since this loop needs to run on a minute basis. I've also read that one of the core features of SLEEP_NETWORK_STANDBY is you should be able to continue your previous session without a handshake.

And from what I understand SEMI_AUTOMATIC mode still handles the Connection on its own. You just have to initiate it, which I've done in my setup()

The only main difference between SEMI_AUTOMATIC mode and AUTOMATIC mode is that Particle.connect() is not called at the beginning of your code; you have to do that yourself.

The problem is that if you go into stop mode sleep (pin + time) there is no indication to the cloud side that you've gone offline. Thus the cloud continues to send requests to the device.

In addition, since you're using SLEEP_NETWORK_STANDBY, the cellular modem is still on and able to receive the requests, so the cloud just ends up timing out the request.

What I would do is use the wake on RI feature as described in the post below to wake up your device from sleep so it can handle the function call, rather than having it time out.

1 Like

Great info of what might be going wrong, thanks. I’m still confused why requests made when the device wakes up get blocked. Something is waiting for a handshake or for old requests to get flushed? Is it the cloud or the Electron?

And unfortunately I made the mistake of buying the Electron without RI (E-series LTE) :cold_sweat:

Looks like I may be out of luck, but I still think something can be done so that both the cloud and the Electron don’t get out-of-sync when commands are sent during sleep. Without requiring a handshake :stuck_out_tongue:

Oooh, that’s an interesting edge case. I’ll have to do some experiments to be sure what’s happening but I’ll post here when I get a chance to look into it further.

Thank you! Let me know what you find out.

This issue has been resolved in E-Series LTE Version 1.4 (or earlier)