[SOLVED] Frequent disconnections - Arduino MKR WiFi 1010

Greetings everybody!
I’m a frequent reader of this community’s posts and found much help in creating my project: I’m building an astrophotographical observatory 3km from home and trying to remote control it through Arduino and Blynk.
Still having a problem with disconnections which won’t stop me (I already found a plan B and, even, plan C), but I would like to solve it to avoid Hard Resets.

Sorry for long post, but I would like to be precise in describing the whole thing.

I’m using all Arduino devices, mainly MKR1010 WiFi, but I also have a Nano BLE and a UNO WiFi Rev.2.
Arduino IDE on Mac OS. Actually in developing phase, so I’m at home using my WiFi and trying to solve bugs before finishing the project in observatory.
Using Blynk server. Blynk library is up to date and I raised the number of BLYNK_MSG_LIMIT from 100 to 1000 in the BlynkConfig.h file to avoid flood error (I know I should edit another file, but I think I’m not finding it unless I use a local server).
I have 3 devices finished (Meteo_IN very stable, Meteo_OUT and Roof_control not) actually coding the Power_station (almost finished), yet not started the Telescope one.

I’m posting the whole code of the Roof_control only because it has the worst behavior (much frequent disconnection than others). Trying to explain the code with comment line by line. I hope it is clear

#include <WDTZero.h>
#include <NewPing.h>
#include <Wire.h>
#include <MPU6050_light.h>
#include <SPI.h>
#include <WiFiNINA.h>
#include <BlynkSimpleWiFiNINA.h>

char auth[] = "xxxx";
char ssid[] = "xxxx";
char pass[] = "xxxx";

unsigned long lastConnectionAttempt = millis();
unsigned long WiFiDisconnectedTimer;
unsigned long BlynkDisconnectedTimer;

BlynkTimer timer;
WDTZero MyWatchDoggy;

#define SONAR_NUM 3      // Number of sensors.
#define MAX_DISTANCE 450 // Maximum distance (in cm) to ping.

NewPing sonar[SONAR_NUM] = {   // Sensor object array.
  NewPing(4, A0, MAX_DISTANCE), // Each sensor's trigger pin, echo pin, and max distance to ping.
  NewPing(4, A2, MAX_DISTANCE),
  NewPing(4, A4, MAX_DISTANCE)
};

MPU6050 mpu6050(Wire);

int FanSpeed;
int Tetto;
int Rain;
int Giorno;
WidgetLED tetto(V18);

WidgetBridge bridgeTettoMillis(V125);
WidgetBridge bridgeTetto(V14);

BLYNK_CONNECTED() {
  bridgeTettoMillis.setAuthToken("xxxx");
  bridgeTetto.setAuthToken("xxxx");
  bridgeTetto.setAuthToken("xxxx");
}

BLYNK_WRITE(V5) {
  FanSpeed = param.asInt();
}
BLYNK_WRITE(V17) {
  Giorno = param.asInt();
}

//------------------------------------------------------------------------------------------------
void setup() {
  Serial.begin(9600);                 
  Wire.begin();
  Blynk.begin(auth, ssid, pass);
  pinMode(6, OUTPUT); //fan speed control via PWM
  pinMode(8, OUTPUT); //relay control to open/close roof. It basically pushes a button of the gate-motor remote
  digitalWrite(0, LOW); //interrupt pin, must be low on reboot because of RISING method for interrupt
  mpu6050.begin();  //accelerometer to check actual roof movement
  mpu6050.calcOffsets(false, true);
  attachInterrupt(digitalPinToInterrupt(0), chiudiSePiove, RISING); //cabled interrupt coming from Meteo_OUT in case of rain
  MyWatchDoggy.setup(WDT_HARDCYCLE16S); //watchdog control set to 16s via WDTZero library in case of stuck loop
  timer.setInterval(30000L, connectionCheck);
  timer.setInterval(10000L, autoReset);
  timer.setInterval(5000L, controlFanSpeed);
  timer.setInterval(1000L, sendHeartbeat);
  timer.setInterval(500L, senseMovement);
  timer.setInterval(5000L, apertoOchiuso);
  timer.setInterval(5000L, chiudiSeGiorno);
}
//------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------
void sendHeartbeat() {  //send actual millis value to Power_station once per second. 
  bridgeTettoMillis.virtualWrite(V125, millis());   //If stuck for more than 60s, Power_station will shut down and up again to hard reset
  MyWatchDoggy.clear(); //stops watchdog timer once for every loop (about 3s)
}
//------------------------------------------------------------------------------------------------
void senseMovement() {  //Read accelerometer 3 axis data and send them to server twice per second - 180 float values per minute
  mpu6050.update();
  Blynk.virtualWrite(V0, mpu6050.getAccX());
  Blynk.virtualWrite(V1, mpu6050.getAccY());
  Blynk.virtualWrite(V2, mpu6050.getAccZ() - 1);
}
//------------------------------------------------------------------------------------------------
void apertoOchiuso() {  //Read ultrasonic sensor clearence of roof to understand if it is open or closed. 
  delay(100);           //100ms delay necessary for correct reading. 
  int sonar0 = sonar[0].ping_cm();  //5 int values for every 5s - total 60 int per minute
  Blynk.virtualWrite(V25, sonar0);
  delay(100);
  int sonar1 = sonar[1].ping_cm();
  Blynk.virtualWrite(V26, sonar1);
  delay(100);
  int sonar2 = sonar[2].ping_cm();
  Blynk.virtualWrite(V27, sonar2);
  int proximity = (sonar0 + sonar1 + sonar2) / 3;
  Blynk.virtualWrite(V28, proximity);
  if (proximity > 50) { //WidgetLED switching ON/OFF and changing roof status
    Tetto = 0;
    tetto.off();
  }
  else {
    Tetto = 1;
    tetto.on();
  }
  Blynk.virtualWrite(V14, Tetto); //Sending roof status
  bridgeTetto.virtualWrite(V14, Tetto); //bridging roof status for other operation in Meteo_stations
}
//------------------------------------------------------------------------------------------------
void chiudiSePiove() { //interrupt - close roof if it's raining
  if (Tetto == 0) {
    digitalWrite(8, HIGH);
    delay(1000); //keep button pushed for 1s
    digitalWrite(8, LOW);
    Blynk.notify("PIOVE! Chiusura tetto avviata");
    delay(15000); //wait 15s for roof closing. I don't mind disconnection after this. Roof must be closed
  }
}
//------------------------------------------------------------------------------------------------
void chiudiSeGiorno() { //close roof at sun rise, same closing routine
  if (Giorno == 1 && Tetto == 0) {
    Blynk.notify("È giorno. Chiusura tetto avviata");
    digitalWrite(8, HIGH);
    delay(1000);
    digitalWrite(8, LOW);
    delay(15000);
  }
}
//------------------------------------------------------------------------------------------------
void connectionCheck() {    //wifi status check, copied and pasted from Handle_disconnection example
  if (WiFi.status() != WL_CONNECTED) {
    if (millis() - lastConnectionAttempt >= 5000) {
      lastConnectionAttempt = millis();
      if (pass && strlen(pass)) {
        WiFi.begin((char*)ssid, (char*)pass);
      }
      else {
        WiFi.begin((char*)ssid);
      }
    }
  }
  if (!Blynk.connected()) { //added connection to server check
    Blynk.connect();
  }
}
//------------------------------------------------------------------------------------------------
void autoReset() {    // 3 cases for autoreset routine: 
  if (millis() >= 3600000) {  //1 hour is passed, 
    NVIC_SystemReset();
  }
  if (WiFi.status() != WL_CONNECTED) { //1 minute without WiFi connection, 
    WiFiDisconnectedTimer = millis();
    if (millis() - WiFiDisconnectedTimer >= 60000) {
      NVIC_SystemReset();
    }
  }
  if (!Blynk.connected()) {  //1 minute without Blynk connection
    BlynkDisconnectedTimer = millis();
    if (millis() - BlynkDisconnectedTimer >= 60000) {
     NVIC_SystemReset();
    }
  }
}
//------------------------------------------------------------------------------------------------
void controlFanSpeed() { // PWM control of fans
  if (Tetto == 1) {
    analogWrite(5, FanSpeed);
  }
}
//------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------
void loop() {
  Blynk.run();
  timer.run();
}

I counted 180 float and 48 int values per minute and 2 bridge (60 long and 12 int) per minute.
I really will appreciate any help

Those blocking delays aren’t a great idea.

This is a bad idea when using the Blynk cloud servers. The cloud servers shouldn’t really be sent more than 10 messages per second per pin, and 20 in total. The library has a mechanism to try to prevent the server from being overwhelmed and massively increasing this limit will cause problems rather than solving them.

Personally, I’d choose the same type of devices for everything, so that you have uniformity and swapability (if that’s a word). My preference would be ESP32 in this situation.

Also, as everything needs to talk to each other, I wouldn’t use Blynk and Bridge code to achieve the inter-communication, I’d use MQTT messaging and Node-Red as the middleware to do the Blynk communication. I’d probably then use Blynk primarily for my remote communication and use something like Nextion touch screens within the observatory for control when you’re on site.

Pete.

1 Like

Thank you Pete for being so responsive (if this is a correct word😅).

I can try switch the delay with

timer=millis();
if (millis() - timer >= 100) {
//etc
}

but in the Meteo_OUT device I don’t have any delay and still have the problem. Do you think this is the only problem?

Ok, so there is no problem with my code in this sense since I have about 250 uploads per minute on different pins. Thanks for clarification on the limit number.

I can do it, but MKR1010 hasn’t enough power (at least I think so) to manage 4 relay and it works on 3,3V. The telescope’s Arduino will manage also relays, so I’ll have 3 MKR1010 and 2 Uno WiFi or 2 Nano BLE (still have to buy the last module and keep for future tests one of the two)

I will try to understand what MQTT is, this is my first IoT project (actually my real first Arduino project!). Unless you consider this disconnection issue (which is practically solved rebooting once per hour), all the code is working and the app is really really responsive (I love it!). I’m not so compliant with the idea of a code revolution at this point, but I’ll give it a chance anyway.

Well, you’re already using “timer” as the object name for your BlynkTimer object, and this wouldn’t work anyway, as it’s not part of a loop that is waiting until the if test is true. A timeout timer, preferably as a lambda function is the correct approach.

It’s difficult to say without seeing the code. My other comment would be that this sketch has a lot of timers that coincide at various points, which isn’t a good idea.

As I said, I’d use an ESP32 board as my standard. It uses 3.3v logic levels but that’s not an issue. When you say “power to manage relays” I feel a little concerned. Relays should be powered by an external source, not from a source that is connected via the voltage regulator on your MCU. The relays should also be onto-isolated, so you are best with pre-built relay boards. The limitations from an MCU point of view are about how many suitable GPIO pins are available, not it’s “power”.

Also, is always choose boards that have native WiFi built- in. The UNO WiFi boards don’t meet this criteria in my book, as the WiFi connectivity is provided by a separate ESP8266 module. Far better to use a fully ESP8266 or ESP32 based board such as a NodeMCU or ESP32 Dev Board. I’d certainly never use a BLE board in an IOT project. The only time I’d use BLE would be if I needed to communicate with a 3rd party device that only has BLE connectivity and in that case I’d probably use OpenMQTTGateway (but that requires MQTT of course.

It’s a way of allowing devices to talk to each other in a structured way. The messages go via a broker, usually a server run on something like a Raspberry Pi. It’s far easier to use than Blynk’s Bridge process, and message bandwidth is higher.
For HA projects this is usually used alongside Node-Red (running on the same Raspberry Pi) and this is a visual programming/workflow environment that can easily take data from multiple MCUs and apply decision making rules.Node-Red has plug-ins for Blynk and many other services such as Amazon Alexa, Google Home etc.

I use this as the basis for my HA system and Blynk as the mobile front-end for this system.

Pete.

Man this Lambda timer is great! :heart_eyes:
instead of writing
delay(100);
I can write
timer.setTimeout(100, [] () {/*code*/});
but this is non-blocking, very compact and doesn’t need to declare many many timer for the if (millis() - xTimer >= xDelay) thing. THANK YOU A LOT! :love_letter:

I already corrected this awful error which was reported in various parts of the sketch (i.e. the “reset if disconnected for more than 60s” part) and replaced all the delay() and millis() timers I had.

My fault: the Nano is 33 IoT, not BLE. It also incorporates a bluetooth module, but I would mainly use it for WiFi as I am doing with the MKR1010 (the Ublox connectivity module is, at first sight, the same on every Arduino model, but I don’t remember if there are differences. Actually I spent many money to buy these boards, so I’m not going to change for ESP32 but I’m taking your advice in mind for future projects.

I’m actually pretty happy with this code now working smoothly. MQTT will be for sure matter of study for Observatory 2.0 :wink: