Getting Time from NTP service using NODEMCU 1.0 (ESP- 12E)

Hello,

I am using a NodeMCU (ESP 12-E) to connect to the internet to get date from the NTP service. I have written the following code:

#include<ESP8266WiFi.h>
#include<time.h>


const char *ssid = "myNetwork"; 
const char *password = "thepasswordtomynetwork"; 

time_t setupTime ()
{
  configTime(5*3600, 0, "pool.ntp.org");
  while(!time(nullptr))
  {
    Serial.println("*");
    delay(500);  
  }

}
void setup() {
  Serial.begin(115200); 

  WiFi.begin(ssid,password); 
  while(WiFi.status() != WL_CONNECTED)
  {
    Serial.print("."); 
    delay(500); 
  }

  Serial.print("Connected to "); Serial.println(ssid); 
  Serial.print("IP Address: "); Serial.println(WiFi.localIP()); 

  setupTime();

  
}

void loop() {

  time_t rawtime; 
  struct tm* timeinfo; 
  time(&rawtime); 

  timeinfo = localtime(&rawtime); 
  char buffer[80];

  strftime(buffer, 80, "%Y%m%d",timeinfo); 

  Serial.println(buffer);
  delay (1000); 
}

I have not defined a Sync Interval for the NTP service. My question is "At what frequency is this code accessing the NTP service i.e. pool.ntp.org?
I would like to call the NTP service only once a day when the day changes and i am worried about over querying the NTP service and getting black listed.
Any help in this regard is much appreciated. Thanks

configTime(5*3600, 0, "pool.ntp.org");

A quick Google for "configTime" tells me that this is in seconds.
That works out to 5 hours.
You could even reduce that to 1*3600 (one hour).
Leo..

The 5 * 3600 bit of the code refers to timezone settings and the next 0 refers to DST. When the time(nullptr) or time(&rawtime) is used in void loop(), the sync to external time should happen at a certain frequency that may be default of the time.h library or should be defined by the setSyncInterval.

I cant find the default in the time.h or the time.cpp and I haven't defined the setSyncInterval, That is why I am looking for the frequency at which external time is being called in this code.

Thanks for the help

This line in Time.cpp means the deafult is 5 minutes (300 seconds)

static uint32_t syncInterval = 300;  // time sync will be attempted after this many seconds

The number is uint32_t so you can set the interval up to 4.2 billion seconds (about 136 years).

This example says it is one hour.

It is based on the ESP’s native SNTP code base and is intended to show that configTime(), using the new named posix named time zone argument signature, can convert a UTC time, such as delivered by a NTP server, to a local time, even before contact with the NTP server is made, which is useful if you also use a real time clock running in UTC.

Anyway, that example implies that the default interval between fetches of the time from the NTP server is 60 minutes. You can alter this if required using a supplied function: uint32_t sntp_update_delay_MS_rfc_not_less_than_15000 (). That fetched time is available immediately via functions such as gettimeofday(), time() etc. The Arduino library TimeLib.h is not used here, only the standard C++ time.h library.

Do not use this form of configTime()

 configTime(tzoffset, dstflg, "ntp-server1", "ntp-server2", "ntp-server3");

If you do, lots of things will not work correctly, since this offset stuff is not how timezone offsets really work, and they have bugs in their library code that attempts to try and do it that way. It is done in the NTP code and not the time library so it also breaks all the gnu time library functions you will be using.

You must use set a TZ string for the gnu time functions to work.
Once you do you will get automatic DST or summertime offset adjustments.
You can use the other form of configTime() to easily do this.

configTime (TZstr, "ntp-server1");

The latest ESP8266 platform includes an updated NTP example sketch that I was involved with when trying get them to fix this offset issue stuff.
It is called NTP-TZ-DST that provides a working example.
Again, don't use the configTime() with the offset as it will not work properly and does not work with the gnu time library functions you will be using.

Also here is a working sample sketch I wrote that you can look at that includes comments about how to use the API functions.

/* vi:ts=4
 *
 * Example shows how to use a TZ timezone string for local time timezone & DST
 * local time works with/without an RTC and/or with/without NTP
 * i.e. RTC only, NTP only or RTC and NTP
 * If using WiFi and NTP, Configure your WiFi paramters
 * Configure your your timezone TZ string
 *
 * If using only an RTC, then you won't need to set up NTP
 * If using only NTP, you won't need to set the system time from the RTC
 *
 * NOTE: true time_t values are ALWAYS ALWAYS ALWAYS
 *       the seconds since 1970-01-01 00:00:00 UTC
 *       and local timezone or DST has absolutely no effect on a time_t value
 *
 * WARNING:
 *	At the time this example was written,
 *  the ESP8266 time_t value a signed 32 bit value. That means that the esp8266
 *  time functions will suffer from the the Y2K38 problem:
 *  https://en.wikipedia.org/wiki/Year_2038_problem
 *  This means that the esp8266 time library code will malfunction starting:
 *  03:14:07 on Tuesday, 19 January 2038 GMT
 *
 * Recommended use:
 *	Bring up Serial monitor at 115200 *before* uploading
 *	Upload code and observe results
 *
 * Code is realeased to the public domain
 * 2020-10-03 Bill Perry
*/

#include <ESP8266WiFi.h>
#include <time.h>		// time() ctime()
#include <sys/time.h>		// struct timeval
#include <coredecls.h>		// settimeofday_cb()


////////////////////////////////////////////////////////

//
// WiFi setup
//

#define SSID            "yourSSID"
#define SSIDPWD         "yourPassword"

// TZ string setup
// TZ string information:
// https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html
const char *TZstr = "CST+6CDT,M3.2.0/2,M11.1.0/2";

////////////////////////////////////////////////////////

// callback function that is called whenever time is set
// When using NTP, It is called just *after* time is set by NTP
// This callback is optional and can be used to trigger things when time is set
// It is called each time NTP syncs the time.
// It could potentially be used to update/set an RTC when NTP sets the time
// NOTE:
// 	Keep in mind that the callback is called whenever settimeofday() is called.
//  So make sure to take that into account if calling settimeofday()



timeval cbtime;			// when time set callback was called
bool cbtime_set = false;

void time_is_set (void)
{
	time_t t = time (nullptr);

	gettimeofday (&cbtime, NULL);
	cbtime_set = true;
	Serial.println
		("------------------ settimeofday() was called ------------------");
	printf (" local asctime: %s\n",
	 asctime (localtime (&t)));	// print formated local time

	// set RTC using t if desired
}

void setup ()
{
	Serial.begin (115200);

	// optional: set function to call when time is set
	// is called by NTP code when NTP is used and NTP sets the time
	// it is called just *after* NTP sets the time
	settimeofday_cb (time_is_set);

///////////////// Setting Time from RTC ///////////////////////////////////////
	// If not using an RTC, this section can be deleted
	// set time from RTC
	// Normally you would read the RTC to get a current time_t value.
	// NOTE:
	//		true time_t values are ALWAYS ALWAYS ALWAYS
	//		the seconds since 1970-01-01 00:00:00 UTC
	//		and local timezone or DST has absolutely no effect on a time_t value
	//
	// this is faked for now.
	time_t rtc_time_t = 946684800;	// fake RTC time:  2000-01-01 00:00:00 GMT

	timeval tv = { rtc_time_t, 0 };

	// set the time of day and explicitly set the timezone offsets to zero
	// as there appears to be a default offset compiled in that needs to
	// be set to zero to disable it.
	// NOTE: normally, the second paramter of 
	// settimeofday(const struct timeval *tv, const struct timezone *tz)
	// should be a timezone struct pointer.
	// but there is some kind of bug that if you use it, the TZ environment
	// variable stuff breaks. So set the timezone parameter to NULL.
	settimeofday (&tv, NULL); // this triggers a call to the settimeofday cb
///////////////////////////////////////////////////////////////////////////////

///////////////// Syncing Time Using NTP //////////////////////////////////////
	// If not using NTP This section can be deleted
	// DO NOT attempt to use the timezone offsets in configTime() !!!!!
	// configTime(tzoffset, dstflg, "ntp-server1", "ntp-server2", "ntp-server3");
	// The timezone offset code is really broken.
	// if used, then localtime() and gmtime() won't work correctly.
	// set both to zero and get real timezone & DST support by using TZ string
	// enable NTP by setting NTP server
	// up to 3 ntp servers can be specified
	// configTime(0, 0, "server1", "server2", "server3");

	// enable NTP by setting up NTP server(s)
	// up to 3 ntp servers can be specified
	// set both timezone offet and dst parameters to zero 
	// and get real timezone & DST support by using a TZ string
	// If not using a network, or NTP, don't use configTime()
	configTime (TZstr, "pool.ntp.org");
///////////////////////////////////////////////////////////////////////////////

///////////////// Configure Local timezone ////////////////////////////////////
	// this must always be done.
	// set up TZ string to use a POSIX/gnu TZ string for local timezone
	// TZ string information:
	// https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html
//	setenv ("TZ", TZstr, 1);

//	tzset ();		// save the TZ variable
///////////////////////////////////////////////////////////////////////////////

///////////////// Start up WiFi network ///////////////////////////////////////
	// If not using NTP or a networking this section can be removed.
	// turn on WIFI using SSID/SSIDPWD
	WiFi.mode (WIFI_STA);
	WiFi.begin (SSID, SSIDPWD);
///////////////////////////////////////////////////////////////////////////////

	// don't wait, observe time changing when ntp timestamp is received

	Serial.println ();
}

// for testing purpose:
extern "C" int clock_gettime (clockid_t unused, struct timespec *tp);
#define PTM(w) \
  Serial.print(":" #w "="); \
  Serial.print(tm->tm_##w);

void printTm (const char* what, const tm* tm)
{
  Serial.print(what);
  PTM(isdst); PTM(yday); PTM(wday);
  PTM(year);  PTM(mon);  PTM(mday);
  PTM(hour);  PTM(min);  PTM(sec);
}


timeval tv;
struct timezone tz;
timespec tp;
time_t tnow;

void loop ()
{
#if 0
	if(!cbtime_set)		// don't do anything until NTP has set time
		return;
#endif

	gettimeofday (&tv, &tz);
	clock_gettime (0, &tp);	// also supported by esp8266 code
	tnow = time (nullptr);

	// localtime / gmtime every second change
	static time_t lastv = 0;
	if(lastv != tv.tv_sec)
	{
		lastv = tv.tv_sec;
#if 1
		printf ("tz_minuteswest: %d, tz_dsttime: %d\n",
			tz.tz_minuteswest, tz.tz_dsttime);
		printf ("gettimeofday() tv.tv_sec : %ld\n", lastv);
		printf ("time()            time_t : %ld\n", tnow);
		Serial.println ();
#endif

		printf ("         ctime: %s", ctime (&tnow));	// print formated local time
		printf (" local asctime: %s", asctime (localtime (&tnow)));	// print formated local time
		printf ("gmtime asctime: %s", asctime (gmtime (&tnow)));	// print formated gm time

		// print gmtime and localtime tm members
		printTm ("      gmtime", gmtime (&tnow));
		Serial.println ();
		printTm ("   localtime", localtime (&tnow));
		Serial.println ();
		Serial.println ();
	}
	delay (100);
}

---- bill

1 Like

Thank you all for your help.

I am an occasional programmer and therefore it is sometimes hard for me to understand things that may be very simple to the experienced programmers.
I have following conclusions from my experience with getting a NodeMCU to get time from the NTP server.

  1. time.h is a standard C library not an arduino library
  2. TimeLib.h is an Arduino library also sometimes named as Time.h which makes it utterly confusing for noobs like myself.
  3. I used TimeLib.h to use functions like now(), setSyncInterval() and setSyncProvider().
  4. I used time.h, the standard C library to use functions like time(&rewTime), localtime(), strftime(),time(nullptr) and configTime() which to me are the simplest methods of getting UTC from NTP server without having to use the UDP library and for formatting the output.
    The Code i have written is as follows:
#include<ESP8266WiFi.h>
#include<time.h>
#include<TimeLib.h>


const char * SSID = "mySSID"; 
const char * Password = "MyPassword"; 

void connectToWiFi()
{
  WiFi.begin(SSID, Password); 
  while(WiFi.status() != WL_CONNECTED)
  {
    Serial.print(".");
    delay(500); 
  }

  Serial.println ("Connected ..."); 
  Serial.print("IP Address: ");
  Serial.println(WiFi.localIP()); 
}



time_t NTPTime()
{
  time_t currentTime; 
  while (time(&currentTime) < 1617460172) // some time as on 03.04.2021
{

  Serial.println("I Am Time");// to see how many times the while loop gets repeated before getting the timezone corrected time
  delay(100);
}
  Serial.println ("the time was synced from external source");

   return currentTime; 
  
}
time_t rawtime; 

void setup()
{

  Serial.begin(115200);
  connectToWiFi(); 
  configTime(5*3600, 0, "pool.ntp.org");
  delay(10); 

  setSyncProvider (NTPTime);
  setSyncInterval(60); // this syncs with the NTP server after every one minute
  
  
}

void loop()
{
 
  struct tm* timeinfo; 
  rawtime = now(); 
  //time(&rawtime);

  timeinfo = localtime(&rawtime); 
  char buffer[80];

  //strftime(buffer, 80, "%Y%m%d",timeinfo); 
  strftime(buffer, 80, "%r",timeinfo); 


  Serial.println(buffer);
  delay (1000); 
  
}

Like i said, i am an occasional programmer and a noob, so i would like if you could enlighten me with any problems that may be with this code.

again, thank you guys for your help and i look forward to your input on this.

... Usman

thehrao,

You are mixing two different time libraries in the same sketch.
time and TimeLib.

I would recommend against this.
There is no need for TimeLib on the esp platforms.

If you want to have the proper timezone offsets along with DST / summertime adjustments, then you should use the built in time library and the associated TZ string to configure the timezone information.
The TimeLib library has no notion of timezones or how to do DST modifications.

If you use the time library, there is no need for a syncprovider as the NTP updates happen in the background.

What you have done is to use a timezone offset capability in the ESP ntp code to seed a time_t value in the TimeLib library.
I would discourage this approach for several reasons.

  1. conflicts & collision of libraries
    While you may get something to compile and link, there can be some issues.
    One of them is with the data type time_t
    TimeLib defines this as a an unsigned value and time defines it as a signed value.
    If time is included before TimeLib then TimeLib will use the time definition to avoid a compilation conflict.
    However, while this can "work" it can also can create some issues depending on the time range.
    Where there will be issues is prior to 1970 and after 2038.

  2. the configTime() offset mucks with the actual time_t value.
    That is not how time_t values and timezones are supposed work.
    A time_t value represents an offset from a single point in time and a time_value should not should not be modified based on locality.
    local time zones are normally handled by offsetting the human broken down time values, when needed not by modifying the actual time_t

  3. using the configTime() offset breaks all the time library functions when offset is not zero
    If you attempt to use the offset capability, the broken down time values you get will be incorrect when using various time library functions.
    i.e. the offset capability provided by configTime() doesn't really work and shouldn't be used.

  4. What you have will not adjust for DST
    If you want DST offsets to work, then the simplest way to get there is to use the time library and avoid using TimeLib

There is quite a bit of confusion over how time_t values work and how local time values are generated from them.
Many people have a misunderstanding that you offset the time_t value to get the proper local time to show up, but in fact that isn't how it is supposed to be done.
The time_t should never be modified since it reflects a specific point in time. i.e. the time_t value is the same everywhere on earth at a given point in time, even though the local time is different in different places.

Where things get complicated/messy is when dealing with a library like TimeLib which has no notion of timezones or DST adjustments.
So many people will end up adjusting the time_t value to try to get TimeLib to output a local time that seems to represent their desired local time. And while that approach can generate local time values that do represent the desired local time, the modified time_t value no longer represents that point in time.

Another issue that comes up when using the TimeLib library, is that it does not support DST adjustments.
So while you can kind of make it work by munging up the time_t value it still won't adjust for DST time changes.
Some people will toss in yet another library like TimeZone to muck with time_t values to account for DST changes.
While it can be done, again, it is modifying the time_t values which isn't really how it should be done.
This hack can work, if all you are doing is display the local time and are not ever storing the time_t values as timestamps to use later.
If using time_t values as timestamps, then this type of time_t modification falls apart and cannot be used.

If you want to have a local time that "just works", the simplest way on the esp platform is to use the built in time library and set a TZ variable for your local timezone.
(The example sketch I provided shows how to do that)

Once you do that, everything "just works".
You can use all the standard time API functions that have existed for 50 years and the time is synchronized with an NTP server in the background.

--- bill

1 Like

The reason for mixing up two libraries is that I don't understand how the time.h library talks to the NTP and what is the frequency of the sync. By bringing in the TimeLib, i just want a bit of control over the call to the NTP service. If i was sure of it, i would use the first code i posted which uses only the time.h library.

I have tried looking for it but i have not been able to find how the time(nullptr) gets the UTC time. Neither have i been able to find an example that implements an NTP Time simply with time.h library or without using the UDP library.I would appreciate it if anyone can point in the right direction.

As far as Timezone offset is concerned, i agree that time_t value should not be altered and human broken down values should be tweeked to get the desired timezone offset.

thanks for your input. i really appreciate it.

... usman

The reason for mixing up two libraries is that I don't understand how the time.h library talks to the NTP and what is the frequency of the sync.

According to the the esp8266 NTP library example
the synch period is default at one hour, and can be changed by this function.

uint32_t sntp_update_delay_MS_rfc_not_less_than_15000 ()
{
     return 12 * 60 * 60 * 1000UL; // 12 hours
}

You only need to define this function and if it is available in your sketch the library will call them. You don't need to add them in the loop.

See NTP for the ESP8266 including day light saving Time (DST) without 3rd party library

thehrao:
The reason for mixing up two libraries is that I don't understand how the time.h library talks to the NTP and what is the frequency of the sync. By bringing in the TimeLib, i just want a bit of control over the call to the NTP service. If i was sure of it, i would use the first code i posted which uses only the time.h library.

But, in your second example in post #6, you are not adding any control over NTP and its syncing.
What you have added as a 2nd time library (TimeLib) that is getting its internal time set from a time_t value that is obtained from the esp8266 system supplied time library every 60 seconds.
i.e. this code

setSyncProvider (NTPTime);
  setSyncInterval(60); // this syncs with the NTP server after every one minute

Is likely not doing or setting up to do what you think it is doing or what you may be wanting to do.

The #6 example code tells TimeLib to call the sync provider function NTPTime() if it sees more than 60 seconds have passed since it last called the sync provider.
It does not happen in the background but will happen when TimeLib API functions like now() is called.
i.e. it NTPTime() will be called once a minute assuming calls are made to TimeLib API functions at least that often.

But the function NTPTime() has nothing to with NTP.
It is merely looking at the current time_t value value, sometimes printing a message, and then returning it.
It is not doing any NTP protocol nor causing the background NTP process to run or sync.

Here is a bit of background on how this works on the ESP8266.
Remember the ESP8266 has an OS on it and things can run in the background.
There is no RTC inside the ESP part.
When you call configTime() it starts up the NTP background NTP process.
The NTP code will periodically wake up and talk to an NTP server and update the time being tracked by the system.
i.e. the time_t value.
In between the NTP code running, the system will update the time_t value every second based on timer interrupts.
If the system timer interrupts were perfect, subsequent connections to the NTP server would not be necessary. But it isn't, and since it isn't, time would start drifting without constant corrections from getting time from an NTP server, and hence the current accurate time_t value.

time() simply returns the system time_t value.
That is all it does. It does not cause a sync with NTP, nor use any sort of RTC.
It just returns the current time_t value.

In terms of the actual code implementation. It seems to all work as long as you use the TZ variable to set the timezone information, and don't try to use the timezone offset stuff in configTime().
It seems to be a fairly complement time library API implementation.
However, the time & ntp code implementation on the ESP is a bit strange. It looks to me like it was done by someone unfamiliar with the time library and originally did the NTP code before they knew about the time library and its functions.
i.e. for some strange reason some of the functionality that should be in the time library is in the NTP code.
So, IMO, the code is a bit "ugly" under the hood as is isn't partitioned as well as it could/should be.

--- bill

after considering all of your inputs the following code seems right

#include<ESP8266WiFi.h>


//#define myTZ "PKT-5"
//#define dst 0

const char * SSID = "NetworkID"; 
const char * Password = "Password"; 

void connectToWiFi()
{
  WiFi.begin(SSID, Password); 
  while(WiFi.status() != WL_CONNECTED)
  {
    Serial.print(".");
    delay(500); 
  }

  Serial.println ("Connected ..."); 
  Serial.print("IP Address: ");
  Serial.println(WiFi.localIP()); 
}

//uint32_t sntp_update_delay_MS_rfc_not_less_than_15000 ()
//{
//    //info_sntp_update_delay_MS_rfc_not_less_than_15000_has_been_called = true;
//    return 60000 * 60; // 1 hour
//}


void setup()
{

  Serial.begin(115200);
  connectToWiFi(); 
  configTime(5*3600,0,"pool.ntp.org");
  //configTime(myTZ,"pool.ntp.org"); some how this doesnt work for me, i have no clue why

 
  while (time(nullptr) < 1617460172) // minimum valid epoch
{
  Serial.println("I Am Time");
  delay(100);
}
  
}


time_t rawtime; 

void loop()
{
 
  struct tm* timeinfo;  
  time(&rawtime);

  timeinfo = localtime(&rawtime); 
  char buffer[80];

  strftime(buffer, 80, "%Y%m%d %r",timeinfo); 
 

  Serial.println(buffer);
  delay (1000); 
  
}

As for the original problem of knowing how many times the NTP server is being accessed is being taken as 1 hour default purely on faith.
my sincerest thanks to everyone for their input. i learned a lot. thanks

I cannot stress enough that if you attempt to use the offset capability as you have done in configTime() you will have problems.
Not only will you not get DST adjustments, but your local times will be incorrect when using some of the time api functions.
It simply does not work properly and should not be used.
Look here if you want the gory details:

If you start using more of the time api functions, you will have problems.
In order for the time API functions to work properly, you need to setup your TZ variable.
I recommend using a POSIX/gnu TZ string rather than one of the cutsie helper macros as shown in the esp8266 time example that comes with the ESP8266 platform.

I have attached an example, again, that you can look at.
Yes it probably has some stuff in it that you may not want or need but you can look at it to see how to use the TZ string (there is even a web link to a page that explains the format in great detail), and how to use configTime() to get all the time API functions working properly.

Again, If you attempt to use the offset capability, you will have issues with various time API functions and I'd guess that you will likely be back asking why certain time functions return the incorrect time and how to get DST working.

--- bill

NTP-RTC-MinExample.ino (7.65 KB)

The example that you have included does not compile for me. it gives the following error:

invalid conversion from 'const char*' to 'long int' [-fpermissive]

The problem goes away when I compile the configTime() with the following offsets rather than the TZ strings.

configTime(5*3600, 0, "pool.ntp.org")

Can you guide how to resolve this error.

thehrao:
The example that you have included does not compile for me. it gives the following error:

invalid conversion from 'const char*' to 'long int' [-fpermissive]

The problem goes away when I compile the configTime() with the following offsets rather than the TZ strings.

configTime(5*3600, 0, "pool.ntp.org")

Can you guide how to resolve this error.

It compiles with no issues for me.

Are you using the latest ESP8266 platform code? version 2.7.4 ?
You need the latest version.

In order to help debug the issue
you will need to provide the sketch you are using and the full compiler output so we can see what the issue is.
Make sure you have turned on verbose compilation output and all compiler warnings in the IDE options.

--- bill

updating to latest version of ESP8266 Platform code fixed the error.

Thanks

And the code now works with the TZ string. here is the code
<#include<ESP8266WiFi.h>

const char * SSID = "";
const char * Password = "";
const char* TZstr = "PKT-5";

void connectToWiFi()
{
WiFi.begin(SSID, Password);
while(WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(500);
}

Serial.println ("Connected ...");
Serial.print("IP Address: ");
Serial.println(WiFi.localIP());
}

//uint32_t sntp_update_delay_MS_rfc_not_less_than_15000 ()
//{
// //info_sntp_update_delay_MS_rfc_not_less_than_15000_has_been_called = true;
// return 60000 * 60; // 1 hour
//}

void setup()
{

Serial.begin(115200);
connectToWiFi();
configTime(TZstr,"pool.ntp.org");

while (time(nullptr) < 1617460172) // minimum valid epoch
{
Serial.println("I Am Time");
delay(100);

}

pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, HIGH);

}

time_t rawtime;

void loop()
{

struct tm* timeinfo;
int min, prevMin = 0;
time(&rawtime);

timeinfo = localtime(&rawtime);
char buffer[80];
min = timeinfo->tm_min;
Serial.println(min);

if(min % 2)
{
Serial.println ("LED OFF");
}
else
{
Serial.println("LED On");
}
strftime(buffer, 80, "%Y%m%d %r",timeinfo);
// char ED[] = "^P013ED";
// strcat(ED, buffer);

Serial.println(buffer);
// Serial.println(ED);
delay (1000);

}/>

I'm very grateful with your answer. It helped and inspired me so much.
Please keep on with these answers. Lots of us really appreciate it .

Extremely useful information about NTP.
Thanks a lot !

@Blend3rman

This thread is about getting time from NTP service on a NodeMCU.
Several answers have pointed out, that this can be done without a separate UDP library, without functions to manually parse udp answers.

Your sketch on github retrieves NTP in a way I don't recommend any more.
See the examples provided in this thread how to retrieve NTP in a smart way on the NodeMCU.
See the IDE example ESP8266 / NTP-TZ-DST
See several examples in the www - for example my NTP-TZ-DST bare minimum

edit: quote restored.