MKR 1000 WIFI connection drops but WiFi.status() == WL_CONNECTED

I am able to connect to wifi fine as well as reconnect when the connection is lost. This has been tested via router restart and I can confirm that WiFi.status() reports a disconnected status during this event. The web server responds via IP and MDNS fine and functions for a good many hours but inevitably (<8hrs) stops responding. At that point I no longer see that the IP is leased by the router, not surprisingly it does not respond to pings because the IP is unroutable. The rest of the program continues to run fine; not stuck in an endless loop. A serial debug reports that the connection is fine:

18:50:45.990 → WiFi Status: 3
18:50:45.990 → SSID: ROSOLA-2.4G
18:50:45.990 → IP Address: 192.168.1.107
18:50:45.990 → signal strength (RSSI):-42 dBm

Interestingly if I then restart the router, the WiFi.status() reports a disconnected status and reconnect logic brings it back online without issue once the router is back up.

Firmware is updated to 19.6.1

WiFi101 Library is version 0.16.0

Router is TPLink Archer C9 (plain old DHCP config)

I have read many related topics but unfortunately have not found an answer. Any thoughts?

I am close to forcing a connection reconnect on a periodic basis or perhaps have it ping it’s host to test it is connected rather than trusting WiFi.status() but these sort of work-arounds should not be necessary.

DEBUG CODE:

void printWiFiStatus() {

  //print wifi status
  Serial.print("WiFi Status: ");
  Serial.println(WiFi.status());
  
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your WiFi shield's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}

CONNECT CODE:

void setupWifi() {

  // wait while not connected
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
  }

  //connected, so start server & MDNS
  server.begin();
  if (!mdnsResponder.begin(mdnsName)) {
    Serial.println("Failed to start MDNS responder!");
    while(1);
  }

  Serial.print("Server listening at http://");
  Serial.print(mdnsName);
  Serial.println(".local/");

}

RECONNECT CODE:

  //attempt to reconnect to wifi if disconnected
    if ( WiFi.status() != WL_CONNECTED ) {
      Serial.println("attempting to reconnect to wifi");
      WiFi.end();
      WiFi.beginProvision();
      delay(5000);
      if ( WiFi.status() != WL_CONNECTED) {
        Serial.println("reconnect failed");
      }else{
        Serial.println("reconnected successful, starting server and dns");
        server.begin();
        mdnsResponder.begin(mdnsName);
      }
    }

WEB SERVER CODE

void operateWebServer(){
   
  // Call the update() function on the MDNS responder every loop iteration to
  // make sure it can detect and respond to name requests.
  mdnsResponder.poll();

  // listen for incoming clients
  WiFiClient client = server.available();
  
  if (client) {                             

    // loop while the client's connected
    unsigned long actualTime = millis(); 
    while (client.connected()) {    

      // exit loop if stuck here.
      if (millis() > actualTime + 20000) {
          Serial.println("Timeout. Forcing client to exit.");
          break;                              
      }
        
      if (client.available()) {             

        //get request
        String c = client.readString();        
        Serial.print(c);                    
             
        // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
        // and a content-type so the client knows what's coming, then a blank line:
        client.println("HTTP/1.1 200 OK");
        client.println("Content-type:text/html");
        client.println();
        
        client.println("HTML STUFF");

        // The HTTP response ends with another blank line:
        client.println();

        // break out of the while loop:
        break;
        
      }
    }
    // close the connection:
    client.flush();
    client.stop();
    Serial.println("client disonnected");
  }
  
}

I had a hunch that the root cause may be the lease length on the router (120 mins in my case). I tested setting my DHCP lease length to 5 mins and monitored and I saw it renew its lease multiple times without issue, so I don't think that is it either.

I have found that pinging the Gateway IP returns “-1” when this connection drop condition occurs so at least I have a fairly easy way to test for it. I am now running with this periodic check below in place to force a reconnect; This is still not acceptable behavior.

bool isWifiConnected(){

  //check connected
  if ( WiFi.status() != WL_CONNECTED) {
    return false;
  }

  //test ping the gateway
  IPAddress gip = WiFi.gatewayIP();
  int pingResult = WiFi.ping(gip);
  if (pingResult < 0) {
    return false;
  }  

  //connected
  return true;
  
}

Some disconnect errors could possibly be due to firmware.
It is certainly worth checking that you are up to date as some of the early MKR's had disconnect issues that were fixed by that upgrade.

BTW thank you for the well laid out posts.
That is very refreshing for a new user

Bob.