Handling WiFi out of Range

Is there a sure fire way to handle the condition of a WiFi access point going out of range causing the photon to continually flash green and thereby block the application thread?

I am using SYSTEM_THREAD(ENABLED) and SYSTEM_MODE(SEMI_AUTOMATIC). The only way I have found to stop the device trying to connect to wifi [and slowing the application to a crawl] is to turn off the wifi module. I am differentiating turning on the wifi from startup (called from setup()) and called from the loop().

I have tried using a network error callback - with mixed results.

I have a few timed processes going on in the application:

  1. Every 10 seconds checks the wifi and cloud connection status and updates a connection icon on screen
  2. Every 30 seconds check the cloud and wifi connections and if not connected will try to reconnect - if it times out on the wifi connection it will assume wifi is out of range and then turn off the wifi module.
  3. Every 3 minutes will check if wifi was disconnected due to out of range and will retry (turn on wifi).

This sort of works but leads to uncomfortably long periods of time where the application is crawling along.

Is WiFi.ready() the only way to tell if the Wifi module is on or off other than keeping a track of it with a global bool variable?

Have you tried WiFi.scan() to find out if your network is in range before trying to connect?

You wouldn’t need WiFi.off() to prevent reconnection, WiFi.disconnect() should do the trick too and should speed up any potential WiFi.scan() calls.

1 Like

The issue is not on connection at startup (called from setup()) I can determine whether the Wifi is available or not and turn the wifi module off.

The issue is not reconnection - the problem is that with 0.8.0 the system just does not give up trying (flashing green) and the process seems to have been given a high priority so that if a WAP that had been connected to is turned off [this is normal practice in some school environments outside hours] then the device effective gets hung, the application gets very little processor time.

In the past WiFi.disconnect() hasn’t worked to stop the module trying to connect. I am going to try a few changes including this one. Thanks

Neither WiFi.disconnect() nor WiFi.Off() will stop the device trying to connect to wifi when the WAP is out of range. I am going to try SYSTEM_MODE(MANUAL);

Huh??? I’ll have to check that. Or do you mean it doesn’t stop it immediately?
I know that some processes in the WiFi module are blocking, but I’ve never seen one that wouldn’t give back control to the application thread at least once in 20-30 seconds.

This is a bit of the logging output starting when the WiFi AP was turned off.

0000047989 [hal.wlan] TRACE: connect cancel
0000048620 [hal.wlan] INFO: Using external antenna
0000048644 [hal.wlan] INFO: Joining ZTESTWPA2
0000048644 [hal.wlan] TRACE: Free RAM connect: 39272
0000051629 [hal.wlan] ERROR: wiced_join_ap_specific(), result: 1006
0000051629 [hal.wlan] INFO: Joining ZTESTWPA2
0000051629 [hal.wlan] TRACE: Free RAM connect: 39272
0000058634 [hal.wlan] ERROR: wiced_join_ap_specific(), result: 1024
0000058634 [hal.wlan] INFO: Joining ZTESTWPA2
0000058635 [hal.wlan] TRACE: Free RAM connect: 39272
0000065761 [hal.wlan] ERROR: wiced_join_ap_specific(), result: 1024
0000065762 [app] TRACE: connSymb OoR F Bad F Was T
0000065805 [hal.wlan] INFO: Joining ZTESTWPA2
0000065805 [hal.wlan] TRACE: Free RAM connect: 39264
0000072933 [hal.wlan] ERROR: wiced_join_ap_specific(), result: 1024
0000072933 [hal.wlan] INFO: Joining ZTESTWPA2
0000072934 [hal.wlan] TRACE: Free RAM connect: 39192
0000080060 [hal.wlan] ERROR: wiced_join_ap_specific(), result: 1024
0000080060 [hal.wlan] INFO: Joining ZTESTWPA2
0000080061 [hal.wlan] TRACE: Free RAM connect: 39192
0000087187 [hal.wlan] ERROR: wiced_join_ap_specific(), result: 1024

It just carries on like this. I have tried .disconnect() followed by .off() and that still does not kill it. I will try MANUAL mode - I am slightly concerned that I will need to pepper the application loop with Particle.process();

I got the time to try with SYSTEM_MODE(MANUAL).

The behaviour was then very weird. Essentially, WiFi.disconnect(); and WiFi.off(); do nothing when the WAP is out of range UNTIL the WAP is back in range whence it immediately after bringing up DHCP disconnects and turns off the wifi.

I have a function in the loop() which is timed to run every 5 seconds, once the WAP is out of range, this frequency goes as high as 64 seconds - there will be log ERROR and INFO pumping out of hal.wlan.

I am going to try reverting to SYSTEM_MODE(SEMI_AUTOMATIC); and a few other timing changes.

It appears to me that there is a serious bug in the wifi stack since it appears to be ignoring application calls.

This sounds severe enough to let @rickkas7 chime in.

I have raised a support ticket - I guess he will probably reply to that. Thanks

Yes, I’ll look into that next week. That behavior does not sound correct, though I think I know how that might happen.


On its own, I don’t see having the Wi-Fi AP being off and the device blinking green affecting the loop thread.

This is the code I used:

#include "Particle.h"


SerialLogHandler logHandler;

const unsigned long LOOP_REPORT_PERIOD = 5000;

bool cloudUp = false;
bool wifiUp = false;

unsigned long lastLoopReport = 0;
int loopCount = 0;

void setup() {

void loop() {

	// Note whether Wi-Fi has gone up or down
	if (WiFi.ready()) {
		if (!wifiUp) {
			Log.info("WiFi up");
			wifiUp = true;
	else {
		if (wifiUp) {
			Log.info("WiFi down");
			wifiUp = false;


	// Note whether cloud has gone up or down
	if (Particle.connected()) {
		if (!cloudUp) {
			Log.info("Cloud up");
			cloudUp = true;
	else {
		if (cloudUp) {
			Log.info("Cloud down");
			cloudUp = false;


	// Report the number of times loop has been executed in the last 5 seconds
	if (millis() - lastLoopReport >= LOOP_REPORT_PERIOD) {
		lastLoopReport = millis();

		Log.info("loopCount=%d", loopCount);
		loopCount = 0;

The code logs when Wi-Fi and cloud go up and down. Also, it reports the number of times loop() is called every 5 seconds.

There’s the normal log (breathing cyan, AP is up and working):

0000002924 [app] INFO: Cloud up
0000005000 [app] INFO: loopCount=573109
0000010000 [app] INFO: loopCount=676523
0000015000 [app] INFO: loopCount=676552
0000020000 [app] INFO: loopCount=676356
0000025000 [app] INFO: loopCount=676602
0000030000 [app] INFO: loopCount=676491
0000035000 [app] INFO: loopCount=676782

And after unplugging the AP power. Note the loopCount stays roughly the same. The device was blinking green the whole time.

0000036585 [app] INFO: Cloud down
0000036806 [app] INFO: WiFi down
0000037524 [hal.wlan] INFO: Using internal antenna
0000037568 [hal.wlan] INFO: Joining Test
0000040000 [app] INFO: loopCount=655707
0000044577 [hal.wlan] ERROR: wiced_join_ap_specific(), result: 1024
0000044577 [hal.wlan] INFO: Joining Test
0000045000 [app] INFO: loopCount=678360
0000050000 [app] INFO: loopCount=678879
0000051674 [hal.wlan] ERROR: wiced_join_ap_specific(), result: 1024

And after I plugged the AP back in:

0000137460 [hal.wlan] INFO: Joining Test
0000140000 [app] INFO: loopCount=678333
0000144563 [hal.wlan] ERROR: wiced_join_ap_specific(), result: 1024
0000144705 [hal.wlan] INFO: Joining Test
0000145000 [app] INFO: loopCount=675422
0000145688 [hal.wlan] INFO: Bringing WiFi interface up with static IP
0000145693 [app] INFO: WiFi up
0000146975 [app] INFO: Cloud up
0000150000 [app] INFO: loopCount=615204

Tested on 0.8.0-rc.11 on a Photon.

Now I suspect there are cases where calling certain functions will adversely affect performance. In particular, calling Particle.publish() will block the calling thread completely in this state. It’s quite possible that other WiFi functions may block as well, but I haven’t tested the individual functions.

Just for a good measure I also tested the case where the AP is powered up but the Ethernet disconnected. The Photon was in blinking cyan in this case:

0001075000 [app] INFO: loopCount=676764
0001080000 [app] INFO: loopCount=676805
0001082934 [app] INFO: Cloud down
0001085000 [app] INFO: loopCount=677096
0001090000 [app] INFO: loopCount=680313
0001095000 [app] INFO: loopCount=680280
0001100000 [app] INFO: loopCount=680322
0001103182 [app] INFO: WiFi down
0001103903 [hal.wlan] INFO: Using internal antenna
0001103948 [hal.wlan] INFO: Joining Test
0001104829 [hal.wlan] INFO: Bringing WiFi interface up with static IP
0001104834 [app] INFO: WiFi up
0001105000 [app] INFO: loopCount=655643
0001110000 [app] INFO: loopCount=680338
0001115000 [app] INFO: loopCount=680379
0001120000 [app] INFO: loopCount=680232
0001122057 [app] INFO: Cloud up
0001125000 [app] INFO: loopCount=617026

The next step is probably to take the test program and add in other functions that you use to see which ones cause problems.

@rickkas7 First, many thanks for checking this out quickly. I implemented your test code on a new photon and got the results shown in the log below = the same as yours.

A couple of differences stood out in your code:

  1. The size is much smaller and RAM usage ditto.
  2. Use of the default antenna setting - I'm using ANT_EXTERNAL - I tried this and no difference
  3. The loop cadence - 125000/Sec. I thought the photon looped at 10000/Sec.
  4. Lastly, just calling Particle.connect() in setup.

0000105001 [app] INFO: loopCount (last 5 sec) =688369
0000110001 [app] INFO: loopCount (last 5 sec) =688332
0000115001 [app] INFO: loopCount (last 5 sec) =688018 - WAP switched off here
0000117993 [app] INFO: Cloud down
0000118214 [app] INFO: WiFi down
0000118969 [hal.wlan] INFO: Using internal antenna
0000119019 [hal.wlan] INFO: Joining ZTESTWPA2
0000120001 [app] INFO: loopCount (last 5 sec) =664192
0000122000 [hal.wlan] ERROR: wiced_join_ap_specific(), result: 1006
0000122000 [hal.wlan] INFO: Joining ZTESTWPA2
0000125001 [app] INFO: loopCount (last 5 sec) =687550
0000129007 [hal.wlan] ERROR: wiced_join_ap_specific(), result: 1024
0000129007 [hal.wlan] INFO: Joining ZTESTWPA2
0000130001 [app] INFO: loopCount (last 5 sec) =687562
0000135001 [app] INFO: loopCount (last 5 sec) =688151
0000136133 [hal.wlan] ERROR: wiced_join_ap_specific(), result: 1024
0000136279 [hal.wlan] INFO: Joining ZTESTWPA2
0000140001 [app] INFO: loopCount (last 5 sec) =684282
0000143405 [hal.wlan] ERROR: wiced_join_ap_specific(), result: 1024
0000143405 [hal.wlan] INFO: Joining ZTESTWPA2
0000145001 [app] INFO: loopCount (last 5 sec) =687569
0000150001 [app] INFO: loopCount (last 5 sec) =688160
0000150531 [hal.wlan] ERROR: wiced_join_ap_specific(), result: 1024
0000150531 [hal.wlan] INFO: Joining ZTESTWPA2
0000155001 [app] INFO: loopCount (last 5 sec) =687569
0000157657 [hal.wlan] ERROR: wiced_join_ap_specific(), result: 1024
0000157803 [hal.wlan] INFO: Joining ZTESTWPA2
0000160001 [app] INFO: loopCount (last 5 sec) =684281
0000164929 [hal.wlan] ERROR: wiced_join_ap_specific(), result: 1024
0000164929 [hal.wlan] INFO: Joining ZTESTWPA2
0000165001 [app] INFO: loopCount (last 5 sec) =687601
0000170001 [app] INFO: loopCount (last 5 sec) =688097
0000172055 [hal.wlan] ERROR: wiced_join_ap_specific(), result: 1024
0000172055 [hal.wlan] INFO: Joining ZTESTWPA2
0000175001 [app] INFO: loopCount (last 5 sec) =687571
0000179182 [hal.wlan] ERROR: wiced_join_ap_specific(), result: 1024
0000179328 [hal.wlan] INFO: Joining ZTESTWPA2
0000180001 [app] INFO: loopCount (last 5 sec) =684320
0000185001 [app] INFO: loopCount (last 5 sec) =688123
0000186454 [hal.wlan] ERROR: wiced_join_ap_specific(), result: 1024
0000186454 [hal.wlan] INFO: Joining ZTESTWPA2
0000190001 [app] INFO: loopCount (last 5 sec) =687551
0000193581 [hal.wlan] ERROR: wiced_join_ap_specific(), result: 1024
0000193581 [hal.wlan] INFO: Joining ZTESTWPA2
0000195001 [app] INFO: loopCount (last 5 sec) =687565
0000200001 [app] INFO: loopCount (last 5 sec) =688160
0000200708 [hal.wlan] ERROR: wiced_join_ap_specific(), result: 1024
0000200854 [hal.wlan] INFO: Joining ZTESTWPA2
0000205001 [app] INFO: loopCount (last 5 sec) =684292
0000207983 [hal.wlan] ERROR: wiced_join_ap_specific(), result: 1024
0000207983 [hal.wlan] INFO: Joining ZTESTWPA2
0000210001 [app] INFO: loopCount (last 5 sec) =687558 - WAP switched back on here
0000215001 [app] INFO: loopCount (last 5 sec) =688152
0000215111 [hal.wlan] ERROR: wiced_join_ap_specific(), result: 1024
0000215111 [hal.wlan] INFO: Joining ZTESTWPA2
0000218348 [hal.wlan] INFO: Bringing WiFi interface up with DHCP
0000218464 [app] INFO: WiFi up
0000220001 [app] INFO: loopCount (last 5 sec) =625313
0000220015 [app] INFO: Cloud up
0000225001 [app] INFO: loopCount (last 5 sec) =681895
0000230001 [app] INFO: loopCount (last 5 sec) =684204
0000235001 [app] INFO: loopCount (last 5 sec) =683608
0000240001 [app] INFO: loopCount (last 5 sec) =683980

I am going to try making changes in 2 ways: A. adding to your code and B. Amending my application with some simplifiers (e.g. Particle.connect():wink:

Any suggestions to approach to help speed to identification of the issue gratefully received.
?? Loop cadence - my application loop cadence is just under 5000/Second, but can drop to 500 when doing things
?? Application size - my application is 130588 byte or 118.1% with LogHandler around 110% without
?? RAM / heap available RAM used 29.5% free memory is 38200
?? Watchdog use - wd.checkin called every loop
?? Cloud Variables
?? Cloud Functions

I have noticed now that I have added Cloud Vars, Cloud Function, freememory enquiry and watchdog checkin, the loop cadence is down to 48000/sec and that when the WAP is turned off the application shows the Cloud Down and WiFi Down the same way as before but now there is a SOS with 1 flash. Is there some incompatibility with these features?

Hmm, like this? This code seems to work the same as before, still getting a large number of calls to loop:

#include "Particle.h"


SerialLogHandler logHandler;

const unsigned long LOOP_REPORT_PERIOD = 5000;

bool cloudUp = false;
bool wifiUp = false;

unsigned long lastLoopReport = 0;
int loopCount = 0;

int testHandler(String cmd);

void setup() {

	Particle.function("test", testHandler);
	Particle.variable("loopCount", loopCount);


void loop() {

	// Note whether Wi-Fi has gone up or down
	if (WiFi.ready()) {
		if (!wifiUp) {
			Log.info("WiFi up");
			wifiUp = true;
	else {
		if (wifiUp) {
			Log.info("WiFi down");
			wifiUp = false;


	// Note whether cloud has gone up or down
	if (Particle.connected()) {
		if (!cloudUp) {
			Log.info("Cloud up");
			cloudUp = true;
	else {
		if (cloudUp) {
			Log.info("Cloud down");
			cloudUp = false;


	// Report the number of times loop has been executed in the last 5 seconds
	if (millis() - lastLoopReport >= LOOP_REPORT_PERIOD) {
		lastLoopReport = millis();

		Log.info("loopCount=%d freeMem=%lu", loopCount, System.freeMemory());
		loopCount = 0;

int testHandler(String cmd) {
	Log.info("testHandler %s", cmd.c_str());
	return 0;
0000010000 [app] INFO: loopCount=671960 freeMem=45496
0000015000 [app] INFO: loopCount=671883 freeMem=45496
0000020000 [app] INFO: loopCount=671851 freeMem=45496
0000025000 [app] INFO: loopCount=671980 freeMem=45496
0000030000 [app] INFO: loopCount=672215 freeMem=45496
0000030709 [app] INFO: Cloud down
0000030930 [app] INFO: WiFi down
0000031654 [hal.wlan] INFO: Using internal antenna
0000031700 [hal.wlan] INFO: Joining Test
0000035000 [app] INFO: loopCount=651605 freeMem=45648
0000038708 [hal.wlan] ERROR: wiced_join_ap_specific(), result: 1024
0000038708 [hal.wlan] INFO: Joining Test
0000040000 [app] INFO: loopCount=673703 freeMem=45648
0000045000 [app] INFO: loopCount=674277 freeMem=45648
0000045817 [hal.wlan] ERROR: wiced_join_ap_specific(), result: 1024
0000045817 [hal.wlan] INFO: Joining Test
0000050000 [app] INFO: loopCount=673711 freeMem=45648
0000052919 [hal.wlan] ERROR: wiced_join_ap_specific(), result: 1024
0000053061 [hal.wlan] INFO: Joining Test
0000055000 [app] INFO: loopCount=670784 freeMem=45648
0000060000 [app] INFO: loopCount=674276 freeMem=45648
0000060163 [hal.wlan] ERROR: wiced_join_ap_specific(), result: 1024
0000060163 [hal.wlan] INFO: Joining Test
0000065000 [app] INFO: loopCount=673707 freeMem=45648
0000067265 [hal.wlan] ERROR: wiced_join_ap_specific(), result: 1024
0000067265 [hal.wlan] INFO: Joining Test
0000070000 [app] INFO: loopCount=673713 freeMem=45648
0000074367 [hal.wlan] ERROR: wiced_join_ap_specific(), result: 1024
0000074509 [hal.wlan] INFO: Joining Test
0000075000 [app] INFO: loopCount=670803 freeMem=45648
0000080000 [app] INFO: loopCount=674252 freeMem=45648
0000081612 [hal.wlan] ERROR: wiced_join_ap_specific(), result: 1024
0000081612 [hal.wlan] INFO: Joining Test
0000082344 [hal.wlan] ERROR: wiced_join_ap_specific(), result: 1006
0000082344 [hal.wlan] INFO: Joining Test
0000083205 [hal.wlan] INFO: Bringing WiFi interface up with static IP
0000083210 [app] INFO: WiFi up
0000084315 [app] INFO: Cloud up
0000085000 [app] INFO: loopCount=613688 freeMem=45400
0000090000 [app] INFO: loopCount=670057 freeMem=45400

OK - the issue with the slower loop was due to the fact I was reading the heap space, System.freememory(); each loop! With my version of your code base I get loop count of 595589 (that's including the watchdog checkin).

Back to my application and I have moved the heap space reading to inside a timed loop cadence count output similar to the one you put at the end of the test loop. I have removed all the WiFi.off() statements as clearly these were not required whilst the WAP is off to keep the loop spinning.

With all the code I have in my loop() a normal loop count every 5 seconds is 25000 or 5000/second. However, when the WAP is turned off this loop count drops to 1! The time between the loop count trace is also much longer than 5 seconds, more like 21 seconds. Just like the loop() is being paused for 6-7 seconds every time it is trying to join the WAP.

0000120137 [app] INFO: loop Count (in 5sec) = 26817
0000125137 [app] INFO: loop Count (in 5sec) = 24411
0000126016 [hal.wlan] INFO: Using external antenna
0000126042 [hal.wlan] INFO: Joining ZTESTWPA2
0000129023 [hal.wlan] ERROR: wiced_join_ap_specific(), result: 1006
0000129023 [hal.wlan] INFO: Joining ZTESTWPA2
0000136028 [hal.wlan] ERROR: wiced_join_ap_specific(), result: 1024
0000136028 [hal.wlan] INFO: Joining ZTESTWPA2
0000143156 [hal.wlan] ERROR: wiced_join_ap_specific(), result: 1024
0000143200 [hal.wlan] INFO: Joining ZTESTWPA2
0000143745 [app] INFO: loop Count (in 5sec) = 1766
0000150328 [hal.wlan] ERROR: wiced_join_ap_specific(), result: 1024
0000150328 [hal.wlan] INFO: Joining ZTESTWPA2
0000157455 [hal.wlan] ERROR: wiced_join_ap_specific(), result: 1024
0000157455 [hal.wlan] INFO: Joining ZTESTWPA2
0000164583 [hal.wlan] ERROR: wiced_join_ap_specific(), result: 1024
0000164606 [hal.wlan] INFO: Joining ZTESTWPA2
0000165093 [app] INFO: loop Count (in 5sec) = 1
0000171734 [hal.wlan] ERROR: wiced_join_ap_specific(), result: 1024
0000171734 [hal.wlan] INFO: Joining ZTESTWPA2
0000178862 [hal.wlan] ERROR: wiced_join_ap_specific(), result: 1024
0000178862 [hal.wlan] INFO: Joining ZTESTWPA2
0000185991 [hal.wlan] ERROR: wiced_join_ap_specific(), result: 1024
0000186014 [hal.wlan] INFO: Joining ZTESTWPA2
0000186501 [app] INFO: loop Count (in 5sec) = 1
0000193142 [hal.wlan] ERROR: wiced_join_ap_specific(), result: 1024
0000193142 [hal.wlan] INFO: Joining ZTESTWPA2
0000200271 [hal.wlan] ERROR: wiced_join_ap_specific(), result: 1024
0000200271 [hal.wlan] INFO: Joining ZTESTWPA2
0000207398 [hal.wlan] ERROR: wiced_join_ap_specific(), result: 1024
0000207421 [hal.wlan] INFO: Joining ZTESTWPA2
0000207907 [app] INFO: loop Count (in 5sec) = 1

During the time the loop is making 1 loop per 5 seconds the interrupt attached buttons can be pressed but are not responding. Could you advise what might be causing such slothfulness. Is there something in the way I bring up the WiFi that causes this?

I have the exact same issue.

At my work, we use Photons for carts like these to authorize users via badge scanner.


I have thereading enabled and it’s in semi-automatic mode. Occasionally the Photons get stuck in a green flashing mode where the WiFi is down and sometimes the Photons response slowly.

Only way to fix is to reboot the Photon.

I thought initially it’s an issue with the APs at work or because threading is in beta. Or perhaps since the carts move throughout the building and maybe losing connectivity and not being able to restore it.

If there is a proper way to handle the WiFi I’d be very interested. Or even to help debugging.

@rickkas7 I have instrumented my application to determine where the time is disappearing.
With the WiFi in range I am seeing a stable loop timing of approx 185 uSec (I am using micros() to measure this). This equates to 25000 loop count.

I am struggling to understand why the time is going when the WiFi is off - when the loop timing is approx 21 seconds!

As far as you are aware could any of the following cause this:

  1. WiFi.listening()?
  2. System.disableReset() - which I use to protect when opening SD files from OTA updates.
  3. locator.loop() - the googlemaps locator call
  4. watchdog checkin?

I will close this as solved. The lessons learned were:

  1. WiFi.listening() does not block when wifi off
  2. System.disableReset - does not cause any issue either
  3. Nor does watchdog checkin
  4. I did add checking for WiFi.ready() true before calling locator.loop(); maybe this should be Particle.connected();?
  5. What was the culprit was this lastSync = Particle.timeSyncedLast(lastSyncTimestamp); I had implemented this pretty much exactly as per the example. I have now put in a check for Particle.connected() before calling the whole block that does the internet time sync with the RTC every day. @rickkas7 could the documentation be clarified on this cloud function with a warning?

The other lesson for me is that 0.8.0-RC.11 works much better than 0.7.0 ever did. It would be nice to see 0.7.1 with the fixes in 0.8.0-RC.11 whilst we wait (and wait) for 0.8.0 to be released for Photon and Electron (small request). I hope these findings are useful for someone else who might have experienced similar issues with their application @Carsten4207?