Updating firmware after deep sleep power savings


#1

I am enjoying getting my hands dirty with my Spark Core. However I need to shut down the core to conserve power for my beehive project. After SLEEP_MODE_DEEP the core comes back up ok, but my code runs so quickly before going back to sleep I have no chance of reprogramming the core over the air. Is there a way to signal the core that there is new firmware available?

The following example code shows what I’m attempting to do but I have to waste 10 seconds and if the core is truly in the field there is little chance I’ll be able to flash new firmware. I expect the tool chain to work like this: write some new code, hit flash, and the next time my core wakes up it grabs the new firmware. This doesn’t seem to be the case. I’m hoping I’m missing something obvious. Thanks!

//Example code to show the Spark going to sleep
//But updating the firmware over-the-air has to be timed just right
//Is there an easier way?
void setup()
{
    Serial.begin(9600);

    while (!WiFi.ready())
    {
    	Serial.println("Waiting on WiFi");
	    delay(1000);
    }    

    for(int x = 0 ; x < 10 ; x++)
    {
        Serial.print("Wait for it:");
        Serial.println(x);

        delay(1000); //You have to hit flash when the unit is sitting here
    }

}

void loop()
{
    Serial.println("Passing out");
    delay(1000);
    Spark.sleep(SLEEP_MODE_DEEP, 5); //Power save!
}

Hmm. This seems to be a known issue/feature request? https://community.spark.io/t/core-doesnt-like-waking-up-after-sleep/6853


Triggering Electron mode for OTA flash via external device
#2

I believe there are plans to make it the way you described it. Currently the Core has to be online when you’re trying to flash. In the future it should be possible to have the Core fetch a new update when it comes online. That, unfortunately, isn’t currently implemented yet. @jgoggins might be able to comment on this, perhaps @dave as well.


#3

This is easier to do with the auto-update firmware feature for products, but we’re also working on a deferred flash feature where you can queue up an update for the next time your device comes online. You might still need to stick around for a few seconds after the handshake to give the update a chance to start, but that could be a once a day kind of thing, or maybe we could provide a flag the device can check to see if it should stick around, etc. :slight_smile:

Thanks,
David


#4

I did not expect two replies in under 10 minutes! Thanks!

Let me know how to help or if there are any hacks to make it work. The power saving features aren’t really power saving if you can’t deploy and reprogram the device in the field. So please please please get this on the new features sprint :smile:


#5

@ChipAddict
I have run into the same problem. Currently there is no way to queue messages for your core from the cloud. You will have to implement some other method to have your core check for pending messages - possibly a google drive, or your own site - and then pass it a custom ‘stay online for firmware update’ message. This will tell your core to not go to sleep. Then on your other site you can take the notification of the core being online, check that the core is in fact online with the spark cloud and then pass along your firmware update message via the cloud.

I think the Spark team is working on improving this capability for the future - as I am sure the electron will need this behavior. They are currently working very hard on getting ready for the photon. I expect we will see in implementation probably after the photon and before the electron :smile:


Delayed OTA flashing after deep sleep
#6

Makes sense but that’s beyond my packet fu. Is there a good tutorial out there? I have looked but haven’t found an example of what you’re describing.


#7

@ChipAddict, another possibility is to have a daily timed OTA event. The Core wakes, connects to the Cloud, waits for a time sync, checks against a fixed time of the day and if reached, goes into a tight SPARK_WLAN_Loop() for x minutes. This becomes your update window. When OTA queuing is implemented, you won’t need any of that. :smile:


#8

Another thought - which I haven’t thought to the end yet - might be a webhook to the “Core got online” event - or another custom event.

In this case you wouldn’t need to have your Core hang around in a 10sec loop, but only as long as the webhook needs to catch.

If there was a simple way to trigger a Web IDE or other OTA flash via webhook that would be perfect, otherwise you could queue your desire to flash in the webhook’s remote end, and if you have queued such a desire, the Core could trigger an SMS or mail and hang for some time in a SPARK_WLAN_Loop() to give you time to respond.

I haven’t used webhooks very extensively, so this might be a ridiculous idea, but maybe some Elite might have something to say to this - I’d like to know too, if this would be doable.


#9

I’m resistant to having to hit the upload button between 11AM and 11:10AM but a very reasonable solution. Thank you! I think I’ll try that in the interim.


#10

Any news on this one?
From what I understand SLEEP_MODE_DEEP will reset the device when the time is up, so it should be a part of connecting to the cloud, in automatic mode the user code is not run before the cloud connection is done, so it should not be that hard for the photon to compare its version against the cloud version, and update before calling the user code.


#11

Is there any update on this? I need to have the photon wake-up and download any new updates. It is difficult, if not impossible, to get updates pushed out to sleeping devices with out this.


#12

I solved this problem as follows:

  • Subscribe to an event, publish to this event with “data=true” to have the device wait for a firmware update
  • Publish that the device is online (I haven’t found another easy way to tell when it comes online yet)
  • Always run the device through a certain number of loops before sleeping
  • If the device on-time exceeds a timeout, or the event (subscribed to earlier) is published with “data=false”, go to sleep

e.g. (untested code I snagged from a larger program I’m writing):

bool waitForUpdate = false; // for updating software
unsigned int updateTimeout = 10*60*1000; // 10 min timeout for waiting for software update
unsigned int startTime = millis();
int waitLoops = 5; // loops to go through before sleeping
int loopCount = 0;

int wakeUpTimeout = 10*60; // sleep 10 mins

void setup()
{
    Particle.subscribe("mahHouse/waterSystem/", eventHandler);
    Particle.publish("mahHouse/waterSystem/tankLevelSensor/online", "true", 90);
}

void loop()
{
    if (waitForUpdate || loopCount < waitLoops) {
        // waiting for you to update the firmware
        delay(4000);
        loopCount += 1;

    } else {
        Particle.publish("mahHouse/waterSystem/tankLevelSensor/online", "false", 90);
        System.sleep(SLEEP_MODE_DEEP, wakeUpTimeout);
    }
}

void eventHandler(String event, String data)
{
    // to publish update: curl https://api.particle.io/v1/devices/events -d "name=mahHouse/waterSystem/tankLevelSensor/update" -d "data=true" -d "private=false" -d "ttl=60" -d access_token=1234
    if (event == "mahHouse/waterSystem/tankLevelSensor/update") {
        (data == "true") ? waitForUpdate = true : waitForUpdate = false; // shorthand if-else
    }
}

To tell the device to wait for you to update the firmware, you can do this in linux (I’m using ubuntu):
to publish update: curl https://api.particle.io/v1/devices/events -d “name=mahHouse/waterSystem/tankLevelSensor/update” -d “data=true” -d “private=false” -d “ttl=60” -d access_token=1234

Or a post request to that URL with the things after the '-d’s as the sent data.


#13

It appears that there is an “is there any update on this?” ping to this thread every couple of months … so I guess it’s my turn now :grinning:

+1 to the comments that it would be highly desirable for a device to check to see if there are any queued OTA flash updates after returning online after a deep sleep interval.

I’ve read about the workarounds being used (coordinated scheduling, subscribe to an event, etc.), but these are certainly not particularly elegant. (I currently use safe mode to flash code, but this is not practical for remote devices). Would like to know if this is something being planned / worked on, or if there might be anything I’ve missed re: a cleaner way to do post deep sleep firmware updates.

Thanks.


#14

“They” said it will be an important part of electron development, so hopefully soon, we will see something.

However since we have safe mode healer now, one workaround could be sending the new firmware as part of the data submission.
For example if you are sending data directly to your server, rather than using particle cloud.
The photon calls /data.php?id=xyz&blabla ,if theres a update waiting the server replies with a certain code, if theres no update waiting it simply replies OK.
If the reply is not OK, the photon waits for say 30seconds before going to sleep.
At the same time the server calls the particle api “PUT /v1/devices/:deviceId” with the new code, which will hopefully manage to get the photon to update before the 30seconds is up.

That can also be done with a webhook, but IMO for simple requests that dont need https, its simpler and more reliable to use HttpClient.


#15

I would also like to chime in here and say that deferred OTA updates would be a very welcome feature. For any kind of battery-powered application putting the device to sleep is a must, as you are all very well aware.


#16

Hi there, just a different approach:

For small scale projects I recommend to go with Blynk app. I make an app, that has got a button, that is being checked for it’s state every time the device goes online. If the button is pressed (High) than the device doesn’t go to sleep and you can flash it with new firmware. In normal conditions the button is Low and so, the device goes to sleep periodically.

BTW - I’m using RedBear Duo but in the end - that’s just a Particle with bluetooth.

More on this you can find here:


#17

Hi all!

I wanted to thank you all for the great ideas you put in this thread.

I solved my issue using a very simple httpclient check for my DHT22 wireless sensors, you can see the code here:


#18

Here’s how I solved this problem