Restarting ESP32

Hello, I've got an ESP32 internet clock that often freezes/stops. I guess this happens because my ESP32 board fails to connect to WiFi. So, I'm thinking to add some code to reconnect to WiFi or restart the ESP32 after N seconds after it fails to connect.
I found an example but because I'm new to coding I can't get it work.

So, I was wondering if someone could point out what exactly needs to be added to my code to make it work. Thanks.

Here is my code:

#include <WiFi.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
#include <MD_Parola.h>
#include <MD_MAX72xx.h>
#include <SPI.h>
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
//#define HARDWARE_TYPE MD_MAX72XX::GENERIC_H
#define MAX_DEVICES 4
#define CLK_PIN   18 
#define DATA_PIN  23 
#define CS_PIN    5 
MD_Parola Display = MD_Parola(HARDWARE_TYPE, DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP);
const char* ssid     = "12345";
const char* password = "12345";
String Time, hour, minute;
String Formatted_date;
long currentMillis = 0;
long previousMillis = 0;
int interval = 1000;
void setup() {
  Serial.begin(115200);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print("Connecting.");
  }
  Serial.println("");
  Serial.println("WiFi connected.");
  timeClient.begin();
  timeClient.setTimeOffset(0);
  
  Display.begin();
  Display.setIntensity(2);
  Display.displayClear();
}
void loop()
 {
   obtainTime();
}
void obtainTime() {
  while(!timeClient.update()) {
    timeClient.forceUpdate();
  }
  currentMillis = millis();
  if (currentMillis - previousMillis > interval)  {
previousMillis = millis();
Formatted_date = timeClient.getFormattedDate();
Serial.println(Formatted_date);
hour = Formatted_date.substring(11, 13);
minute = Formatted_date.substring(14, 16);

Time = hour + ":" + minute;
Serial.println(Time);
Display.setTextAlignment(PA_CENTER);
Display.print(Time);
}
}  

I added a few strokes to my original code but not sure if it'll work the way I want.

#include <WiFi.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
#include <MD_Parola.h>
#include <MD_MAX72xx.h>
#include <SPI.h>
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
//#define HARDWARE_TYPE MD_MAX72XX::GENERIC_H
#define MAX_DEVICES 4
#define CLK_PIN   18 
#define DATA_PIN  23 
#define CS_PIN    5 
#define CONNECTION_TIMEOUT 10
MD_Parola Display = MD_Parola(HARDWARE_TYPE, DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP);
const char* ssid     = "12345";
const char* password = "12345";
String Time, hour, minute;
String Formatted_date;
long currentMillis = 0;
long previousMillis = 0;
int interval = 1000;
void setup() {
  Serial.begin(115200);
  WiFi.begin(ssid, password);
  Serial.println("\nConnecting");
    int timeout_counter = 0;

  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(500);
    timeout_counter++;
        if(timeout_counter >= CONNECTION_TIMEOUT*5){
        ESP.restart();
  }
  Serial.println("");
  Serial.println("WiFi connected.");
  timeClient.begin();
  timeClient.setTimeOffset(0);
  
  Display.begin();
  Display.setIntensity(2);
  Display.displayClear();
}
}

void loop()
 {
   obtainTime();
}
void obtainTime() {
  while(!timeClient.update()) {
    timeClient.forceUpdate();
  }
  currentMillis = millis();
  if (currentMillis - previousMillis > interval)  {
previousMillis = millis();
Formatted_date = timeClient.getFormattedDate();
Serial.println(Formatted_date);
hour = Formatted_date.substring(11, 13);
minute = Formatted_date.substring(14, 16);

Time = hour + ":" + minute;
Serial.println(Time);
Display.setTextAlignment(PA_CENTER);
Display.print(Time);
}
}  

I think the reason you are getting stuck is because you are trying to update the client to often.

1 Like

May I ask what number do you suggest? How often can I update it without affecting my connectivity? Thanks

You don't need to update the NTP time very often at all, the ESP should/will keep track of it by itself. Updating once a minute or once an hour is all good. Updating it too often will cause the server to kick you out. All you need to make sure is that it has updated once before it will start putting out the correct time. My system is so different from yours, that i can't really make time to modify yours to your need.

move this

while(!timeClient.update()) {
    timeClient.forceUpdate();
  }

to setup()
and see how the works for you first.

2 Likes

Got it, thanks. I'll give it a try.

a lot of WiFi-routers can be used as the NTP-time-server.
here is a demo-code
The code defines a constant with the name of the router.
In my case the WLAN-router is a AVM Fritz!Box hence the local url "fritz.box"

const char* ntpServer = "fritz.box";

If you don't know the local url-name of your WLAN-router use the IP-adress of your WLAN-router.

example

const char* ntpServer = "192.168.1.1";
/* Example Demo-Code for ESP8266 and ESP32
  Showing how to
  - organise code well structured into functions
  - connecting to a WiFi
  - synchronise time with an NTP-server
  - if connecting fails how to scan and print available WiFi-networks
  - how to use minuteOfDay and secondOfDay which make it easier to compare
  - the actual time with a certain point of time
  - non-blocking timing based on function millis() with a helper-function
  - how to print a timestamp when the code was compiled
  written by user StefanL38
*/

#if defined(ESP32)
#include <WiFi.h>
char deviceType[] = "ESP32";
#else
#include <ESP8266WiFi.h>
char deviceType[] = "ESP8266";
#endif

unsigned long MyTestTimer = 0;                   // variables MUST be of type unsigned long
const byte    OnBoard_LED = 2;
int connectCounter = 0;
int NoOfWiFis;
long minuteOfDay;
long secondOfDay;

const   char *ssid     = "your SSID";
const char *password = "your password";

const char dayOfWeek[][16] = {"sunday",
                              "monday",
                              "tuesday",
                              "wednesday",
                              "thursday",
                              "friday",
                              "saturday"
                             };

// a lot of home-wlan-routers can be used as a NTP-server too
const char* ntpServer = "fritz.box";
const long  gmtOffset_sec = 0;
const int   daylightOffset_sec = 7200;

#include <time.h>                   // time() ctime()
time_t now;                         // this is the epoch
tm myTimeInfo;                      // the structure tm holds time information in a more convient way
int Year;
int Month;
int Day;
int Hour;
int Minute;
int Second;
int DayIndex;


void updateMyTimeVars() {
 Year   = myTimeInfo.tm_year + 1900; // years since 1900
 Month  = myTimeInfo.tm_mon + 1;     // January = 0 (!)
 Day    = myTimeInfo.tm_mday;
 Hour   = myTimeInfo.tm_hour;
 Minute = myTimeInfo.tm_min;
 Second = myTimeInfo.tm_sec; 
 DayIndex = myTimeInfo.tm_wday;
}


void clearSerialMonitor() {
  for (int i = 0; i < 50; i++) {
    Serial.println();  // print 50 empty lines
  }
}


void showTime() {
  time(&now);                       // read the current time
  localtime_r(&now, &myTimeInfo);   // update the structure tm with the current time
  updateMyTimeVars();
    
  Serial.print("year:");
  Serial.print(Year);  

  Serial.print(" month:");
  if (Month < 10) {
    Serial.print("0");
  }
  Serial.print(Month);      

  Serial.print(" day:");
  if (Day < 10) {
    Serial.print("0");
  }
  Serial.print(Day);         // day of month

  Serial.print(" hour:");
  if (Hour < 10) {
    Serial.print("0");
  }
  Serial.print(Hour);         // hours since midnight  0-23

  Serial.print(" min:");
  if (Minute < 10) {
    Serial.print("0");
  }
  Serial.print(Minute);          // minutes after the hour  0-59

  Serial.print(" sec:");
  if (Second < 10) {
    Serial.print("0");
  }
  Serial.print(Second);          // seconds after the minute  0-61*
  Serial.print(" DayIndex:");

  Serial.print(DayIndex);         // days since Sunday 0-6

  Serial.print(" name of day ");
  Serial.print(dayOfWeek[DayIndex]);

  minuteOfDay = Hour *   60 + Minute;
  secondOfDay = Hour * 3600 + Minute * 60 + Second;
  Serial.println();
  Serial.println();

  Serial.print("minuteOfDay ");
  Serial.print(minuteOfDay);

  Serial.print(" secondOfDay ");
  Serial.print(secondOfDay);

  //                 12 hours    4 minutes  59 seconds = 12:04:59
  if (secondOfDay < (12 * 3600 + 4 * 60   + 59) ) {
    Serial.println(" actual time is before 12:04:59");
  }
  else {
    Serial.println(" actual time is AFTER 12:04:59");
  }
  Serial.println();
  Serial.println();
}


void connectToWifi() {
  Serial.print("try connecting to ");
  Serial.println(ssid);

  WiFi.persistent(false);
  WiFi.mode(WIFI_STA);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    yield(); // very important to have this function call to enable backround-processes
    BlinkHeartBeatLED(OnBoard_LED, 333);

    if ( TimePeriodIsOver(MyTestTimer, 500) ) {
      Serial.print(".");
      connectCounter++;
      if (connectCounter % 20 == 0) {
        Serial.println();
      }
    }

    if (connectCounter > 120) {
      break;
    }
  }

  if (WiFi.status() == WL_CONNECTED) {
    Serial.print("\n connected.");
    Serial.println(WiFi.localIP() );
  }
  else {
    Serial.print("\n unable to connect to WiFi with name #");
    Serial.print(ssid);
    Serial.println("#");
    ScanWiFis();
    Serial.print("\n code stopped with while(true) yield() ");
    while (true) {
      yield();
    }
  }
}

void ScanWiFis() {
  int WiFiIdx;

  Serial.println("Startscanning for networks");
  NoOfWiFis = WiFi.scanNetworks();
  Serial.println("scanning done List of SSIDs");
  Serial.print("found number of networks ");
  Serial.println(NoOfWiFis);

  for (WiFiIdx = 0; WiFiIdx < NoOfWiFis; WiFiIdx++) {
    // Print SSID and RSSI for each network found
    Serial.print(WiFiIdx);
    Serial.print(" #");
    Serial.print( String( WiFi.SSID(WiFiIdx) ) );
    Serial.print("# RSSI ");
    Serial.print( String (WiFi.RSSI(WiFiIdx)) );
    Serial.print(" dB");
    Serial.println();
  }
}


void synchroniseWith_NTP_Time() {
  Serial.print("configTime uses ntpServer ");
  Serial.println(ntpServer);
  configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
  Serial.print("synchronising time");

  while (myTimeInfo.tm_year + 1900 < 2000 ) {
    time(&now);                       // read the current time
    localtime_r(&now, &myTimeInfo);
    BlinkHeartBeatLED(OnBoard_LED, 100);
    delay(100);
    Serial.print(".");
  }
  Serial.print("\n time synchronsized \n");
  showTime();
}


void PrintFileNameDateTime() {
  Serial.println( F("Code running comes from file ") );
  Serial.println(__FILE__);
  Serial.print( F("  compiled ") );
  Serial.print(__DATE__);
  Serial.print( F(" ") );
  Serial.println(__TIME__);
}

boolean TimePeriodIsOver (unsigned long & periodStartTime, unsigned long TimePeriod) {
  unsigned long currentMillis  = millis();
  if ( currentMillis - periodStartTime >= TimePeriod )
  {
    periodStartTime = currentMillis; // set new expireTime
    return true;                // more time than TimePeriod) has elapsed since last time if-condition was true
  }
  else return false;            // not expired
}


void BlinkHeartBeatLED(int IO_Pin, int BlinkPeriod) {
  static unsigned long MyBlinkTimer;
  pinMode(IO_Pin, OUTPUT);

  if ( TimePeriodIsOver(MyBlinkTimer, BlinkPeriod) ) {
    digitalWrite(IO_Pin, !digitalRead(IO_Pin) );
  }
}


void setup() {
  Serial.begin(115200);
  delay(2000);
  Serial.println("\n Setup-Start \n");
  PrintFileNameDateTime();

  connectToWifi();
  synchroniseWith_NTP_Time();
}

void loop() {
  BlinkHeartBeatLED(OnBoard_LED, 100);

  if ( TimePeriodIsOver(MyTestTimer, 1000) ) {
    showTime();
  }
}

best regards Stefan

1 Like

Thanks a lot, Stefan! Didn't know that and I'll definitely try it as well.

As noted there's absolutely no need for handling the NTP synching yourself. ESP32 does that automatically in the background and you can set the synch interval (every hour is probably good) and the sync type ("smooth" assures that only small, slow adjustments are made and your time values will always be monotonic). ESP32 also has full support of for POSIX time functions, so you might as well use them to make your life easier.

The below code simply connects to WiFi, synchs to NTP, then prints the time every second. If interested, I can also post a more sophisticated code the resynchs to NTP should the WiFi connection be lost and then reacquired. I've also attached a TZ.h file that lets you use more readable names instead of the rather cryptic POSIX time zone strings (you can also find them with a Google search).

#include "Arduino.h"
#include <WiFi.h>
#include "esp_sntp.h"
#include "TZ.h"

void setup() {
  const char ssid[] = "XXXXX";
  const char password[] = "XXXXX";
  uint8_t retryTest = 0;
  tm *timeinfo;
  const char ntpServer1[] = "time.nist.gov";
  const char ntpServer2[] = "pool.ntp.org";
  const uint32_t syncInterval = 3600UL * 1000;
  uint8_t attemptsBeforeReset = 5;
  timeval tv;
  time_t now;

  Serial.begin(115200);
  delay(4000);
  Serial.println("Starting");

  Serial.printf("Station MAC Address: %s\n", WiFi.macAddress().c_str());
  Serial.printf("Connecting to %s\n", ssid);

  while (WiFi.status() != WL_CONNECTED) {
    if (retryTest == 0) {
      WiFi.disconnect();
      WiFi.begin(ssid, password);
      retryTest = 5;
    } else {
      Serial.print(".");
      retryTest--;
      delay(1000);
    }
  }
  Serial.println();

  sntp_set_sync_mode(SNTP_SYNC_MODE_IMMED);  // Set for immediate synch on WiFi connect
  sntp_set_sync_interval(syncInterval);
  configTzTime(TZ_America_New_York, ntpServer1, ntpServer2);

  retryTest = 0;
  while (true) { // Wait for NTP sync to take effect
    if (retryTest == 0) {
      if ((--attemptsBeforeReset) == 0) {
        ESP.restart();
      }
      Serial.println("Synching Time to NTP Server");
      sntp_sync_time(&tv);
      retryTest = 10;
    } else {
      Serial.print(".");
      retryTest--;
    }
    delay(2000);
    now = time(nullptr);
    timeinfo = localtime(&now);
    if (timeinfo->tm_year >= (2022 - 1900)) {
      break;
    }
  }
  Serial.println();

  sntp_set_sync_mode(SNTP_SYNC_MODE_SMOOTH);  // Switch to smooth synch

  timeinfo = gmtime(&now);
  Serial.println("UTC Info:");
  Serial.printf("Year = %d, Mon = %d, Day = %d\n", timeinfo->tm_year, timeinfo->tm_mon, timeinfo->tm_mday);
  Serial.printf("Hour = %d, Min = %d, Sec = %d\n", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec);
  Serial.printf("DoY = %d, DoW = %d, IsDST = %d\n", timeinfo->tm_yday, timeinfo->tm_wday, timeinfo->tm_isdst);
  Serial.printf("TZ = %s\n", getenv("TZ"));
}

void loop() {
  const TickType_t delayTime = 1000;
  char timeString[100];
  time_t now;
  tm *timeinfo;

  now = time(nullptr);
  timeinfo = localtime(&now);
  strftime(timeString, 100, "Local Time: %A, %B %d %Y %H:%M:%S %Z", timeinfo);
  Serial.println(timeString);
  delay(delayTime);
}

TZ.h (22.2 KB)

1 Like

Thank you. This is very helpful.

You must use some older version of the parola-library If I try to compile I get this error

F:\myData\Arduino\libraries\MD_Parola\src\MD_Parola.cpp: In member function 'bool MD_Parola::begin(uint8_t)':

F:\myData\Arduino\libraries\MD_Parola\src\MD_Parola.cpp:43:21: error: void value not ignored as it ought to be

   bool b = _D.begin();    // method return status

anyway here is a modified code that shows how the changing between time / and DHT can be done

#include <WiFi.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
#include <MD_Parola.h>
#include <MD_MAX72xx.h>
#include <SPI.h>
#include <DHT.h>
#define DHTPIN 1
#define DHTTYPE DHT11   // DHT 11
DHT dht(DHTPIN, DHTTYPE);
float h;
float t;
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
//#define HARDWARE_TYPE MD_MAX72XX::GENERIC_H
#define MAX_DEVICES 4
#define CLK_PIN   18
#define DATA_PIN  23
#define CS_PIN    5
MD_Parola Display = MD_Parola(HARDWARE_TYPE, DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP);
const char* ssid     = "12345";
const char* password = "12345";
String Time, hour, minute;
String Formatted_date;

int interval = 1000;

unsigned long updateTimer;
unsigned long changeDisplayTimer;
unsigned long changeDisplayPeriod = 3000;
boolean printTime = true;


void setup() {
  Serial.begin(115200);
  WiFi.begin(ssid, password);
  
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print("Connecting.");
    
    while (!timeClient.update()) {
      timeClient.forceUpdate();
    }
  }

  Serial.println("");
  Serial.println("WiFi connected.");
  timeClient.begin();
  timeClient.setTimeOffset(0);

  //Display.begin();
  Display.begin(4);
  Display.setIntensity(0);
  Display.displayClear();
  dht.begin();
}


void loop() {

  // check if more time than stored in variable "changeDisplayPeriod"
  // has passed by since last time this period was over
  if ( TimePeriodIsOver(changeDisplayTimer, changeDisplayPeriod) ) {
    // if more time REALLY has passed by
    printTime = !printTime; // invert the value of flag "printTime"
  }

  if (printTime == true) {
    obtainTime();
  }
  else { // which means printTime == false)
    printHumTEmp();
  }
}


void obtainTime() {

  if ( TimePeriodIsOver(updateTimer, 1000) ) {
  Formatted_date = "does not work";//timeClient.getFormattedDate();
    Serial.println(Formatted_date);
    hour = Formatted_date.substring(11, 13);
    minute = Formatted_date.substring(14, 16);

    Time = hour + ":" + minute;
    Serial.println(Time);
    Display.setTextAlignment(PA_CENTER);
    Display.print(Time);
  }
}


void printHumTEmp() {
  if ( TimePeriodIsOver(updateTimer, 1000) ) {
    // your code reading in
    // and printing humidity and temperature
  }
}


// easy to use helper-function for non-blocking timing
boolean TimePeriodIsOver (unsigned long &startOfPeriod, unsigned long TimePeriod) {
  unsigned long currentMillis  = millis();
  if ( currentMillis - startOfPeriod >= TimePeriod ) {
    // more time than TimePeriod has elapsed since last time if-condition was true
    startOfPeriod = currentMillis; // a new period starts right here so set new starttime
    return true;
  }
  else return false;            // actual TimePeriod is NOT yet over
}

best regards Stefan

1 Like

Thank you very much Stefan. I've tried this sketch but unfortunately it didn't work. My display only shows two letters "rk". There were no errors at all.

start thinking on your own again
What do you think do you have to change in this line of code to make it work?

and inside here

void printHumTEmp() {
  if ( TimePeriodIsOver(updateTimer, 1000) ) {
    // your code reading in
    // and printing humidity and temperature
  }
}

what do you think do you have to add?
best regards Stefan

2 Likes

Thanks for getting back to me Stefan.

I guess it should be Time, not Date.

Formatted_date = "does not work";//timeClient.getFormattedTime();

As for the rest two I'm not quite sure what to add to make the code work ...

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