Arduino Uno WiFi Rev2 hangs if WiFi connection disrupted

I'm currently trying to implement a project using the Arduino Uno WiFi Rev2. I'm testing using one of the examples - WiFiWebClientRepeating and all works fine when I have a valid WiFi connection but when I try to test various error conditions the Uno hangs and can only be recovered via hard reset.
I've tracked it down to the command "client.connect(server, 80). Documentation states that this returns a flag indicating success or failure, however when the WiFi network is not available the application gets stuck on this command and I do not see anything returned.
My use-case is unattended without the opportunity to manually reset the device and because of the hang a programatic reset will not work. Given that in any typical implementation one should plan for network outages I cannot see that this behavior is correct.
Is this a problem with the library or am I doing something wrong?
Thanks for any guidance.

@dachurchill, please do not cross-post. Other thread removed.

sorry, new to this forum and initially missed that there was a section dedicated to the WiFi Rev2. It won't happen again :slight_smile:

Use Report to moderator if you ever want this thread moved.

I tested the example and after it was running I blacklisted the device on my router, thereby disconnecting it. Once I removed the blacklist entry the Arduino did not re-establish a connection to the router. This is exactly what should happen based on the example code. Please notice that the connection to the router is currently done in the setup method, this method only runs on boot (or reset). When the network connection is broken you will continually receive the "connection failed" message on the serial monitor because the program cannot reestablish it based on how it is written. You would want to call the code that creates the connection ( I would pull the code out of the setup method, put it in it's own method (see below) and call the new method from setup (in place of the existing code) as well as when you receive the "connection failed" error on line 108 of the example.

void createConnection() {

// This new line is required to disconnect the previous connection otherwise
// it will try to use the old connection and never reconnect if the connection fails
status=WiFi.disconnect();

// attempt to connect to Wifi network:
while (status != WL_CONNECTED) {
Serial.print("Attempting to connect to SSID: ");
Serial.println(ssid);
// Connect to WPA/WPA2 network. Change this line if using open or WEP network:
status = WiFi.begin(ssid, pass);

// wait 10 seconds for connection:
delay(10000);
}
// you're connected now, so print out the status:
printWifiStatus();

}

Thanks for testing this.
I understand what you are saying however what I am reporting is that the UNO WiFi Rev2 hangs and requires a hard reset at the command "client.connect(server,80)" This command is supposed to return a flag but in my case does not return anything, the command never returns control to the application.
I am using latest firmware (1.2.1) and library (1.4.0) as far as I can tell.
I tested this by running the example and then disconnecting power to my router. As soon as I do this the Uno just hangs and is completely unresponsive. There are no further updates to the serial monitor.
This is the issue I am trying to address.
Thanks

This is the original code that I am running from the example and I cannot replicate what you are saying is happening. If the client.connect(server, 80) fails, it drops through to the else and sends a message to the serial monitor. Which is where I suggest calling the new createConnection method.

// this method makes a HTTP connection to the server:
void httpRequest() {
// close any connection before send a new request.
// This will free the socket on the Nina module
client.stop();

// if there's a successful connection:
if (client.connect(server, 80)) {
Serial.println("connecting...");
// send the HTTP PUT request:
client.println("GET / HTTP/1.1");
client.println("Host: example.org");
client.println("User-Agent: ArduinoWiFi/1.1");
client.println("Connection: close");
client.println();

// note the time that the connection was made:
lastConnectionTime = millis();
} else {
// if you couldn't make a connection:
Serial.println("connection failed");
}
}

Thanks again.
In your test you state that you blacklisted the device. The only remaining difference is that I physically shut down the Router for a short period.... is there anyway you can test this scenario please?
Thanks

I cannot shutdown the router but I realized in the middle of the night a difference that has documentation to back it up. I recently installed firmware version 1.2.2 to test another problem from the hourly build of IDE 1.8.9 at https://www.arduino.cc/en/Main/Software#hourly and it is still installed on my Arduino. The change log shows fixes for hangs when the WiFi is disconnected. You could try updating to 1.2.2 and see if that gets rid of the hang. The program will still need to run the router connection code outside of setup. As far as I can tell during my testing, once connected, the status remains a 3 (WL_CONNECTED) even when the router is disconnected so it cannot be relied upon at this time to control whether the connection to the router failed (after successfully connected). As a work around, I just attempt to reconnect to the router if the client.connect fails...

Thanks for the excellent support !!!
I installed the latest firmware (1.2.2) and re-tested. It certainly looks like the hang condition has been fixed. In all my tests with this version, so far the WiFi Rev2 has fully recovered each time.
still much more testing needed but I am now past the one which was killing me, I'll post again when I am complete with my testing and/or I uncover anything else.
Again, I really appreciate the rapid assistance and advice.
Thanks !!

You're welcome! Glad to hear that the fix in 1.2.2 resolved your problem!

Is 1.2.2 released as yet?

FWIW I have run into what appears to be this exact problem using 1.2.1 Firmware. And with can with just some print commands isolate it to

client.connect(server, 80)

If I remote disable the wifi radio at the right moment the code will stop right there and never return.

I attempted to do things like check WiFi.status() before executing client.connect but all indications are that status stays WL_Connected for a few seconds after the Wifi radio goes silent, thus allowing client.connect() to try and fail and not return either a true nor false.

So in the following code fragment example, I can see "Attempting to connect to server..." in the Serial Monitor but not "connecting..." which pretty clearly says client.connect() is going away and never coming back...


void makehttpRequest() {
// If Wifi died before this call bail out

if (WiFi.status() != WL_CONNECTED) {
return;
}

Serial.println("Attempting to connect to server...");
// if there's a successful connection:
if (client.connect(server, 80)) {
Serial.println("connecting...");
// send the HTTP PUT request:
client.println("GET /data/2.5/forecast?q=" + nameOfCity + "&APPID=" + apiKey + "&mode=json&units=imperial&cnt=5 HTTP/1.1");
client.println("Host: api.openweathermap.org");
client.println("User-Agent: ArduinoWiFi/1.1");
client.println("Connection: close");
client.println();

Serial.println("Request Sent...");
... etc etc

ZainS:
Is 1.2.2 released as yet?

It depends on what you mean by "released".

There are three components to that question:

  • Has there been a release of the NINA firmware? I would say "yes" (actually there is even a 1.2.3 now), though the developers haven't created Git tags in that repository since the 1.1.0 release for some reason.
  • Has there been a release of the WiFi101/WiFi NINA Firmware Updater plugin for the Arduino IDE which contains NINA firmware 1.2.2? Yes. The 0.10.7 release of the plugin contains NINA firmware 1.2.2. The 0.10.8 release of the plugin contains NINA firmware 1.2.3.
  • Has there been a release of the Arduino IDE which contains WiFi101/WiFi NINA Firmware Updater plugin 0.10.7 or newer? No. There has not been an Arduino IDE release since the time that WiFi NINA 1.2.2 came out. It is part of the Arduino IDE hourly build though.

Thanks. Being the non-software newb I am, my definition of "released" is probably #3. Or anything were I can just ask the IDE to update itself and update firmware with handy menus. :slight_smile:

The Arduino IDE doesn't have the capability of updating itself with a new NINA firmware version, but if you use the Hourly Build, the 1.2.2 version is certainly there in the handy menus.

I am having a similar problem running the SimpleWebServer example . Firmware version is 1.2.4

If I switch off my router, the programme hangs and will not reconnect when the router is back up unless I reset the Arduino.

I have tried the suggestions above, but the wifi status remains at 3 even when there is no router so the program continuosly loops and will not reconnect.

Most frustrating, any help much appreciated.

/*


  created 25 Nov 2012
  by Tom Igoe
*/
#include <SPI.h>
#include <WiFiNINA.h>

#include "arduino_secrets.h"
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
char ssid[] = SECRET_SSID;        // your network SSID (name)
char pass[] = SECRET_PASS;    // your network password (use for WPA, or use as key for WEP)
int keyIndex = 0;                 // your network key Index number (needed only for WEP)

int status = WL_IDLE_STATUS;
WiFiServer server(80);
int x = 0;
void setup() {

  Serial.begin(9600);      // initialize serial communication
  pinMode(9, OUTPUT);      // set the LED pin mode

  // check for the WiFi module:
  if (WiFi.status() == WL_NO_MODULE) {
    Serial.println("Communication with WiFi module failed!");
    // don't continue
    while (true);
  }

  String fv = WiFi.firmwareVersion();
  if (fv < WIFI_FIRMWARE_LATEST_VERSION) {
    Serial.println("Please upgrade the firmware");
  }


  createConnection ();

}
void loop() {

  Serial.print("Wifi Status at start of loop; ");
  Serial.println (status);


  if (status != WL_CONNECTED) {
    createConnection();
  }
  WiFiClient client = server.available();   // listen for incoming clients

  if (client) {                             // if you get a client,
    Serial.println("new client");           // print a message out the serial port
    String currentLine = "";                // make a String to hold incoming data from the client
    while (client.connected()) {            // loop while the client's connected
      if (client.available()) {             // if there's bytes to read from the client,
        char c = client.read();             // read a byte, then
        Serial.write(c);                    // print it out the serial monitor
        if (c == '\n') {                    // if the byte is a newline character

          // if the current line is blank, you got two newline characters in a row.
          // that's the end of the client HTTP request, so send a response:
          if (currentLine.length() == 0) {
            // 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();

            // the content of the HTTP response follows the header:
            client.print("Click <a href=\"/H\">here</a> turn the LED on pin 9 on
");
            client.print("Click <a href=\"/L\">here</a> turn the LED on pin 9 off
");

            // The HTTP response ends with another blank line:
            client.println();
            // break out of the while loop:
            break;
          } else {    // if you got a newline, then clear currentLine:
            currentLine = "";
          }
        } else if (c != '\r') {  // if you got anything else but a carriage return character,
          currentLine += c;      // add it to the end of the currentLine
        }

      }
    }
    // close the connection:
    client.stop();
    Serial.println("client disconnected");
    x = x + 1;
    Serial.print ("Number of times through the loop: ");
    Serial.println (x);
    Serial.print ("Wifi Status at end of loop: ");
    Serial.println (status);
    if (status != WL_CONNECTED) {
      createConnection();
    }

  }
  delay (1000);
}


void printWifiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your board'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");
  // print where to go in a browser:
  Serial.print("To see this page in action, open a browser to http://");
  Serial.println(ip);
}

void createConnection() {
  // This new line is required to disconnect the previous connection otherwise
  // it will try to use the old connection and never reconnect if the connection fails
  status = WiFi.disconnect();

  while (status != WL_CONNECTED) {
    Serial.print("Attempting to connect to Network named: ");

    Serial.println(ssid);                   // print the network name (SSID);
    Serial.print ("Wifi Status during connection: ");
    Serial.println (status);
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    status = WiFi.begin(ssid, pass);
    // wait 10 seconds for connection:
    delay(10000);
  }
  printWifiStatus();                        // you're connected now, so print out the status
  server.begin();                           // start the web server on port 80
}

I have found a way round this by checking the WiFi strength, if the router drops out this goes down to 0.

This is the bit of code that checks the signal and restarts the sketch if the router has dropped out.

 void(* resetFunc) (void) = 0;//declare reset function at address 0

void loop() {

  if (WiFi.RSSI() == 0) // Checks if Wifi signal lost.
  { resetFunc(); //Calls Reset
  }


//rest of code goes here.

}

I have been trying to find a solution to this as well. I have been using the SimpleWebServer sketch as my test code. I'm running firmware version 1.3.0. I have tried moving the Wifi connection section of the code inside of the void loop and making it an IF statement instead of a WHILE loop. I've even left it as a WHILE loop so that I'm changing as little as possible from the working code. Everything appears to work. If I turn off the router (to force the wifi to drop) and then turn it back on, the Uno Wifi rev2 seems to hook back up to the router based on the messages coming across the serial monitor. However, the browser never can reconnect back to the Arduino (the web page never comes back and the browser eventually times out).

After doing some research, I found a thread on Github that suggests that even though the Arduino is getting an IP form the router again, something about the DNS not resolving. I don't know if that is the reason for my issue but its the only thing I have found. The thread suggests using client.stop() and Wifi.disconnect() to close any open TCP sockets. However, that didn't seem to resolve the issue either.

In general, I would like to know why a reset of the board successfully reconnects the Arduino to the router so that the web page is accessible but running the exact same code in the Void loop does not seem to work. Is there something that is getting cleaned out of memory during the reset? If so, is there a way I can do the same in the Void loop? Has anyone been successful at reconnecting the Arduino to the router and have have the web page work properly with out a full blown reset of the Arduino?

Below is my modified code that I think seems to reconnect to the router after a loss of signal but the web page stops functioning.

/*
  WiFi Web Server LED Blink

 A simple web server that lets you blink an LED via the web.
 This sketch will print the IP address of your WiFi module (once connected)
 to the Serial monitor. From there, you can open that address in a web browser
 to turn on and off the LED on pin 9.

 If the IP address of your board is yourAddress:
 http://yourAddress/H turns the LED on
 http://yourAddress/L turns it off

 This example is written for a network using WPA encryption. For
 WEP or WPA, change the Wifi.begin() call accordingly.

 Circuit:
 * Board with NINA module (Arduino MKR WiFi 1010, MKR VIDOR 4000 and UNO WiFi Rev.2)
 * LED attached to pin 9

 created 25 Nov 2012
 by Tom Igoe
 */
#include <SPI.h>
#include <WiFiNINA.h>

#include "arduino_secrets.h" 
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
char ssid[] = SECRET_SSID;        // your network SSID (name)
char pass[] = SECRET_PASS;    // your network password (use for WPA, or use as key for WEP)
int keyIndex = 0;                 // your network key Index number (needed only for WEP)

int status = WL_IDLE_STATUS;
WiFiServer server(80);
WiFiClient client;

void setup() {
  Serial.begin(9600);      // initialize serial communication
  pinMode(9, OUTPUT);      // set the LED pin mode

  // check for the WiFi module:
  if (WiFi.status() == WL_NO_MODULE) {
    Serial.println("Communication with WiFi module failed!");
    // don't continue
    while (true);
  }

  String fv = WiFi.firmwareVersion();
  if (fv < WIFI_FIRMWARE_LATEST_VERSION) {
    Serial.println("Please upgrade the firmware");
  }

  
  }
  



void loop() {
  
// attempt to connect to Wifi network:
  while (status != WL_CONNECTED) {
    Serial.print("Attempting to connect to Network named: ");
    Serial.println(ssid);                   // print the network name (SSID);
    client.stop();
    WiFi.disconnect();
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    status = WiFi.begin(ssid, pass);
    // wait 10 seconds for connection:
    delay(10000);
    server.begin();                           // start the web server on port 80
    printWifiStatus();                        // you're connected now, so print out the status
  }
    
  WiFiClient client = server.available();   // listen for incoming clients

  if (client) {                             // if you get a client,
    Serial.println("new client");           // print a message out the serial port
    String currentLine = "";                // make a String to hold incoming data from the client
    while (client.connected()) {            // loop while the client's connected
      if (client.available()) {             // if there's bytes to read from the client,
        char c = client.read();             // read a byte, then
        Serial.write(c);                    // print it out the serial monitor
        if (c == '\n') {                    // if the byte is a newline character

          // if the current line is blank, you got two newline characters in a row.
          // that's the end of the client HTTP request, so send a response:
          if (currentLine.length() == 0) {
            // 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();

            // the content of the HTTP response follows the header:
            client.print("Click <a href=\"/H\">here</a> turn the LED on pin 9 on
");
            client.print("Click <a href=\"/L\">here</a> turn the LED on pin 9 off
");

            // The HTTP response ends with another blank line:
            client.println();
            // break out of the while loop:
            break;
          } else {    // if you got a newline, then clear currentLine:
            currentLine = "";
          }
        } else if (c != '\r') {  // if you got anything else but a carriage return character,
          currentLine += c;      // add it to the end of the currentLine
        }

        // Check to see if the client request was "GET /H" or "GET /L":
        if (currentLine.endsWith("GET /H")) {
          digitalWrite(9, HIGH);               // GET /H turns the LED on
        }
        if (currentLine.endsWith("GET /L")) {
          digitalWrite(9, LOW);                // GET /L turns the LED off
        }
      }
    }
    // close the connection:
    client.stop();
    Serial.println("client disonnected");
  }
  status = WiFi.status();
}

void printWifiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your board'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");
  // print where to go in a browser:
  Serial.print("To see this page in action, open a browser to http://");
  Serial.println(ip);
}

Maybe try this function from loop(). It works in my case, but I am not running a server, only publishing data via MQTT.

Unfortunately, the WiFiNINA library has no ESP.reset() function, and lacks many others.

void connectToWLAN()
{
  // Check if the WLAN module works
  if (WiFi.status() == WL_NO_MODULE)
  {
    Serial.println("Connection to WLAN module failed");

    // If it doesn't, trap code execution here forever
    while (true)
    {
      // And indicate there is a WLAN module malfunction
      WiFi.setLEDs(0, 255, 0); // Red
    }
  }

  // Return to loop() if already connected to the WLAN router
  if (WiFi.status() == WL_CONNECTED)
  {
    return;
  }

  if (millis() - timeNowWLAN >= intervalWLAN)
  {
    // Update the timestamp for the next loop() execution
    timeNowWLAN = millis();

    Serial.println("Trying to connect to WLAN router");

    WiFi.disconnect();
    WiFi.end();

    // Indicate there is neither a WLAN router nor Internet connection yet
    WiFi.setLEDs(160, 255, 0); // Yellow

    // Start connection to WLAN router
    WiFi.begin(WLAN_SSID, WLAN_PASS);

    // WL_NO_SHIELD       = 255
    // WL_IDLE_STATUS     = 0
    // WL_NO_SSID_AVAIL   = 1
    // WL_SCAN_COMPLETED  = 2
    // WL_CONNECTED       = 3
    // WL_CONNECT_FAILED  = 4
    // WL_CONNECTION_LOST = 5
    // WL_DISCONNECTED    = 6
    Serial.println(WiFi.status());

    Serial.println("Connection to WLAN router successful");

    // Indicate that the WLAN router connection was established
    WiFi.setLEDs(255, 0, 0); // Green

    // A call to this function prints various connection details
    printWLANStatus();
  }
}

void printWLANStatus()
{
  // Print the ESP32's MAC address
  byte mac[6];
  WiFi.macAddress(mac);
  Serial.print("MAC address: ");

  // A call to this function fetches the MAC address
  printMacAddress(mac);

  // Print the SSID of the WLAN network connected to
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // Print the ESP32's IP address assigned by the router
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // Print the router's subnet mask, usually 255.255.255.0
  Serial.print("Subnet mask: ");
  Serial.println((IPAddress)WiFi.subnetMask());

  // Print the rounter's IP address
  Serial.print("Gateway IP: ");
  Serial.println((IPAddress)WiFi.gatewayIP());

  // Print the WLAN router's signal strength received
  long rssi = WiFi.RSSI();
  Serial.print("Signal strength (RSSI): ");
  Serial.print(rssi);
  Serial.println(" dBm");
}

void printMacAddress(byte mac[]) {
  for (int i = 5; i >= 0; i--) {
    if (mac[i] < 16) {
      Serial.print("0");
    }
    Serial.print(mac[i], HEX);
    if (i > 0) {
      Serial.print(":");
    }
  }
  Serial.println();
}