Maintaining a wifi connection in manual mode with threading enabled

Our team is developing a product built around the Photon that should function just as well offline as online. Furthermore, when a network connection is available, it’s important that our application code is never blocked for too long (> a few ms) lest that delay create a visible stutter that would detract from an end user’s experience. Thus, we’re wholly dependent on (and thankful for) the SYSTEM_THREAD feature that was rolled out in 0.4.6 and further stabilized in 0.4.7.

In MANUAL mode with SYSTEM_THREAD enabled, the application code is completely responsible for bringing up and maintaining a Wifi connection. I’ve brought up the question of how best to do this in the past for discussion, so I’m officially beginning one now.

At least for our devices, what we really want is the convenience of automatic mode with the controlled, nonblocking behavior of manual mode with threading enabled. A single call to Particle.connect() gets us almost everything we need:

  1. Enter listening mode, if no credentials are present (this can be bypassed by checking credentials manually)
  2. Connect to network, if credentials are present and router is available
  3. Connect to cloud, if outside access available

What we don’t have is:

  1. Some method of detecting connection status and failures for user feedback / debugging - There’s no Particle.connecting(), and cloud-related system events have not been fleshed out yet.
  2. Full manual control of cloud connectivity - Issue #748 Once a connection is attempted, the system firmware takes over the reins and reconnects and resets as it sees fit.

If these issues get fixed, anyone should be able to attain AUTOMATIC behavior in MANUAL+THREADING mode with simple code like this:

This may not be of much interest to non-organizational users, but it is definitely critical to any application that wants connectivity as a background feature without core functionality being blocked.

I was originally planning to post this state machine flowchart for attaining and maintaining connectivity, but I now think it is completely unnecessary given that Particle.connect probably has to determine all the same things and conditionally branch in all the same ways to function as advertised. Provided, of course, that it functions as advertised.

Thanks for reading!

There’s one aspect of this that I completely overlooked, and that’s the wifi setup process. The wifi setup process is an out-of-band method for controlling the connectivity state of the system - the very same state that the application firmware is attempting to control with Particle.connect() and monitor with calls like WiFi.hasCredentials().

In an ideal world, whatever connectivity flow the application implements would support the wifi setup process without any adverse effects. In our device’s ideal world, it would know exactly when the user caused it to enter listening mode and when it received valid credentials to connect with. I don’t think the “simple” code I posted above is very cooperative in that sense. My hunch is that as soon as a user makes the device enter listening mode, Particle.connect() will be called and the device will be reconnected to the network (which I’m about to test out).

In any case, this lends credence to the point I made earlier about the system events being useful, not only for feedback but also for determining the right network action to take based on the current network state. I don’t have a concrete suggestion to make on this just yet.

Adding to the list above:

  1. Nonblocking WiFi.connect() & Particle.connect() [ reference ] - There seems to be an issue where user code is blocked for a few seconds at a time even with SYSTEM_THREAD(ENABLED)

Just put this one to rest :wink:
With the right choice of SYSTEM_MODE() things work a bit smoother.

Awesome! We’ll take SEMI_AUTOMATIC out for a spin then.

Hello,
I’m sorry to reply to this old topic but I’m having some troubles with WiFi connection recovery in manual mode with threading enabled.

With a test application everything works fine and my Photon (version 0.6.0) is able to reconnect to a WiFi hotspot.
Here is the code to test it, code is very simple, reconnection is automatic.

SYSTEM_MODE(MANUAL);
SYSTEM_THREAD(ENABLED);


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

 WiFi.on();
 WiFi.selectAntenna(ANT_INTERNAL);
 WiFi.clearCredentials();
 WiFi.setCredentials("test","password");
 WiFi.connect();
}


void loop(){
 delay(1000);
 Serial.printlnf("%d WiFi: %s%s SSID:%s RSSI:%d", millis(), WiFi.connecting()?"C":"c",WiFi.ready()?"R":"r",WiFi.SSID(),WiFi.RSSI());
 Serial.printlnf("%d mem:%d", millis(), System.freeMemory());
}

This same code but in a complex code with UDP sockets leads to unwanted behavior. In fact when WiFi connection is lost WiFi.connecting() and WiFi.ready() are always false. In test application, connection is automatically retried.

Has anyone had the same problem?

One thing that is no good idea is this

void setup(){
  ...
 WiFi.selectAntenna(ANT_INTERNAL);
 WiFi.clearCredentials();
 WiFi.setCredentials("test","password");
 ...
}

these settings are written to flash and hence will stay there even after power down. But especially the clearCredentials()/setCredentials() combo does clear and rewirte the flash each start, which will sooner or later wear out your flash and then you can just ditch your devices.

And for your immediate question.
Once you see WiFi.ready() == false, why don’t you call WiFi.connect() again (only once with some timeout to not retrigger while the connection attempt is running)?

1 Like

Hi ScruffR,
code above works really fine. It was just an app to test WiFi reconnection ability. I don’t know why but there is no need to call WiFi.connect() when WiFi.ready() == false, everything is done automatically and reconnection works fine too.

But if I use same code for a complex project where UDP sockets are instantiated reconnection never occurs.

I will try to make a test app adding UDP socket to check if reconnection works