Switching between Wifi devices [Solved]

I am trying to have a starting Wifi Connection, then switching to another known Wifi AP and pinging google. After the ping is done it returns to the original Wifi AP.

Currently I never see the "Pings Return: " in my dashboard, and the device resets while running the code. Sometimes quickly showing red before restarting.

I have tried looking into

SYSTEM_THREAD(ENABLED);

but all I get is a flashing red led

Flow:
Photon starts Wifi SSID1
Photon connects to Wifi SSID2
ping
Photon connects to Wifi SSID1

Code:

bool connected = false;
int delayRun = 20000;
long lastRan = 0;
IPAddress pingAddr(192,168,1,1);
int led = D7;

void setup() {
    WiFi.setCredentials("SSID1", "password");
    WiFi.connect();
    pinMode(led, OUTPUT);
}

void loop() {
    if(!connected){
        WiFiAccessPoint aps[20];
        int found = WiFi.scan(aps, 10);
        for (int i=0; i<found; i++) {
            WiFiAccessPoint& ap = aps[i];
            if(String(ap.ssid).startsWith("SSID2")){
                debug("Found");
                WiFi.disconnect();
                WiFi.clearCredentials();
                WiFi.setCredentials(ap.ssid, "password");
                WiFi.connect();

                Particle.process();
                debug("SSID2 Connected");
                digitalWrite(led, HIGH);
                lastRan = millis();
                int ping;
                while(!WiFi.ready() && (millis() - lastRan) < delayRun){
                    Particle.process();
                }
                ping = WiFi.ping(pingAddr);
                Particle.process();

                WiFi.disconnect();
                WiFi.clearCredentials();
                WiFi.setCredentials("SSID1", "password");
                WiFi.connect();
                debug(String::format("Pings Return: %i", ping));
                
                digitalWrite(led, LOW);
                break;
            }
        }
    }
}

// Log message to cloud, message is a printf-formatted string
bool debug(String message) {
    return Particle.publish("DEBUG", message);
}

I’ve not ploughed through the whole code yet, but I’d recommend that you don’t set WiFi credentials unconditionally on each startup.
It’s not required and will push out other credentials that are already stored for other networks.

That was added in case it fails or restarts, so that I can get it to connect to a known Wifi. I had an issue for a while that the device kept ending up in listening mode, which forced me to use the phone app to re add the Credentials so that I could update the code.

You could use WiFi.hasCredentials() to check if there are any stored credentials and most likely one of the five possible sets should usually work.
But if you really could not WiFi connect, you can always use a serial terminal or CLI to provide new credentials.

You need to be aware that the WiFi credentials are stored in flash without good wear leveling, so if you keep clearing and setting credentials e.g. in loop() you might wear out your flash, rendering your device unusable.

Yes, it is definitely not the best way to switch between Wifi Access Points, but it is the only way I can figure out with the current Wifi API.

Using the Particle-CLI and Serial.print, I can see that the section:

debug("Found");
WiFi.disconnect();
WiFi.clearCredentials();
WiFi.setCredentials(ap.ssid, "password");
WiFi.connect();

causes the device to go into blinking blue (listening) mode. Specifically the line:

WiFi.setCredentials(ap.ssid, "password");

Once it start blinking blue I have to set the credentials either with the SoftAP or the USB, the setup() setCredentials() does not fix the blinking on restart as I had hoped.

To use WiFi.setCredentials() with only two parameters your desired network must be available, since the function needs to acquire the WLAN_CIPHER, which you could provide explicitly via the four-parameter version.

And it might be good to give the device some time between WiFi.setCredentials() and WiFi.connect().

I also can’t see that you are using a SYSTEM_MODE that allows for non-cloud operation. Even with SYSTEM_THREAD(ENABLED) SYSTEM_MODE(AUTOMATIC) would attempt to connect. Hence I’d suspect that actually WiFi.clearCredentials() will cause the system thread to jump into Listening Mode.
And since these threads are “independent” it migh appear as if WiFi.setCredentials() was causing it, but it might only be an after effect of the previous command.

So after this thread and thinking about it over night, i decided to simplify my code and exclude the cloud all together.

SYSTEM_MODE(MANUAL);
SYSTEM_THREAD(ENABLED);
int led = D7;
int pause = 10000;
IPAddress pingGate(192,168,1,1);
IPAddress pingGoogle(8,8,8,8);
IPAddress pingBad(169,254,0,0);

char input[30] = {0};
int pos = 0;

void setup() {
    pinMode(led, OUTPUT);
    Serial.begin(9600);
}

void loop() {

    digitalWrite(led, HIGH);
    Serial.println("On");

    Serial.printf("Cred: %i", WiFi.hasCredentials());
    if(WiFi.hasCredentials()){
        WiFi.connect();
        waitUntil(WiFi.ready);
        wait(1000);
        int pingGate = WiFi.ping(pingGate);
        Serial.printf("Ping Gateway: %i\n", pingGate);
        wait(1000);
        int pingGoog = WiFi.ping(pingGoogle);
        Serial.printf("Ping Google: %i\n", pingGoog);
        wait(1000);
        int pingBad = WiFi.ping(pingBad);
        Serial.printf("Ping Bad: %i\n", pingBad);
        wait(1000);
        WiFi.disconnect();
    }

    digitalWrite(led, LOW);
    Serial.println("Off");
    
    wait(5000);
}

void wait(long waitTime){
    long start = millis();
    while(millis()-start < waitTime){}
}

void serialEvent() {
  while (Serial.available())
  {
    char inChar = (char)Serial.read(); 
    Serial.write(inChar);
    if (inChar != '\r') // Command begins
    {
        input[pos] = inChar;
        pos++;
    }else{
        input[pos] = 0;
        changeWifi(input);
    }
  }
}

int changeWifi(char *command){
        char *ssid = strsep(&command, ",");
        char *pass = strsep(&command, ",");
        Serial.printf("SSID: %s, PASS: %s", ssid, pass);
        if(ssid != NULL && pass != NULL){
            WiFi.clearCredentials();
            WiFi.setCredentials(ssid, pass);
            return 1;
        }
        return 0;
}

Thanks for your insight