Arduinocloud.update() stops loop when connection is lost

I was trying to avoid starting a new thread, I've searched and found others with my issue but no real resolution. I have a fridge and a freezer that were previously using UNO R3 boards for about 6 months issue free. I recently switched both the fridge and freezer to UNO R4 WiFi boards, converted the codes to work with Arduino Cloud IoT so I can monitor temperatures from my phone, see if compressors are running, defrost cycle on or off, and have it log a temperature graph.

It worked great for 3 weeks, until the first time the internet went down during a wind storm. Basically, the loop freezes, and only runs once a minute as arduinocloud.update() tries to execute, but fails.Thankfully however, once wifi is back up and internet is available both reconnect just fine and continue on normally.

I need the loop to run regardless of WiFi connection or cloud connection. My code pretty much runs on seconds, without the loop running once per second, the compressors off-time delay of 5 minutes turns into 5 hours and the meat/beer goes warm, that isn't good.The IoT remote app is a nice feature, but not a priority here.

Is there something along the lines of the below?

if (WiFi connected && cloud connected) {
  arduinocloud.update();
}

Or a timeout?
Or if the update fails two times to give up?
I don't care if it takes a physical reset for it to try and reconnect.
Ive also considered putting in switches, with the update call in an if statement based on switch state so i have a failsafe if internet goes down.

I haven't been able to find much info, and am a novice with coding, but have some successful projects around the house using UNO R3s.

Thanks for any info.

//LIBRARIES
#include <DallasTemperature.h>
#include <OneWire.h>
#include <EEPROM.h>
#include <LiquidCrystal_PCF8574.h>
#include "thingProperties.h"

//INPUT PINS
#define ONE_WIRE_BUS 2
const int lcdchange = 3;    // LCD sub display (orange/white)
const int fanState = 5;     // State of Evaporator fan, used for on/off timing. (green)
const int compState = 7;    // State of Compressor, used for evap fan delay.(blue)
const int motion = 10;      // Motion for LCD backlight (brownwhite)

//OUTPUT PINS
const int evapFan = 4;      // Evaporator fan SSR (green)
const int compressor = 6;   // Compressor SSR (blue)
const int heater = 8;       // Defrost heater SSR (white)
const int alarm = 9;        // Alarm Beeper (brown)
const int fanLED = 11;      // Fan White LED (blue/white)
const int compLED = 12;     // Compressor Blue LED (blue)
const int defLED = 13;      // Defrost Yellow LED (orange)


//INTEGERS
int tempLOW = -3;         // Low setpoint
int tempHIGH = 3;         // High setpoint
int compwait = 0;         // Compressor wait time before start/restart, 3 min
int compRunMIN = 0;       // Compressor Runtime minutes (3,3)
int compRunSEC = 0;       // Compressor Runtime seconds (6,3)
int DEFonMIN = 29;        // Defrost timer Minutes (14,3)
int DEFonSEC = 59;        // Defrost timer Seconds (17,3)
int DEFoffHR = 7;         // Defrost countdown Hours (14,3)
int DEFoffMIN = 59;       // Defrost countdown Minutes (17,3)
int DEFoffSEC = 59;       // Defrost countdown Seconds (not displayed)
int Defrost;              // Defrost true or false
int defrostcount;         // number of defrost cycles completed
int resetcount;           // reset counter due to watchdog reset
int lighttimer;           // LCD light on for 10 minutes(600)


//Temp Alarm
unsigned long previousMillis = 0;  // Stores last time alarm sequence ran
unsigned long pulseInterval = 100;  // Interval for high/low pulse (100ms)
unsigned long sequenceInterval = 10000;  // Interval between sequences (10 seconds)
int pulseCount = 0;  // Count how many times the pulse has occurred

OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

// Addresses of DS18B20s
DeviceAddress cabinetTempAddress =  { 0x28, 0x61, 0x5C, 0x58, 0xD4, 0xE1, 0x3C, 0xB1 };
DeviceAddress evapTempAddress =  { 0x28, 0xEF, 0x3A, 0x58, 0xD4, 0xE1, 0x3C, 0xC5 };

//LCD Setup
char array1[] = "Cabinet |Set|  EVAP ";
char array2[] = " xx.x |-3 to 3| xx.x";
char array3[] = "Compressor | Defrost";
char array4[] = "   00:00   |  00:00 ";
char array5[] = "Resets    =         ";
char array6[] = "Defrosts  =         ";
char array7[] = "High Temp Beeps >30F";
char array8[] = "Hold for Defrost    ";
char array9[] = "Hold to cancel DEF  ";

LiquidCrystal_PCF8574 lcd(0x27);
char lcdDisplay[4][20];

void setup() {
  Serial.begin(9600);
  delay(1500);
  initProperties();
  ArduinoCloud.begin(ArduinoIoTPreferredConnection);
  setDebugMessageLevel(2);
  ArduinoCloud.printDebugInfo();
  pinMode(evapFan, OUTPUT);  digitalWrite(evapFan, OFF);
  pinMode(compressor, OUTPUT);  digitalWrite(compressor, OFF);
  pinMode(heater, OUTPUT); digitalWrite(heater, OFF);
  pinMode(alarm, OUTPUT);  digitalWrite(alarm, OFF);
  pinMode(fanLED, OUTPUT);  digitalWrite(fanLED, ON);
  pinMode(compLED, OUTPUT);  digitalWrite(compLED, ON);
  pinMode(defLED, OUTPUT);  digitalWrite(defLED, ON);
  pinMode(motion, INPUT_PULLUP);
  pinMode(compState, INPUT_PULLUP);
  pinMode(fanState, INPUT_PULLUP);
  pinMode(lcdchange, INPUT_PULLUP);
  lcd.begin(20,4);
  lcd.setBacklight(255);
  digitalWrite(fanLED, LOW);
  digitalWrite(compLED, LOW);
  digitalWrite(defLED, LOW);
  lcd.clear();
  lcd.print("Loading...");
  delay(5000);
  lcd.clear();
  lcd.print(array1);
  lcd.setCursor(0, 1);
  lcd.print(array2);
  lcd.setCursor(0, 2);
  lcd.print(array3);
  lcd.setCursor(0, 3);
  lcd.print(array4);
  resetcount = EEPROM.read(0);
  defrostcount = EEPROM.read(1);
  resetcount++;
  EEPROM.write(0, resetcount);
  sensors.begin();
  sensors.setResolution(12);
  sensors.requestTemperatures();
  float cabinetTempC = sensors.getTempC(cabinetTempAddress);
  float cabinetTempF = (cabinetTempC * 9.0 / 5.0) + 32;
  if (cabinetTempF <= 20) {
    Defrost = true; // Start defrost on power up if < 20F
  }
  else {
    Defrost = false;
  }
}

void loop() {
  ArduinoCloud.update();
  unsigned long currentMillis = millis();

  //LCD reset

  if (digitalRead(lcdchange) == LOW) {
    lcd.setBacklight(255);
    lcd.clear();
    lcd.print(array5);
    lcd.setCursor(0, 1);
    lcd.print(array6);
    lcd.setCursor(0, 2);
    lcd.print(array7);
    lcd.setCursor(0, 3);
    if (Defrost == false) {
      lcd.print(array8);
    }
    if (Defrost == true) {
      lcd.print(array9);
    }
    lcd.setCursor(11, 0);
    lcd.print(resetcount);
    lcd.setCursor(11, 1);
    lcd.print(defrostcount);
    delay(3000);
    if (digitalRead(lcdchange) == LOW) {
      if (Defrost == false) {
        Defrost = true;
        lcd.clear();
        lcd.setCursor(0, 1);
        lcd.print("Manual Defrost Start");
        lcd.setCursor(0, 2);
        lcd.print("Release Button");
        delay(2000);
      }
    }
    if (digitalRead(lcdchange) == LOW) {
      if (Defrost == true) {
        Defrost = false;
        compwait = 300;
        lcd.clear();
        lcd.setCursor(0, 1);
        lcd.print("Manual Defrost Stop");
        lcd.setCursor(0, 2);
        lcd.print("Release Button");
        delay(2000);
      }
    }
    lcd.clear();
    lcd.print(array1);
    lcd.setCursor(0, 1);
    lcd.print(array2);
    lcd.setCursor(0, 2);
    lcd.print(array3);
    lcd.setCursor(0, 3);
    lcd.print(array4);
  }

  // LCD Backlight

  if (digitalRead(motion) == HIGH) {      // light timer start at 3 minutes (180)
    lighttimer = 0;
  }
  lighttimer++;
  if (lighttimer <= 180) {               // light on, off after 3 minutes no motion
    lcd.setBacklight(255);
  }
  else {
    lcd.setBacklight(0);
  }

  //TEMP SENSORS-------------------------------------------------------------------------

  sensors.requestTemperatures();
  float cabinetTempC = sensors.getTempC(cabinetTempAddress);
  float evapTempC = sensors.getTempC(evapTempAddress);
  float cabinetTempF = (cabinetTempC * 9.0 / 5.0) + 32;
  float evapTempF = (evapTempC * 9.0 / 5.0) + 32;
  cabinetTempIND = cabinetTempF;
  evapTempIND = evapTempF;
  CloudTemperature cabinetTempIND;
  CloudTemperature evapTempIND;

  // Display cabinet temperature
  lcd.setCursor(0, 1);
  if (cabinetTempF >= 0 && cabinetTempF < 10) {
    lcd.print("  ");
  }
  if (cabinetTempF >= -9 && cabinetTempF <= -1) {
    lcd.print(" ");
  }
  if (cabinetTempF >= 10) {
    lcd.print(" ");
  }
  lcd.print(cabinetTempF, 1);

  // Display evap temperature
  lcd.setCursor(15, 1);
  if (evapTempF >= 0 && evapTempF < 10) {
    lcd.print("  ");
  }
  if (evapTempF >= -9 && evapTempF <= -1) {
    lcd.print(" ");
  }
  if (evapTempF >= 10) {
    lcd.print(" ");
  }
  lcd.print(evapTempF, 1);

  // Defrost-----------------------------------------------------------------------

  if (Defrost == true) {
    digitalWrite(compressor, LOW);
    digitalWrite(compLED, LOW); 
    compIND = false;
    digitalWrite(evapFan, LOW);
    digitalWrite(fanLED, LOW); 
    fanIND = false;
    digitalWrite(defLED, HIGH); 
    defIND = true;
    DEFoffHR = 7;
    DEFoffMIN = 59;
    DEFoffSEC = 59;
    if (evapTempF < 45) {
      digitalWrite(heater, HIGH);
    }
    if (evapTempF > 45) {
      digitalWrite(heater, LOW);
    }
    lcd.setCursor(3, 3);//compressor
    lcd.print("xx:xx");
    lcd.setCursor(14, 3);
    if (DEFonMIN < 10) {
      lcd.print("0");
    }
    lcd.print(DEFonMIN);
    lcd.setCursor(17, 3);
    if (DEFonSEC < 10) {
      lcd.print("0");
    }
    lcd.print(DEFonSEC);
    DEFonSEC = DEFonSEC - 1;

    if (DEFonSEC == -1) {
      DEFonSEC = 59;
      DEFonMIN = DEFonMIN - 1;
    }
    if (DEFonMIN == -1) { // 30 min terminate
      digitalWrite(heater, LOW);
      digitalWrite(defLED, LOW); 
      defIND = false;
      Defrost = false;
      defrostcount++;
      EEPROM.write(1, defrostcount);
      DEFonMIN = 29;
      DEFonSEC = 59;
      compRunMIN = 0;
      compRunSEC = 0;
      compwait = 180;
    }//30 min terminate
    if (cabinetTempF >= 20) {  // 20 degree terminate
      digitalWrite(heater, LOW);
      digitalWrite(defLED, LOW); 
      defIND = false;
      Defrost = false;
      defrostcount++;
      EEPROM.write(1, defrostcount);
      DEFonMIN = 29;
      DEFonSEC = 59;
      compRunMIN = 0;
      compRunSEC = 0;
      compwait = 180;
    }//32 degree terminate
  }//defrost

  if (Defrost == false) {

    digitalWrite(heater, LOW);
    digitalWrite(defLED, LOW); 
    defIND = false;
    //Defrost countdown
    lcd.setCursor(14, 3);
    if (DEFoffHR < 10) {lcd.print("0");}
    lcd.print(DEFoffHR);
    lcd.setCursor(17, 3);
    if (DEFoffMIN < 10) {lcd.print("0");}
    lcd.print(DEFoffMIN);
    if (DEFoffSEC == -1) {
      DEFoffSEC = 59;
      DEFoffMIN = DEFoffMIN - 1;
    }
    if (DEFoffMIN == -1) {
      DEFoffMIN = 59;
      DEFoffHR = DEFoffHR - 1;
    }
    DEFoffSEC = DEFoffSEC - 1;
    if (DEFoffHR == -1) {
      Defrost = true;
    }

    // Temp Alarm-------------------------------------------------------------------

    if (cabinetTempF >= 30) {//high temp alarm
      if (currentMillis - previousMillis >= sequenceInterval) {
        previousMillis = currentMillis;
        pulseCount = 0;
        while (pulseCount < 4) {
          digitalWrite(alarm, HIGH);
          delay(pulseInterval);
          digitalWrite(alarm, LOW);
          delay(pulseInterval);
          pulseCount++;  // Increment pulse count
        }
      }
    }//high temp alarm

    // Temp Control--------------------------------------------------------------------

    if (cabinetTempF >= tempHIGH) {// Temperature HIGH Setpoint, turn compressor on
      if (compwait < 300) {// 5 min minumum off time
        digitalWrite(compressor, LOW);
        digitalWrite(compLED, LOW); 
        compIND = false;
      } else {
        digitalWrite(compressor, HIGH);
        digitalWrite(compLED, HIGH); 
        compIND = true;
      }
    }//high setpoint

    if (cabinetTempF < tempLOW) {// Temperature LOW Setpoint, turn compressor off
      digitalWrite(compressor, LOW);
      digitalWrite(compLED, LOW); 
      compIND = false;
      compwait = 0;
    }//low setpoint

    if (evapTempF <= cabinetTempF && evapTempF < 30) {//evap temp less than cabinet
      digitalWrite(evapFan, HIGH);
      digitalWrite(fanLED, HIGH); 
      fanIND = true;
    }//less then
    else {//evap temp greater than cabinet
      digitalWrite(evapFan, LOW);
      digitalWrite(fanLED, LOW); 
      fanIND = false;
    }//greater then

    // Compressor ON-------------------------------------------------------------

    if (digitalRead(compState) == HIGH) {
      lcd.setCursor(3, 3);          //compressor minutes
      if (compRunMIN < 10) {
        lcd.print("0");
      }
      lcd.print(compRunMIN);
      lcd.setCursor(6, 3);          //compressor seconds
      if (compRunSEC < 10) {
        lcd.print("0");
      }
      lcd.print(compRunSEC);
      compRunSEC = compRunSEC + 1;
      if (compRunSEC == 60) {        // compressor seconds counter
        compRunSEC = 00;
        compRunMIN = compRunMIN + 1;
      }
    }//compstate on

    else {//compressor off
      compRunMIN = 0;                    //runtime reset
      compRunSEC = 0;                    //runtime reset
      compwait++;
    }//Compressor OFF
  }//Defrost false
  delay(400);  //buffer to keep counting by seconds
}//Loop

Hi @tmarsh1994 you can check if WiFI connection is up using WiFi.status() and also trim the time WiFi.begin() waits before returning an error if there is no WiFi connection using WiFi.setTimeout(). The default is 10s.

However it looks a bit strange to me the loop() is blocking for 60 seconds... I've made a test and if WiFi connection is up but there is no internet the loop() runs every 10s. The cause of this is the WiFi.getTime() call in the connectionHandler that is waiting for a response from the firmware. This should be fixed using the new firmware will be released.

Yes, I’m sorry, I just tested it myself by unplugging Ethernet to my router, and you are correct. The loop does appear to run every 10 seconds. I didn’t pay close attention before as to how long it was.

So the WiFi.status(), does that apply to only the connection to wifi or does it also cover the actual cloud connection? Again, my issue was that the wifi connection was there, but no connection to the internet due to a service interruption.

WiFi.status() applies only to WiFi connection, if you want to remove the 10s wait time you should try to load the new WiFi firmware.

You can check cloud connection using ArduinoCloud.connected() but if connection drops and you don't call ArduinoCloud.update() the board will not re-connect automatically to the cloud.

1 Like

21 posts were split to a new topic: Loop stops after Internet connection is lost

Hello @pennam,

The OPTAs are doing the same thing when an internet connection is lost: a 10s delay which appears to be coming from WiFi.getTime().

It would be nice to control for this delay in loop() since we have devices that rely on timing with other boards, relays and equipment which this delay causes problems with, similar to @tmarsh1994

We've managed to control for no connection at boot which allows the OPTA to run fast without a connection, check every 15m for a connection, and if available, start the ConnectionHandler.

The current work around for a lost connection during operation after a connection has been established, is a reboot like this after a 5m connection loss:

if( !ArduinoCloud.connected() && ((millis() - lostConnectionStart) > 5 * 60 * 1000) ) {
  NVIC_SystemReset();
}

Even with the 10s delays, this code is eventually executed rather quickly once the 5m mark has elapsed.

Once the reboot happens, the device typically cannot connect at boot due to more persistent internet issues vs. transient ones, which then allows loop() to run fast without a connection, trying every 15m as above to reconnect.

I'll take a look at how WiFi.status() or WiFi.setTimeout() may help us. The reboot isn't that big of a deal as we've managed to limit downstream equipment cycling using time-delay relays or other OPTAs. But still, I would think that we could solve this in software.

Thanks for any updates!

Chris

Hi @hermosaranchllc
thanks for your explanation. I do not thingìk the delay is coming from WiFi.getTime(), that function is not even implemented,returning always 0.

If I recall correctly the timeout is coming from helper function getHostByName, used from NTPUtils inside of ArduinoIoTCloud. Initially the timeout was really long and then we have reduced it to 15seconds.

Unfortunately it is not configurable at runtime but you can experiment with this configurations and see if situation improves

If you are willing to test a change i would say the easyest way to fix it is to change this line of ArduinoIoTCloud library from

if (_time_service.sync())

to

if (_time_service.getTime())

1 Like

I've changed my mind and I do not think this is enough, because then connect() will hang if there is no internet access...

Providing an IP address instead of the hostname here should skip dns resolution and then you can configure the NTP timeout with this value.

If it work we can add some setters to get this done.