Wifi keeps disconnecting (void loop() is clean)

Dear friends,

I was hesitating for some time before creating this topic, since I realize that I am not the only one having connection problems. Nevertheless, some weeks later, here I am.

My project runs on an Arduino nano 33 IoT through the Blynk server with Blynk library 0.6.1. My phone runs iOS 14.4.2. I have a FritzBox 7490 and Fritz!Repeater 1200, both configured as mesh with newest OS.

After starting the program, the wifi disconnects after a random amount of time (between 1 minute and 2 hours). Afterwards, the system is not able to reconnect itself. I then have to press the reset button or upload the sketch again via usb (OTA is also not available anymore, of course). Not only the connection to the Blynk server is lost, since the device does not show up in my router’s list of connected devices anymore.

The wifi signal seems strong enough when connected (-67dBm). I understood that keeping the void loop() clean is essential for Blynk. Apart from ArduinoOTA.poll() there is nothing more in it.

Maybe there is something wrong with the timing in my code? Or the program gets stuck somewhere? I truly appreciate your help and suggestions. Please find my code below:

#define BLYNK_PRINT Serial

#include <SPI.h>
#include <WiFiNINA.h>
#include <BlynkSimpleWiFiNINA.h>
#include <TimeLib.h>
#include <WidgetRTC.h>
#include <ArduinoOTA.h>

// const for Blynk
char auth[] = "-";
char ssid[] = "-";
char pass[] = "-";
// const for relais
const int pumpPin = 2;
const int valvePin = 3;
// const and vars for HC-SR04
const int trigPin = 9;
const int echoPin = 10;
float duration, distance;
// fill level water tank (min. u. max. distance between water surface and sensor in cm)
const int wasserMax = 3;
const int wasserMin = 15;
int waterLevel;
// variables for virtual pins in Blynk
int powerSwitch, valveButton, waterButton, morningButton, eveningButton, morningTime, eveningTime, waterDuration, lastFill;
bool morningWeekday, eveningWeekday, boolFill;
int i;

BlynkTimer timer;
WidgetRTC rtc;
WidgetTerminal terminal(V11);

// sync all pins with Blynk server
BLYNK_CONNECTED() {
  Blynk.syncAll();
  rtc.begin();
}

// read Blynk's virtual pins
BLYNK_WRITE(V0){powerSwitch = param.asInt();}
BLYNK_WRITE(V1){
  valveButton = param.asInt();
    // control solenoid
  if (valveButton == 1) checkwaterlevel();
  else if (valveButton == 2) digitalWrite(valvePin, LOW);
  else if (valveButton == 3) digitalWrite(valvePin, HIGH);
  }
BLYNK_WRITE(V2){waterButton = param.asInt();
  if (waterButton == 0) water();
  }
BLYNK_WRITE(V3){morningButton = param.asInt();}
BLYNK_WRITE(V4){eveningButton = param.asInt();}
BLYNK_WRITE(V5){
  TimeInputParam t(param);
   for (int j = 1; j <= 7; j++) {
    if (t.isWeekdaySelected(j)) {
      if (t.isWeekdaySelected(j) == weekday(now())) morningWeekday = 1;
    }
  }
  morningTime = param.asInt();
  }
BLYNK_WRITE(V6){
    TimeInputParam t(param);
   for (int j = 1; j <= 7; j++) {
    if (t.isWeekdaySelected(j)) {
      if (t.isWeekdaySelected(j) == weekday(now())) eveningWeekday = 1;
    }
  }
  eveningTime = param.asInt();
  }
BLYNK_WRITE(V7){waterDuration = param.asInt();
  Blynk.virtualWrite(V9, waterDuration);
  }
BLYNK_WRITE(V11)
{
  if (String("time") == param.asStr()) {
      terminal.print("it is ");
      terminal.println(timeToString(now()));
      terminal.flush();
  }
  if (String("signal") == param.asStr()) {
      long rssi = WiFi.RSSI();
      terminal.print("RSSI:");
      terminal.println(rssi);
      terminal.flush();
  }
}


// Digital clock display of the time
void clockDisplay()
{
  char currentTime[16];
  sprintf(currentTime, "%02d:%02d:%02d", hour(), minute(), second());
  // Send time to the App
  Blynk.virtualWrite(V12, currentTime);
  // irrigation timer
  int currentTimeInSeconds = 3600 * hour() + 60 * minute() + second();
  if (morningWeekday == 1 && morningButton == 1 && currentTimeInSeconds == morningTime) water();
  if (eveningWeekday == 1 && eveningButton == 1 && currentTimeInSeconds == eveningTime) water();
}

void setup()
{
  // pinModes for relais
  pinMode(pumpPin, OUTPUT);
  pinMode(valvePin, OUTPUT);
  digitalWrite(pumpPin, HIGH);
  digitalWrite(valvePin, HIGH);
  // pinModes for HC-SR04
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  // Debug console
  // Serial.begin(9600);
  Blynk.begin(auth, ssid, pass);
  Blynk.virtualWrite(V9, waterDuration);
  Blynk.virtualWrite(V2, HIGH);
  setSyncInterval(10 * 60); // Sync interval in seconds (10 minutes)
  // Display digital clock every 1 seconds
  timer.setInterval(1000L, clockDisplay);
  timer.setInterval(1010L, checkwaterlevel);
  boolFill = 0;
  lastFill = now();
  ArduinoOTA.begin(WiFi.localIP(), "Arduino", "-", InternalStorage);
  terminal.clear();
  terminal.print(timeToString(now()));
  terminal.println(" System gestartet.");
  terminal.flush();
  // TO DO: read lastFillTimer from server
  // BLYNK_WRITE(V10){morningButton = param.asStr();}
}


// method for irrigation
void water()
{
  if (waterLevel > 5){
    Blynk.virtualWrite(V2, LOW);
    digitalWrite(pumpPin, LOW);
    for (int i = waterDuration; i > 0; i--) {
      Blynk.virtualWrite(V9, i);
      delay(1000);
    }
    digitalWrite(pumpPin, HIGH);
    Blynk.virtualWrite(V9, waterDuration);
    Blynk.virtualWrite(V2, HIGH);
    terminal.print(timeToString(now()));
    terminal.println(" Bewässert.");
    terminal.flush();
  }
  else {
    if (waterButton == 0) Blynk.virtualWrite(V2, HIGH);
    terminal.print(timeToString(now()));
    terminal.println(" Nicht bewässert. Füllstand zu niedrig.");
    terminal.flush();
  }
}

void checkwaterlevel()
{
  // send and receive ultrasonic waves
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  // calculate distance in cm
  duration = pulseIn(echoPin, HIGH);
  distance = (duration*.0343)/2;
  // calculate fill level in %
  if (distance <= wasserMin && distance >= wasserMax) waterLevel = map(distance*100, wasserMin*100, wasserMax*100, 0, 100);
  else if (distance > wasserMin) waterLevel = 0;
  else if (distance < wasserMax) waterLevel = 100;
  // send fill level to Blynk
  Blynk.virtualWrite(V8, waterLevel);
    
  if (valveButton == 1){
     // close or open solenoid after status query of the pins
    if (waterLevel == 100){
      if (digitalRead(valvePin) == HIGH) digitalWrite(valvePin, LOW);
    }
    else if (waterLevel < 100){
      if (digitalRead(valvePin) == LOW) digitalWrite(valvePin, HIGH);
    }
  }
  else if (valveButton == 2) digitalWrite(valvePin, LOW);
  else if (valveButton == 3) digitalWrite(valvePin, HIGH);

  // TO DO: correct cases for boolfill
  if (waterLevel < 5){
    if (boolFill == 1){
      boolFill = 0;
      Blynk.notify("Füllstand niedrig!");
      terminal.println("Füllstand niedrig. Tank auffüllen.");
    }
  }
   else if (waterLevel > 75){
    if (boolFill == 0){
      boolFill = 1;
      lastFill = now();
    }
   }

  int lastFillTimer = now() - lastFill;
  Blynk.virtualWrite(V10, timeToString(lastFillTimer));
  Blynk.virtualWrite(V13, distance); 
}


char * timeToString(unsigned long t)
{
 static char str[12];
 long h = t / 3600;
 h %= 24;
 long d = h / 24;
 t = t % 3600;
 int m = t / 60;
 int s = t % 60;
 sprintf(str, "%02ld:%02ld:%02d:%02d", d, h, m, s);
 return str;
}

void loop() {
  Blynk.run();
  timer.run(); // Initiates BlynkTimer
  ArduinoOTA.poll();
}

From what I read in this forum, the blynk.run() routine also includes maintenance of the wifi connection. Is that correct? Nevertheless, I have also tried to include some manual wifi reconnection routine into my code. The routine consists of the method WDT_WiFi() (find snippet below) which was called from within void loop(). This routine has led to a little longer connection times of 1-2 days. Still, connection got lost after that and the system could not reconnect on its own anymore.

void WDT_WiFi() {
   if (!wifiBegun) {
    WiFi.begin(ssid, pass);
    delay(10000); // acceptable freeze  
    if (WiFi.status() == WL_CONNECTED) {
      wifiBegun = true;
    } else {
      WiFi.end();
    }
  } else if (wifiBegun && WiFi.status() != WL_CONNECTED) {
    WiFi.end();
    wifiBegun = false;
  }
}

I’d suggest that you have a re-connection routine which tests if Blynk is connected (Blynk.connected()) either in the void loop or as a timed function.

If you search the forum you’ll see that this has been discussed many times and there are many code examples.

Pete.

Pete, thanks for believing in me. I searched again and found this routine which works like a charm:

https://community.blynk.cc/t/esp8266-running-online-and-offline-also-reconnect-when-wifi-or-server-connection-fails/37519

Now I can move on, clean up the code and solve minor issues.

Thank you!!

1 Like