WiFi drops after about ~15 minutes

Hey all,

I'm building a garage door controller that exposes an HTTP UI for status and control. I'm having a few issues, which I think might be related either to the board or (more likely) my implementation of the code using WiFi.

Issue #1: WiFi seems to disconnect from the AP after a period of time, sometimes a few hours, but often mostly around 15 minutes

Issue #2: While operational, sending "too many" connections to the board (i.e. reloading the browser page more than about once every 3-4 seconds) will cause it to 'hang'.

My first and major issue is #1; it's largely useless as a garage door controller if I have to keep power-cycling the board every 15 minutes.

The code is below; note I had to remove code comments/truncate some functions for brevity to avoid hitting the maximum character limit for a post. Appreciate any pointers/tips you have for trying to get this to work more reliably!

(Oh, probably worth mentioning I've just updated the board firmware and the WiFi firmware, still no joy)

Thanks.

#include <WiFi101.h>

// ArduinoCloud - Version: Latest 
#include <ArduinoCloud.h>
#include <ArduinoCloudThing.h>
#include <ArduinoCloudThingBase.h>
// Arduino Cloud settings and credentials
const char userName[]   = "XXX";
const char thingName[] = "XXX";
const char thingId[]   = "XXX";
const char thingPsw[]  = "XXX";
WiFiSSLClient sslClient;
ArduinoCloudThing GDC;


// Configuration
int RELAY_PIN = 7;
int SWITCH_SENSOR_PIN = 8;
int SWITCH_POWER_PIN = 9;
int RELAY_DURATION_MS = 750;
char SSID[] = SECRET_SSID;
char PASSWORD[] = SECRET_PASSWORD;

// Global variables
int relayTriggering = 0;
int errorState = 0;
const int OPEN = HIGH;
const int CLOSED = LOW;
int status = WL_IDLE_STATUS;
String doorState = "UNKNOWN";
String lastDoorState = "UNKNOWN";
int wifiStatus;

// Objects
WiFiServer server(80);

void setup() {
    configurePins();
    Serial.begin(9600);    
    delay(3500);    
    initialiseWifi();     
    initialiseServer();       
    
	//Arduino cloud
	GDC.begin(thingName, userName, thingId, thingPsw, sslClient);
    GDC.enableDebug();
    GDC.addProperty("garageDoorStatus", CHARSTRING, R);
    GDC.addProperty("sensorPinValue", INT, R);
	
    initialiseSensorSwitch(); 

    digitalWrite(6, HIGH); 
}

void loop() {   
   listenHttpServer();    
   getDoorState();   
   checkAndReconnectWifi();
}

void configurePins() {
  pinMode(RELAY_PIN, OUTPUT);
  pinMode(SWITCH_SENSOR_PIN, INPUT_PULLUP);
  pinMode(SWITCH_POWER_PIN, OUTPUT);    
  pinMode(6, OUTPUT); 
}

void initialiseSensorSwitch() {
  digitalWrite(SWITCH_POWER_PIN, HIGH);
  digitalWrite(SWITCH_SENSOR_PIN, HIGH);
  doorState = getDoorState();
  
  Serial.println("Writing door state to Arduino cloud...");
  GDC.writeProperty("garageDoorStatus", doorState);
  GDC.writeProperty("sensorPinValue", digitalRead(SWITCH_SENSOR_PIN));
}


String getDoorState() {
  
  int state = digitalRead(SWITCH_SENSOR_PIN);  
  digitalWrite(6, !state);
  if (state == LOW) {     
    doorState = "CLOSED";
  } else {
    doorState = "OPEN";    
  }
  
  if (doorState != lastDoorState) {
    lastDoorState = doorState;    
    GDC.writeProperty("garageDoorStatus", doorState);
  }  
  return doorState;
}

void initialiseServer() {
  server.begin();
}

// Create an HTTP Server to listen for connections and return pages.
void listenHttpServer() {
  WiFiClient client = server.available();
  if (client) {                             
    //Serial.println("new client");        
    String currentLine = "";                
    while (client.connected()) {           
      if (client.available()) {             
        char c = client.read();            
        //Serial.write(c);                  
        if (c == '\n') {                    

          if (currentLine.length() == 0) {
            
            String hdrs = "";
            String page = indexPage();
            hdrs += "HTTP/1.1 200 OK\n";
            hdrs += "Content-type:text/html\n";
            hdrs += "Server: GDC, by Richard Parker\n";
            hdrs += "Connection: close\n";
            hdrs += "Content-Length: " + page.length();
            hdrs += "\n";            
            hdrs += "\n\n";
            
            client.print(hdrs);
            client.print(page);
            client.print("\n\n");            
            
            break;
          }
          else {      
            currentLine = "";
          }
        }
        else if (c != '\r') {    
          currentLine += c;      
        }

       
        if (currentLine.endsWith("GET /PUSH")) {
         pulseRelay();
        }
      }
    }
    
    client.stop();
    Serial.println("disconnected client");    
  } 
}

String indexPage() {
  
  String response = "";  
  
  response += "<html>\n";
  response += "<head>\n";
  
  // Truncated for brevity
  
  // The HTTP response ends with another blank line:
  response += "</div>\n";
  response += "</body></html>\n";   
  
  return response;  
}


String getDoorStateHtml() {
  // Truncated for brevity
}

// Initialise and turn ON WiFi...
void initialiseWifi() {
  Serial.println("BOOT: Initialising WiFi... ");
  
  if (WiFi.status() == WL_NO_SHIELD) {
    Serial.println("ERROR: WiFi chip not present.");    
    errorState = 1;
  } 
  
  else {
    
    Serial.println("BOOT: WiFi chip OK!");
    Serial.print("WIFI: Attempting to connect to SSID: ");
    Serial.println(SSID);
    
    
    while (wifiStatus != WL_CONNECTED) {           
      wifiStatus = WiFi.begin(SSID, PASSWORD);
      delay(5000);              
    }
    
    Serial.print("WIFI: ");
    Serial.print(SSID);
    Serial.println(" connected!");
    printWifiStatus();
  }
}

void checkAndReconnectWifi() {
  if (WiFi.status() != WL_CONNECTED) {
    while (status != WL_CONNECTED) {
      Serial.println("WIFI: Disconnected. Reconnecting...");
      status = WiFi.begin(SSID, PASSWORD);
      delay(5000);
    }
    Serial.println("WIFI: Reconnected!");
    printWifiStatus();
  }
}

void printWifiStatus() {
 // Truncated for brevity
}

void pulseRelay() {  
  if (relayTriggering == true) { exit; } // This is effectively a "de-bounce" for relay-triggering.
    
  relayTriggering = true;  
  Serial.print("Triggering relay... ");
  digitalWrite(RELAY_PIN, OPEN);
  delay(RELAY_DURATION_MS);
  digitalWrite(RELAY_PIN, CLOSED);
  Serial.println("Finished.");
  relayTriggering = false;    
}

It looks like you are using Arduino CLOUD ?
If so you should be aware it is still classed as BETA.

A couple of things for the MKR1000 though.

Some earlier boards suffered dropouts but this was fixed when the firmware was upgraded.
There is a quite painless upgrade path.

IIRC it is mentioned in a few other posts.
It can only be performed with the regular IDE which should be at least 1.8.5
There is an example in the WiFi101 section called "CheckWiFi101FirmwareVersion" and you should load that first to see if you need to update.
It will tell you in the serial console if there is an update.

If that is the case then there is another example called "FirmwareUpdater" that you should upload as that will prepare the MKR1000 for the update.

Then you can use TOOLS, WiFi Firmware Updater which will open a new box with options to do the update.

From that box select the correct COM port and test the connection then select the correct firmware and simply do the update.

As far as RELAY's go they often have a very specific voltage and current requirement. Be careful that you are supplying a steady voltage and enough current possibly with and external supply NOT from the MKR1000 although a common ground to the MKR should be used.

Hi ballscrewbob,

Thanks for your reply. I started out with the latest version of the firmware having updated at the first sign of trouble (my first port of call when I experience these types of issues - usually folks have already fixed them!).

This however didn't resolve my issue.

I also did some additional fairly extensive testing over the weekend and have since found a solution which appears - fingers crossed - to be more stable. Using my Ubiquiti WiFi AP, I've been able to pull up client statistics to give me an insight into the connection problems. Caveat: while I'm not a WiFi expert, here's my take on what I've found:

  1. The MKR1000 is a fantastic little receiver. It isn't the best at transmitting though. I was apparently asking too much of it to reach the WiFi AP (installed in the roof of the main house) from the garage - through a few concrete walls.

  2. The UniFi AP would effectively seem to trigger a disconnect and re-connect cycle on the MKR1000 after too many transmit fails were acknowledged; BUT it seemed the MKR1000 was't handling those - and never reconnected.

  3. Perhaps something in the firmware (?) on the MKR1000 WiFi module needs an update to watch for those kind of disconnects?

In the meantime, I've since installed a separate AP and the MKR1000 has been stably connected now for about 23 hours. It also doesn't seem to suffer the intermittent 'packet loss' (which I assume was happening for me to experience the types of issues I was seeing) now that the AP is closer.

Sorry I can't be more definitive, but if anything changes I'll update the thread so people can track the progress, however, so far - everything looks good by ensuring the MKR1000 is closer from a transmit point-of-view.

Thanks!

Agree 100% with the TX side of things.

Moved my router to the centre of the house from a lower position the cable guy installed it and got much better coverage even outside.

Having your main AP high is not a good thing as the nulls may miss things in a lot of positions. (ground plane effect)

Many routers have unknown nulls and lobes.
Attached a pic that is a little more descriptive.

I can understand why you wanted it high which would normally be the case with a real antenna.
However with WiFi there are other considerations such as the shorter range.

Makes total sense. I'm hopeful that the AP I purchased (UAP-AC-LR PRO) should have a slightly more usable radiation pattern in the orientation it is now mounted (vs. the orientation before; now it is essentially pointed directly DOWN at the garage - both RX and TX) since UBNT quote:

Since most UniFi access points are designed to be mounted on the ceiling or wall, signal has been optimized for the direction opposite of the mounting side or in the direction facing the U symbol

Source: https://help.ubnt.com/hc/en-us/articles/115012664088#3

Of course, that wouldn't affect the TX side of things on the MKR1000 - it still has to reach the AP.

Out of curiosity, does the MKRWIFI1010 have a better TX capability do you know? Or does it support an additional antenna?

Thanks!

Yes the MKR1010 has a little better RX / TX but still within the bounds of regular WiFi which is subject to strict limitations (country dependant)

Neither the MKR1000 or the 1010 have external antenna sources which I consider an OMISSION on the part of the designers of the 1010.

If you had the equipment and knowledge you could supplement either of them but such modifications would void any warranty and experience would be a must.

There are some other old tricks you could use to help such as tinfoil behind its mounting location in a fixed deployment but that means you must ensure that the board and any other items cannot come into contact with whatever you use as a radio reflective surface.

Google the old cell phone tricks of adding tinfoil to the backs of phones and such. But remember it makes them directional. See the first picture above as that is highly directional and can provide a few dB of gain.

EDIT.

If your router has real antenna and more than one you could swap out one of them for such as this giving you an much better range and highly directional. "point and shoot"