Hi,
I want to simply put out some data in serial monitor in Arduino IDE 2.2.1 from my ESP32.
The project get date and time value from NTP-Server in my getTime() function:
This seems to me that some data gets truncated. In first row it should be 2023-11-16 and in third row it should be like 16:42:46 . In the second line I output the mDay variable just to be sure it is the correct value.
/* 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 long as the WiFi-connection is established the ESP32 keeps getting the time form the WiFi-connection.
pinging very often to NTP-servers has become a real problem because today there are billions of network-devices who want to do that.
That is the reason why I use my local WiFi-Router as the NTP-server.
The FritzBox-routers from manufacturer AVM are very versatile and very reliable devices with an outstanding WiFi-supply-perfomance.
I'm about to start developing something that needs timestamps often about every second, nothing faster. Would it make sense then to add an RTC and update the RTC when wifi is available in the event the RTC has skewed over time?
the default NTP interval is 1 hour.
the ESP will keep track of the time between each NTP polling interval. So each time you call for a new timestamp (something like time(&now)) will give you an updated timestamp - but that will not cause an NTP request to the NTP server.
If you loose WIFI connection, the internal time will continue to run - just there are no NTP updates any more (until you reconnect to WIFI).
Sounds like I don't need to implement a RTC if the assumption that wifi will always be available? (Except for power outages). Accuracy is not necessary while no wifi, I just want to make sure timestamps continue 'incrementing'.
Thanks, that's a nice example, but it doesn't solve my problem. I wasn't asking for useful methods to get the time from somewhere and synchronize it with my ESP32 system, I was presenting a problem with Serial.Println.
It doesn't matter where the data comes from, that's not the problem. The problem is that apparently a joined string of other strings cannot be transferred completely without further ado.
First of all, I made a mistake in my last post. I meant it is a string of concatenated strings, not integers. I edited the post immediately afterwards, perhaps there was a misunderstanding.
Even with c_str(); there is no improvement.
I now suspect that it is due to my IF-Else branching. I have built this in so that a preceding 0 is appended in the event that the date is less than 10, for example 9 becomes 09:
if you want to concantenate strings and not do pointer arithmetics (like you do with "0"+timeinfo.tm_mday which builds a pointer pointing timeinfo.tm_mday bytes further away in memory than the constant char pointer of "0" ) then take it one line at a time
On microcontrollers with small RAM the string-class can eat up all RAM over time and then your code can crash.
There is another library which does avoid this.
It is the SafeString-library.
The SafeString-library works this way
initially you declare a safeString-variable and define the maximum of characters that this variable can hold.
cSF(mySafeString,32);
Then you can assign any kind of variable in this way
Here is a demo-code with a function that stores timestamps
#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
#include <SafeString.h>
createSafeString(myDemo_SS, 32);
createSafeString(mySecondDemo_SS, 32);
#define MaxTimeStampLength 64
createSafeString(TimeStamp_SS, MaxTimeStampLength);
unsigned long myCounter;
//useful function for non-blocking timing
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
}
unsigned long MyTestTimer = 0; // variables MUST be of type unsigned long
const byte OnBoard_LED = 13; // Arduino-Uno Onboard-LED is IO-pin 13
void setup() {
Serial.begin(115200);
Serial.println( F("Setup-Start") );
myCounter = 0;
myDemo_SS = "Hello world!";
}
void loop() {
myCounter++;
// loop is running very fast counting up very fast
// but only once every 1234 milliseconds print
if ( TimePeriodIsOver(MyTestTimer,1234) ) {
mySecondDemo_SS = myDemo_SS; // assigning a SafeString to another SafeString
mySecondDemo_SS += " "; // append a SPACE
mySecondDemo_SS += myCounter; // append integer-number
Serial.println(mySecondDemo_SS);
StoreTimeStampIntoSS(TimeStamp_SS);
Serial.println(TimeStamp_SS);
Serial.println(TimeStamp_SS.c_str() );
}
}
void StoreTimeStampIntoSS(SafeString& p_RefToSS) {
time(&now); // read the current time
localtime_r(&now, &myTimeInfo); // update the structure tm with the current time
//p_RefToSS = " ";
p_RefToSS = myTimeInfo.tm_year + 1900;
p_RefToSS += ".";
if (myTimeInfo.tm_mon + 1 < 10) {
p_RefToSS += "0";
}
p_RefToSS += myTimeInfo.tm_mon + 1;
p_RefToSS += ".";
if (myTimeInfo.tm_mday < 10) {
p_RefToSS += "0";
}
p_RefToSS += myTimeInfo.tm_mday;
p_RefToSS += "; ";
if (myTimeInfo.tm_hour < 10) {
p_RefToSS += "0";
}
p_RefToSS += myTimeInfo.tm_hour;
p_RefToSS += ":";
if (myTimeInfo.tm_min < 10) {
p_RefToSS += "0";
}
p_RefToSS += myTimeInfo.tm_min;
p_RefToSS += ":";
if (myTimeInfo.tm_sec < 10) {
p_RefToSS += "0";
}
p_RefToSS += myTimeInfo.tm_sec;
}