Flush messages before going to sleep

How can i wait untill all cloud messages are flushed?
lets look at the following code:

void setup() {
Spark.public("boot");
pinMode(D0, INPUT_PULLUP);
}

void loop() {
if (digitalRead(D0)) {
Spark.publish("Switch is high");
} else {
Spark.publish("Switch is low");
}
Spark.sleep(SLEEP_MODE_DEEP, 60);
}

but none of those 2 messages (boot and switch is…) ever reach the cloud. i guess the core already turned off before they are fully transmitted. Putting a delay(1000); before the sleep solves the issue right now, but what if the network is slow?

is there a way to check that there are no messages left to send?

Remco


I’ve edited your post to properly format the code. Please check out this post, so you know how to do this yourself in the future. Thanks in advance! ~Jordy

First of all, in your setup you’ve got Spark.public, which I assume is just a mistake.

As far as you question goes, Can’t you just set a boolean switch? Something like:

messageSent = 0;

void loop() {
    if (digitalRead(D0)) {
        Spark.publish("Switch is high");
        messageSent = 1:
    } 
    else {
        Spark.publish("Switch is low");
        messageSent = 1:
    }
    if (messageSent = 1){
        Spark.sleep(SLEEP_MODE_DEEP, 60);
    }
}

That way it’ll wait for the button to be pressed and the message to be sent before going to sleep. I’m not sure it this is the mose elegant way, but it should work. Give it a try and let me know how it worked out.

That is still too quick it seems. i only get the ‘online’ event, not even the ‘spark/cc3000-patch-version’ event. i guess it needs more time. may be 1 iteration of Spark.process(). looping 25 times gets me 2 events (the online and cc3000 patch), looping 50 times gets me all 4 events.
not a very scientific method yet :slight_smile:

One way to be completely sure your events have been sent and received is to send a specific “ready to sleep” event last, which you subscribe to, and wait for the subscription to come back. Like this:

#include "application.h"

bool canSleep = false; // set to true when the core can sleep
void subscribeHandler(const char* event, const char* data) {
    // data set to the device ID that wants to sleep.
    String id = Spark.deviceID();
    // see if this was a notification from this core that we can sleep
    if (!strcmp(data, id.c_str()))  
        canSleep = true;
}

void setup()
{
    Spark.publish("boot");      // startup events etc..
    Spark.subscribe("sleep", subscribeHandler, MY_DEVICES);  // listen for sleep events
}

void loop()
{
    // do other stuff, including publishing events
    
    // publish the sleep event last
    String deviceID = Spark.deviceID();
    Spark.publish("sleep", deviceID.c_str(), 60, PRIVATE);
    
    while (!canSleep) {
        delay(100);   // waiting for the event - delay runs the system idle code
    }
    Spark.sleep(SLEEP_MODE_DEEP, 10);
}

When I run this, I see the core connect to the cloud, publish boot and sleep events (which I see in the event stream), and wait a few seconds for the response before sleeping.

I hope that’s what you were looking for! :smile:

Cheers,
mat.

6 Likes

Addendum: I’m digging into the CC3000 code to hunt TCP bugs, and just noticed there is also a notification from the CC3000 when all requested packets have been sent. So it’s possible to know when the data has been sent, and delay sleep until then. This should reduce the latency considerably.

You could try a delay loop waiting for the sent packets to match up:

while (tSLInformation.NumberOfReleasedPackets!=tSLInformation.NumberOfSentPackets) {
   delay(10);
}
3 Likes

My apologies @mdma for digging up this old post,

This is exactly what I was looking for to save battery life and not waiting several seconds for publishing to complete. However when I insert this little code snippet into my code I get an error

photon_powersaver.cpp:407:16: error: 'tSLInformation' was not declared in this scope

This is likely due to my lack of coding prowess. :confused: I’ve added #include application.h but it made no difference. I am using the WEB IDE.

Any help is appreciated.

The code given by @mdma was for the CC3000 which is the WiFi chip of the :particle: Core and is not present on the Photon.

Thank you @ScruffR

I woke up at 5 this morning realizing this code was for the Core. :flushed: Guess I think better in the morning than late at night.

That being said, is there something similar for the Photon? Right now I have a minimum of a 3 second delay before calling sleep and every second saved is helpful. Any less than 3 seconds results in publishing failing more often than I’d like.

I realize that a call to particle.publish returns a success code but what I don’t know is what this means. Is it success, the event made it to the cloud, or success, the event message left via wifi, or success, event message sent to the Wifi chip for processing.

1 Like

I’ve no answer for that, but @mdma might have.

Maybe one could think up some way to provide a callback parameter to Spark.publish() that gets called when publishing is finished :wink:

But for immediate testing, you could just add a Particle.process() after your Particle.publish() to see if this shortens your minimum waiting periode.

1 Like

Gave it a shot tonight and so far adding Particle.process() right before the sleep command is working like a charm.

I’ll test this tonight and all day tomorrow but right now @ScruffR, you’re a genius! :joy:

Ok I’ve done some further testing. Removing the delay completely and just calling Particle.process right before going to sleep doesn’t work. However a delay of 500 seems to work just fine, that’s a whole lot better than the delay of 2000 I was using before.

2 Likes

Is there an official position on this?

It seems like the sleep command doesn’t wait for publish to finish.

Is there a waitUntilPunlished command or something??

I think that If you need a delay then it is not reliable because it will be variable depending on how much time it takes to process the command.

Is there a best practice here?

@mdma

Not official, but speaking from experience :wink:

With the most recent firmware this issue should not exist anymore - some edge cases might still exhibit this, but would need reporting to pinpoint circumstances.

So, you can leave the delay out and see if it works for you.

Let me take a look on what firmware version I am… In the current one I am using if I leave it out, it simply does not send it…

Thanks for the info!

Do you mean rc 0.6.0 or 0.5.3?

In that regard both should behave the same, but I’ve only tested with 0.6.0-rc.2 and on Electron (which usually is a bit slower via cellular)

0.5.3 is behaving good!

1 Like

Hi, here is my code and it works very well with Photon!!

// Let photon go to 12 sec Deep-Sleep mode when 
// a condition become true
 
int i = 7;
int goSleep;

void setup() {
    Serial.begin(9600);
}

void loop() {
    if (i == 1) {
        Serial.println("Condition is TRUE <3");
        delay (20000);
        goSleep = 1;
    } 
    else {
        i = i - 1;
        Serial.println("Condition is false!!");
        delay (200);
        goSleep = 0;
    }
    if (goSleep == 1){
        Particle.sleep(SLEEP_MODE_DEEP, 12);
    }
}
1 Like

Where exactly is the Particle.publish()?

Also, that Particle.process and the following delay won’t be executed since the device will effectively reboot, and thus start at the top again. It won’t get to that code. There isn’t anything there requiring Particle.process in the first place though, so it’s not really a big deal, but wanted to point it out regardless.

1 Like

Yup, you are right, I missed that important note, actually yes there is no need for that two instructions at the end :smile:
thanks @Moors7

I’m dropping a note here for someone like me looking for documentation on the behavior of calling publish() followed by sleep(). Maybe this will save you some time:

There are currently only a few cases where sleep() will check for outgoing messages to be ACK’d before sleeping. You need to be using the Electron, and only certain sleep modes. I’ll leave it to someone else to clarify which sleep modes are supported, but Deep Sleep isn’t supported.

It’s unfortunate that the “Add Documentation” checkbox remains unchecked on this pull request.

2 Likes