How to force a handshake for OTA updates

third party.

The force handshake works!

With a 3rd party SIM your keep alive may be too long for the providers requirements.
While it is true that a publish will do the UDP hole punching, for that the first attempt after the hole had already closed will probably fail as it is “consumed” in the process.

Have you set Particle.keepAlive() after the connection gets established?
There is an open issue regarding that

1 Like

What is the difference between this and just calling Particle.disconnect + Particle.connect (which is what I’ve been doing). I’ve been looking for an alternative to Particle.disconnect + Particle.connect due to the fact that i run mine in SEMI_AUTOMATIC and Particle.connect comes with the blocking risk. Would calling Particle.publish here allow me to achieve the same thing without the blocking risk? Note, I have the SYSTEM_THREAD enabled.

Particle.disconnect will stop actively using the cloud connection, but will reuse the session upon reconnection. Reusing the saved session is normally a good thing because it saves several K bytes of data usage upon Particle.connect, including waking from sleep.

However, there’s an unknown condition where sometimes you might have trouble communicating and starting a new session seems to help.

1 Like

I have struggled to get reliable OTA for several months. I have a VERY tight power budget and hence spend a lot of time asleep. The app only wakes for a few seconds every 15 minutes, and doing long idle connects didn’t seem like a great solution. After combing dozens of threads I finally stumbled upon this one and the suggest that @rickkas7 provided to force a session disconnect / reset using

Particle.publish(“spark/device/session/end”, “”, PRIVATE);

It works! I only do it infrequently (once every four hours) but ending the Session is the ONE THING that seems to reliably force a new product firmware release to load. If this is the 'best practice’ for OTA updates that it be shared extensively with the community. Thank you @rickkas7 !!


OMG. This is exactly what I’m looking for. But is there anyway to achieve this through the cloud, rather than initiating from the device?

Yes. If you PUT the disconnect endpoint for a device it will reset the cloud connection from the cloud side.

curl -X PUT<deviceid>/disconnect?access_token=<token>

This should also work from the product endpoint using a product bearer token:

curl -X PUT<productid>/devices/<deviceid>/disconnect?access_token=<token>

You’re a :star:

Worked like a charm.

1 Like

I’ve been using the particle rules engine for forcing updates based on this guide here:

Is this helpful?

Hey all — to close the loop here — we’ve just announced a new feature to help intelligently deliver a firmware release as quickly as possible, but also without disrupting busy devices. I believe this new feature can help address challenges discussed in this post.

Check out our announcement here and let me know if you have questions: New OTA firmware capabilities and intelligent releases for optimized control

1 Like

I have been looking for something like this for weeks, and I finally found this … Thank you!

Hi everyone,

I’ve been trying to figure out how to do this for free (not a premium customer, not planning on becoming one).

Old technique (Particle OS v0.6.1)

I used to just have all my devices subscribed to a private “fleetReset” event that I would manually publish to my product’s event stream using particle API, and that would cause every device in my fleet to reset at the same time. After reset, they would connect to the cloud again and at this point they would receive a firmware update. So I would “release” firmware to my fleet, and then cause all connected devices to reset simultaneously, which would result in coordinated fleet-wide firmware update to all my devices. Any device not connected at the time of the “fleetReset” publish would simply automatically receive firmware update next time it connected due to cloud handshake.

This technique does not work anymore (Particle OS v1.0.1)

When I try this technique now that I have upgraded all my fleet from 0.6.1 to 1.0.1, I am dismayed to find that a device reset does not result in a cloud handshake (now, the session is preserved across resets, so no handshake on reset, thus no firmware update).

Calling Particle.disconnect()/connect() does not force handshake (Particle OS v1.0.1)

In a post in this thread (above), @ScruffR said:

You can just Particle.disconnect() , wait a few seconds and Particle.connect() again.

I had the idea of refactoring my “fleetReset” logic to a “fleetHandshake” logic, based on the idea that if I call Particle.disconnect(), wait a minute, and then call Particle.connect(), the Electron should be forced to handshake with the Particle cloud on reconnect.

This is not the case. The new product default firmware does not get downloaded by using this technique, because this technique does not force a handshake with the cloud.

How to immediately flash to all my devices for FREE

It appears that the only option for forcing a firmware update to the fleet that is free is:

  • Use the Particle API to loop through each device in the fleet and send an API request to flash new firmware to each device

@jeiden is my understanding correct?


I use this API call to end a device’s cloud connection:

This forces a new handshake, which will result in an update if you’ve got something queued. Not as easy as your old method, but not as bad as looping through each device with particle update

1 Like

A reset does not seem to kill the session keys, pulling the RST pin does not, and pulling the EN pin does not on a Boron, unless it is done long enough, and I have not be able to determine that limit yet.

Have you tried this:

I am currently trying this for when a module hangs. My quest is to find a way to reset the device and session keys that work every single time from 1.0.1 and up, (It is a MAJOR pain). Otherwise we can not use this in a product.

Have you had any luck figuring out how to reset the session keys?

Not consistently longterm.

The above quoted way of doing this does seem to work on earlier releases, but it seem to be more of a hack than an actual platform supported way of doing it longterm. A HW watchdog in itself does not seem to be able to do it reliably either.

It can be or may already have been blocked in future OS updates, as session key handling in connection with deploying SW updates was recently “featurized”. If an when that happen(ed) we would likely not be informed about it, and our customers would be back “in harms way” (a few days to a weeks outage, as seen recently would kill our business).

The lack of consistent control over resetting the session keys in a supported way, also in connection with a HW watchdog, and in combination with a cloud that is not yet reliable enough for our purpose, is too much of a risk for a product in large numbers at this point.

@BDub can you comment on whether there is a supported workaround that can be used to cause a fleet of Electrons to “choose” to download a firmware update simultaneously? Has fleet-coordinated firmware updating been “featurized” and therefore locked down with no workarounds as @thrmttnw posits?

The feature I am referring to is called intelligent firmware releases:


Before the Intelligent Firmware Releases we were enableing updates System.enableUpdates and triggering a handshake event like this to force an update. We are currently on firmware version 1.4.4

Particle.publish(“spark/device/session/end”, “”, PRIVATE);

That no longer works. Per the comment below, I have tried sending firmware binaries to a specific device to trigger an update, but I get a cryptic error: "{\"error\":\"Nothing to do?\"}"

Here is how I’m triggering the device firmware update, where filename is compiled .bin file:

curl -X PUT  -F file=#{filename} -F file_type=binary

I’ve tried using a device bearer token AND the product-level access token. Either way I get the same error. How can I flash a device to customers?

I have not been able to get this to work.on product devices. I receive a ‘disconnect initiated’ response, but there is no new handshake that is forced.