Device doesn't reconnect after losing wifi connection

I have a MKR1010 that I'm using in a chicken coop to control heaters, door, etc. The coop is about 100 ft from the house, so the wifi isn't perfect, although I've had no issues with other wifi devices. ( I had an UNO wifi rev 2 running same basic program with Blynk before switching over to IOT cloud). It seems the device loses the wifi connection, doesn't reconnect, and remains Status: Offline.

Is there a method to determine if the device is continuing to attempt to reconnect or to force a reconnect attempt after a certain period of time?

/* 
  Sketch generated by the Arduino IoT Cloud Thing "Untitled 2"
  https://create.arduino.cc/cloud/things/0f446719-7f15-4072-ac35-98a9f9f24c1a 

  Arduino IoT Cloud Variables description

  The following variables are automatically generated and updated when changes are made to the Thing

  float f;
  float water_Temp;
  int motor_Timer;
  CloudTime currentTimeIOT;
  CloudTime sunriseIOT;
  CloudTime sunsetIOT;

  Variables which are marked as READ/WRITE in the Cloud Thing will also have functions
  which are called when their values are changed from the Dashboard.
  These functions are generated with the Thing and added at the end of this sketch.
*/

#include "thingProperties.h"
#include <WiFiNINA.h>
//#include "DHT.h"
#include <EduIntro.h>
#include <TimeLib.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <RTCZero.h>
///#include <time>
#include <sunset.h>

#define TIMEZONE    -6
#define LATITUDE    38.3970
#define LONGITUDE   -90.6412

RTCZero timeVar;

SunSet sunVar;

// pins:
//A0   - 
//A1   - 
//A2   - 
//A3   - 
//A4   - 
//A5   - 
//A6   -
//D0~  - none
//D1~  - none
//D2~  - water temp sensor
//D3~  - cold relay HIGH
//D4~  - 
//D5~  - humidity/temp sensor
//D6~  - 
//D7~  - 
//D8~  - 
//D9   - actuator relay
//D10~ - actuator relay
//D11  - actuator relay
//D12~ - actuator relay
//D13  - 
//D14  - 




////const int GMT = 2; //change this to adapt it to your time zone



//The type of DHT that is being used
#define DHTTYPE DHT11   // DHT 11
//Which pin the DHT output is connected to the Arduino
#define DHTPIN 5
//DHT dht(DHTPIN, DHTTYPE);
DHT11 dht11(D5);

// Data wire for the DS18B20 is plugged into port 2 on the Arduino
#define ONE_WIRE_BUS 2

// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);

// Pass our oneWire reference to Dallas Temperature. 
DallasTemperature sensors(&oneWire);


unsigned long currentMillis;
unsigned long previousMillis1 = 0;
unsigned long previousMillis2 = 0;
unsigned long previousMillis3 = 0;
unsigned long previousMillisMotor = 0;
const long intervalTime = (1000*30); //30 seconds
const long intervalTemp = (1000*40); //40 seconds
const long intervalDoor = (1000*45); //45 seconds
int intervalMotor = (1000*35); //35 seconds

bool DST = false;
int DSTOffset = 0;
//bool iced = false;

int opentime = (6*3600);
int closetime = (20*3600);
int currentTime;
//unsigned int currenttime = ArduinoCloud.getLocalTime();
int offsetCloseTime = (1000*30*60); // 30 minutes
double sunrise;
double sunset;
//float f;
float h;



int in1 = 11;
int in2 = 12;
int in3 = 3;

void setup() {
  // Initialize serial and wait for port to open:
  Serial.begin(9600);
  // This delay gives the chance to wait for a Serial Monitor without blocking if none is found
  delay(1500); 
  


  // Defined in thingProperties.h
  initProperties();

  // Connect to Arduino IoT Cloud
  ArduinoCloud.begin(ArduinoIoTPreferredConnection);
  
  /*
     The following function allows you to obtain more information
     related to the state of network and IoT Cloud connection and errors
     the higher number the more granular information you’ll get.
     The default is 0 (only errors).
     Maximum is 4
 */
  setDebugMessageLevel(2);
  ArduinoCloud.printDebugInfo();
  setSyncInterval(10 * 60); // Sync interval in seconds (10 minutes)

  
  pinMode(in3, OUTPUT);
  // Start up the temp probe library
  sensors.begin();

  dht11.update();
  
  timeVar.begin();
  //delay(5000);
  sunVar.setPosition(LATITUDE, LONGITUDE, TIMEZONE);
  DSTvoid();
  delay(1000);
  TimeCalcs();
  //send_sensor_DHT(); 
  //send_sensor_ICE();
  //door_status();
  
}

void loop() {
  ArduinoCloud.update();
  // Your code here 
  ///digitalWrite(LED_PIN, (millis().= % 2000) < 1000);
  currentMillis = millis();
  if (currentMillis - previousMillis1 >= intervalTime)
  {
    previousMillis1 = currentMillis;
    Serial.println("----------Time Calculations----------");
    DSTvoid();
    TimeCalcs();
  }
  if (currentMillis - previousMillis2 >= intervalTemp)
  {
    previousMillis2 = currentMillis;
    Serial.println("----------Sensor Data----------");
    send_sensor_DHT(); 
    send_sensor_ICE();
  }
  if (currentMillis - previousMillis3 >= intervalDoor)
  {
    previousMillis3 = currentMillis;
    Serial.println("----------Door Actions----------");
    door_status();
  }
}

void DSTvoid(){
  if (timeVar.getMonth() < 3)
  {
    DST = false;
    Serial.println("DST = FALSE");
    DSTOffset = 0;
  }
  if (timeVar.getMonth() >= 3 && timeVar.getMonth() <= 11)
  {
    if (timeVar.getDay() >= 0)
    {
      DST = true;
      Serial.println("DST = TRUE");
      DSTOffset = -1;
    }
  }
  if (timeVar.getMonth() >= 11)
  {
    if (timeVar.getDay() >= 8)
    {
      DST = false;
      Serial.println("DST = FALSE");
      DSTOffset = 0;
    }
  }
}

void door_status()
{
  //TimeCalcs();

    if (currentTime > sunrise)
    {
      if (currentTime < sunrise + (30 * 60))
      {
        door_open();
        Serial.println("Door open");
      }    
    }
    if (currentTime > sunset + offsetCloseTime)
    {
      door_close();
      Serial.println("Door closed");    
    }
}

void send_sensor_DHT()
{
  dht11.update();
  //Set the variable h to the value for humidity
  float h = dht11.readHumidity();
  // Read temperature as Fahrenheit (isFahrenheit = true)
  //Set the variable f to the value for temp
  f = dht11.readFahrenheit();
  //delay(1000);
  //float TempF = sensors.getTempFByIndex(0);
  //Perform a check if either h or f has no value
  if (isnan(h) || isnan(f)) 
  {
    Serial.println(F("Failed to read from DHT sensor!"));
    return;
  }
  //These would be used to send data to the serial window
  Serial.print("Hum: ");
  Serial.println(h);
  Serial.print("Temp: ");
  Serial.println(f);
}

void send_sensor_ICE()
{
  sensors.requestTemperatures(); // Send the command to get temperatures
  float temp_Water = sensors.getTempFByIndex(0);
  float TempF = temp_Water;
  water_Temp = TempF;
  Serial.print("Temp probe: ");
  Serial.print(TempF);
  Serial.println(" F");
  f = dht11.readFahrenheit();
    
  Serial.print("Outdoor Temp: ");
  Serial.println(f);
  if (f < 34.00)
  {
    ice();
  }
  if (f > 36.00)
  {
    ice_done();
  }
}

void ice()
{
  digitalWrite(in3, HIGH);
  Serial.println("Iced");

}

void ice_done()
{
  digitalWrite(in3, LOW);
  Serial.println("No Ice");

}

void motor_stop()
{
  digitalWrite(in1,LOW);
  digitalWrite(in2,LOW);
}

void door_open()
{
  pinMode(in1,OUTPUT);
  pinMode(in2,OUTPUT);
  digitalWrite(in1,HIGH);
  digitalWrite(in2,LOW);
  Serial.println("Door is opening");
  if (currentMillis - previousMillisMotor >= intervalMotor)
  {
    previousMillisMotor = currentMillis;
    //motor_stop();
  }
  Serial.println("Door open");
}

void door_close()
{
  pinMode(in1,OUTPUT);
  pinMode(in2,OUTPUT);

  digitalWrite(in1,LOW);
  digitalWrite(in2,HIGH);
  Serial.println("Door is closing");
  if (currentMillis - previousMillisMotor >= intervalMotor)
  {
    previousMillisMotor = currentMillis;
    //motor_stop();
  }

  Serial.println("Door closed");
}

void TimeCalcs()
{
    sunVar.setCurrentDate(timeVar.getYear(), timeVar.getMonth(), timeVar.getDay());
    sunVar.setTZOffset(TIMEZONE);
    sunrise = sunVar.calcSunrise()-(DSTOffset*60);
    sunriseIOT = (sunrise * 60);
    delay(500);
    sunset = sunVar.calcSunset()-(DSTOffset*60);
    sunsetIOT = (sunset * 60);
    Serial.println();
    Serial.print("Month: ");
    Serial.println(timeVar.getMonth());
    Serial.print("Day: ");
    Serial.println(timeVar.getDay());
    Serial.print("Hours: ");
    Serial.println(timeVar.getHours()-6-DSTOffset);
    Serial.print("Minutes: ");
    Serial.println(timeVar.getMinutes());
    Serial.print("Total Minutes: ");
    delay(500);
    currentTime = (timeVar.getHours()-6-DSTOffset) * 60 + timeVar.getMinutes();
    if (currentTime < 0)
    {
      currentTime = (24 + (timeVar.getHours()-6-DSTOffset)) * 60 + timeVar.getMinutes();
    }
    currentTimeIOT = ((currentTime)*60);
    Serial.println(currentTime);
    Serial.print("Sunrise: ");
    Serial.println(sunrise);
    Serial.print("Sunset: ");
    Serial.println(sunset);
}

So it's been 3 days and the device did reconnect. Obviously I've rather my devices not be offline for so long. Is there a method of checking connection and attempting reconnection within the code that I can add?

Just an update, but it's been 9 days after the device appeared online. It was online for only about 6 hours, and been offline ever since. Is there an expected signal strength that I should be seeing with the device so I can ensure that I have the appropriate wifi signal and that perhaps I may have a device issues???

Hi @Stang_shane what is the output of the serial monitor?

I use ESP32's and a running task to determine WiFi connected.

void MQTTkeepalive( void *pvParameters )
{
  sema_MQTT_KeepAlive   = xSemaphoreCreateBinary();
  xSemaphoreGive( sema_MQTT_KeepAlive ); // found keep alive can mess with a publish, stop keep alive during publish
  MQTTclient.setKeepAlive( 90 ); // setting keep alive to 90 seconds makes for a very reliable connection, must be set before the 1st connection is made.
  TickType_t xLastWakeTime = xTaskGetTickCount();
  const TickType_t xFrequency = 250; //delay for ms
  for (;;)
  {
    //check for a is-connected and if the WiFi 'thinks' its connected, found checking on both is more realible than just a single check
    if ( (wifiClient.connected()) && (WiFi.status() == WL_CONNECTED) )
    {
      xSemaphoreTake( sema_MQTT_KeepAlive, portMAX_DELAY ); // whiles MQTTlient.loop() is running no other mqtt operations should be in process
      MQTTclient.loop();
      xSemaphoreGive( sema_MQTT_KeepAlive );
    }
    else {
      log_i( "MQTT keep alive found MQTT status % s WiFi status % s", String(wifiClient.connected()), String(WiFi.status()) );
      if ( !(wifiClient.connected()) || !(WiFi.status() == WL_CONNECTED) )
      {
        connectToWiFi();
      }
      connectToMQTT();
    }
    //log_i( " high watermark % d",  uxTaskGetStackHighWaterMark( NULL ) );
    xLastWakeTime = xTaskGetTickCount();
    vTaskDelayUntil( &xLastWakeTime, xFrequency );
  }
  vTaskDelete ( NULL );
}

and here is my WiFi connection function,

void connectToWiFi()
{
  int TryCount = 0;
  while ( WiFi.status() != WL_CONNECTED )
  {
    TryCount++;
    WiFi.disconnect();
    WiFi.begin( SSID, PASSWORD );
    vTaskDelay( 4000 );
    if ( TryCount == 10 )
    {
      ESP.restart();
    }
  }
  WiFi.onEvent( WiFiEvent );
}

Not sure if the code will be of help.

Since this is outside, I don't have a comp hooked up in order to check the serial monitor. And the disconnect is so sporadic that I can't catch it at the right time. I suspect reading a few other connection issue threads that the Watchdog may be maxing the memory after trying to connect repeatedly. So, I may look at turning the Watchdog off for this application and create my own functions to reconnect periodically. I have another project that I'm working on that I'm attempting to create as a low power, deep sleep device, but have found that IoT Cloud doesn't work well with this method and I believe these two issues (repeated connection attempts and Watchdog memory as well as Watchdog and IoT Cloud compatibility) are related. Hopefully I can create a workaround until this is fixed on the IoT side.

Reference to a WTD thread:

Hi [Stang_shane]

I'm buikding a chicken coop too, with M5Stack (ESP32)
and I'm facing same issue, if it disconnect it does not reconnet, I can replicate easily, just removing the wifi poer supply
First of all I really like your code and the idea of using sunset and sunrise time , so you don't even need sensors (unless as double safety mechanism in case you loose the clock) I'm using same technique for a heliostat with little LED candle at sunset.

and I like also your simil scheduler with timeperiods for every action.

so how did you fix the reconnection?
can we stay in contact so we build a better chicken coop, I would then make a YT video on my small YT : "maker Fabio"
I hope I can find this thread again, I'm not good on kkeping track on forums
thanks
Fabio

Hey Fabio,

So far, I've been really disappointed with the IOT Cloud features, considering this connection issue and another project that needs deepsleep, which isn't compatible with IOT Cloud. So I removed it from this code.

I've moved back to using an UNO Rev 2 Wifi and the RTC, since I was using it previously with Blynk and had minimal connection issues. But now I basically have no IOT features in the code anymore. I've thought about adding a local network page back to it and have a portion of code that I've put together to add it back in, because I don't really need the IOT interactions, but the status indication is nice.

Glad you like the project, let me know if I can help (unless it's IOT Cloud related, lol).
Thanks.
Shane

I see
I also need deep sleep, i will try with complete iot startup procedure every time i wake up (i guess it will be every 10 minutes)
I will also check for azure and other iot options

Lets see. This IOT things, is in everyone mouth, like an easy and smooth thing, but is not as smooth as it looks.

Do you have any place where i can check your chicken coop and see how you build it?

A website or youtube channel?

My YT channel is “maker Fabio” mainly toys and repair things

Thanks
Fabio

A post was split to a new topic: Power saving for IoT device

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.