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.
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.
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();
}
}
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).
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
}
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.