The secret OTA sauce... reliable OTA updates

For a very, very long time I have been fighting with OTA. With the help of @rickkas7 and many others I have finally cracked the code and I thought I would share.

My devices spend a lot of time asleep. They are on a very strict power budget (solar) and so when they wake up I want them to publish exceedingly very quickly and then get back to sleep.

OTA has been a nightmare. Usually is simply doesn’t work. I’ve tried lots of tricks. Pretty much every trick that I have ever read documented here in the forum. What follows is my secret sauce. It is efficient (both power and bandwidth) and in extensive testing I have been able to reliably get OTA updates to every device once a day (you can use other strategies for kicking off the SystemReset function) .

I hope others can benefit from this approach and I welcome any suggestions or feedback.

#include "Particle.h"
PRODUCT_ID(Product_ID);           //replace with yours
SYSTEM_MODE(MANUAL);          // manual mode allows greater control and reduces message count

int wake_rate = 30;           // number of seconds to stay asleep
int day;

void SystemReset() {
  System.sleep(SLEEP_MODE_DEEP, 5);     //this mode forces a system restart when it wakes up

void setup()
  while (!Particle.connected());
  Particle.publish("New_session",PRIVATE);                     // this is the secret sauce.
                      // If you don't force a new session the OTA doesn't seem to kick in
  Particle.publish("spark/device/session/end", "", PRIVATE);   
  while (!Particle.connected());
  while (System.updatesPending());
  day =;

void loop()
  Particle.publish ("I'm awake",PUBLIC);
  System.sleep(D0, RISING, wake_rate, SLEEP_NETWORK_STANDBY);   
               //keeps cellular connected while asleep which allows for very short wake up cycle
  while (!Particle.connected());
	       //do some stuff and publish events
  if ( != day) SystemReset();         
              //forces a reboot every day...btw, I tried using millis()...that doesn't increment when you are sleeping

Awesome! I would suggest renaming this thread to something more searchable though, like “Getting successful OTA on a tight power/wake budget”

1 Like

I am trying to understand what’s going on with the “special” Particle.publish statements in the setup().
I found a reference to the session/end in a couple posts here and here.
Is the first one (“New_session”) another “special”?

+1 on rewording the topic, but also seems like something to add to the docs. @rickkas7

1 Like

@Darmitage Thanks for sharing the fruits of no doubt a lot of test cycles.

My experience with Particle.connect(); is that it should be called only once - but this is with the photon and using SYSTEM_MODE(SEMI_AUTOMATIC); Also, isn’t while(!Particle.connected()); completely blocking the application thread? I guess without an application watchdog you are not worrying about this?

@rickkas7 suggested to me that System.updatesPending() is not reliable and that an event handler is the better route. It appears that isn’t the case here!

Strangely I have had the opposite problem with the OTA updates happening when they weren’t wanted - when running a control algorithm or when writing data to SD card so deploy System.disableUpdates();!

1 Like

The reason for the special event is that OTA updates are only sent when the device connects to the cloud. For the Photon/P1 this is every connection.

However, for the Electron most of the time it resumes the session, which saves several K of data. This is a good thing in general, but bad for OTA updates because you don’t get an OTA update on resume, only on full connect.

The magic event forces the session to disconnect, which causes a full reconnect and an OTA update if available. It might clear up any weird cloud state issues as well. You shouldn’t do it all the time because you’ll use a lot of data, but maybe once a day, or if you’re having odd cloud issues.

1 Like