WiFi.hasCredentials() is blocking for 18 seconds

I have a WiFi setup process which from a user menu allows any existing credentials to be cleared. To test whether there are any credentials on the photon I am using WiFi.hasCredentials(). This works fine most of the time, however, if there are credentials on the photon but the device is not within range of the wi-fi (not wi-fi connected) then I am seeing a delay of approximately 18 seconds until the function returns an answer - the answer is correct. Is there anything that I can do to reduce this delay? Code snippet below:

SYSTEM_THREAD(ENABLED);

Serial.printlnf("wifiSetupScreen after  bmpDraw     at %i ", millis());
#endif
int i = WiFi.hasCredentials()?13:0;                         //V124B
mainButtons(2, i, 3, 4); //V091H/V124B
#if DEBUG
Serial.printlnf("wifiSetupScreen after mainButtons()at %i ", millis());
#endif

Let me ping someone that might be able to help, @rickkas7 or @ParticleD are you able to assist?

@KyleG I never received an answer to my question and I am being asked again by users why there is such a long delay in painting the buttons - surely WiFi.hasCredentials() could return quicker?

There’s certainly more code than that.

What SYSTEM_MODE are you using?

If you are in the process of connecting while calling WiFi.hasCredentials() it won’t return until the connection is complete or has failed, because there is a mutex on some WiFi operations.

In order to prevent blocking for WiFi.hasCredentials you need to check before you attempt to connect to WiFi or Particle cloud.

2 Likes

SYSTEM_MODE(SEMI-AUTOMATIC);

Correct - a very snippet of the code.

I have worked around this issue thus:

    if (WiFi.ready())                               //V126 to avoid read lock issue on DCT - if connected then must have credentials
    {
        mainButtons(14, 13, 3, 4); //V091H/V124B/V126
        if (screenBrightness == 0) softLite();      //V126
    }
    else
    {
        mainButtons(14, 0, 3, 4); //V091H/V124B/V126
        if (screenBrightness == 0) softLite();      //V126
        statusMessage("Checking for credentials");
        mainButtons(14, WiFi.hasCredentials()?13:0,3,4);
        clearStatusLine();
    }

I find it strange that checking for some wifi data existing or not needs to get blocked until connected or failed.

Any other suggestions about how to improve this welcomed.

Presumably you have a Particle.connect() or WiFi.connect() before the check for WiFi.ready() in SEMI_AUTOMATIC mode, otherwise the test would never be true.

You should move the test for WiFi.hasCredentials() before Particle.connect() or WiFi.connect(). You could store it in a variable instead of using it right away if necessary.

Correct - in setup() wifi module is set on and WiFi.connect() called.
There is a function which paints a connection symbol which is called just before the button symbols (code above). This checks if WiFi.ready() and if true but Particle.connect() is false will call Particle.connect() but only once.

I could have a global bool variable set which maintains if credentials set or not and will be non blocking. Seems like a clunky solution when there is a function WiFi.hasCredentials()?

The global variable with the result from WiFi.hasCredentials() is the best solution.

It’s actually the configuration flash mutex that’s causing the problem. Since some WICED calls modify the configuration flash we need to mutex the whole call, which may take a while.

The check for hasCredentials() also needs to access the configuration flash, and that’s why it blocks.

2 Likes

Just a side note, while it might appear clunky when writing the code, it's all but clunky when you consider the impact on the processor itself.
Calling a function that may well execute hundreds of machine code instructions and has to interact with an "external" device (the WiFi module) to hand you back a single boolean info multiple times compared to calling it only once and store the data which then can be re-accessed over and over with half a dozend instructions, calling the function is the clunkier approach when it comes to run-time assessment.

2 Likes

I found that entering listening mode prior to checking is a pretty good solution during setup.

The check for WiFi.hasCredentials() is only done when entering the screen for WiFi setup and is there to show or not a button to clear the stored WiFi credentials. So it is hardly a big overhead to call this function once even if it is complicated versus always calling the function in setup().

I have got an answer as to why it is blocking and what I can do to improve the UX. Thanks all.