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;
}
}