ESP8266 NodeMCU NTP (Network Time Protocol) Clock

This tutorial demonstrate how to get NTP Network Time using ESP8266 NodeMCU? Getting network time is much simpler than adding external RTC Chip to ESP8266. Use of NTP with ESP8266 makes getting time simpler and accurate. Before we start we must know what is NTP and How to get NTP Time in ESP8266.

What is NTP?

The Network Time Protocol (NTP) is widely used to synchronize computer clocks in the Internet. NTP is intended to synchronize all participating computers to within a few milliseconds of Coordinated Universal Time (UTC).

What is NTP Server?

NTP uses the concepts of server and client. A server is a source of time information, and a client is a system that is attempting to synchronize its clock to a server.

What is NTP Port?

OpenNTPD also uses high-numbered source ports so if it is able to synchronize but ntpd is not, it is very probable that the incoming UDP port 123 is blocked. If you’re going to run ntpd , you need to fix your network/firewall/NAT so that ntpd can have full unrestricted access to UDP port 123 in both directions.

How NTP UDP Protocol Works?

for more details read RFC958

The NTP packets sent by the client to the server and the responses from the server to the client use a common format, as shown in Figure.

ntp udp packet format for ESP8266

The header fields of the NTP message are as follows:

LI Leap Indicator (2 bits)
This field indicates whether the last minute of the current day is to have a leap second applied. The field values follow:
0: No leap second adjustment
1: Last minute of the day has 61 seconds
2: Last minute of the day has 59 seconds
3: Clock is unsynchronized
VN NTP Version Number (3 bits) (current version is 4).
Mode NTP packet mode (3 bits)
The values of the Mode field follow:
0: Reserved
1: Symmetric active
2: Symmetric passive
3: Client
4: Server
5: Broadcast
6: NTP control message
7: Reserved for private use
Stratum Stratum level of the time source (8 bits)
The values of the Stratum field follow:
0: Unspecified or invalid
1: Primary server
2–15: Secondary server
16: Unsynchronized
17–255: Reserved
Poll Poll interval (8-bit signed integer)
The log2 value of the maximum interval between successive NTP messages, in seconds.
Precision Clock precision (8-bit signed integer)
The precision of the system clock, in log2 seconds.
Root Delay The total round-trip delay from the server to the primary reference sourced. The value is a 32-bit signed fixed-point number in units of seconds, with the fraction point between bits 15 and 16. This field is significant only in server messages.
Root Dispersion    The maximum error due to clock frequency tolerance. The value is a 32-bit signed fixed-point number in units of seconds, with the fraction point between bits 15 and 16. This field is significant only in server messages.
Reference Identifier For stratum 1 servers this value is a four-character ASCII code that describes the external reference source (refer to Figure 2). For secondary servers this value is the 32-bit IPv4 address of the synchronization source, or the first 32 bits of the Message Digest Algorithm 5 (MD5) hash of the IPv6 address of the synchronization source.
 packetBuffer[0] = 0b11100011; // LI, Version, Mode 
 packetBuffer[1] = 0; // Stratum, or type of clock 
 packetBuffer[2] = 6; // Polling Interval 
 packetBuffer[3] = 0xEC; // Peer Clock Precision 

 // 8 bytes of zero for Root Delay & Root Dispersion 
 packetBuffer[12] = 49; 
 packetBuffer[13] = 0x4E; 
 packetBuffer[14] = 49; 
 packetBuffer[15] = 52;

ESP8266 NodeMCU Program to get Network Time

Before uploading program make changes in WiFi Network settings and UTC Time Zone for your area.

/*
    ESP8266 NodeMCU NTP (Network Time Protocol) Example
    Hardware: NodeMCU
    Date: 2018
    
Zero to Hero : ESP8266
*/ #include <ESP8266WiFi.h> #include <WiFiUdp.h> char ssid[] = "circuits4you.com"; // your network SSID (name) char pass[] = "********"; // your network password //Your UTC Time Zone Differance India +5:30 char HH = 5; char MM = 30; unsigned int localPort = 2390; // local port to listen for UDP packets /* Don't hardwire the IP address or we won't get the benefits of the pool. * Lookup the IP address for the host name instead */ //IPAddress timeServer(129, 6, 15, 28); // time.nist.gov NTP server IPAddress timeServerIP; // time.nist.gov NTP server address const char* ntpServerName = "time.nist.gov"; const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets // A UDP instance to let us send and receive packets over UDP WiFiUDP udp; //======================================================================= // SETUP //======================================================================= void setup() { Serial.begin(115200); Serial.println(); Serial.println(); // We start by connecting to a WiFi network Serial.print("Connecting to "); Serial.println(ssid); WiFi.mode(WIFI_STA); WiFi.begin(ssid, pass); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); Serial.println("Starting UDP"); udp.begin(localPort); Serial.print("Local port: "); Serial.println(udp.localPort()); } //======================================================================= // send an NTP request to the time server at the given address //======================================================================= unsigned long sendNTPpacket(IPAddress& address) { Serial.println("sending NTP packet..."); // set all bytes in the buffer to 0 memset(packetBuffer, 0, NTP_PACKET_SIZE); // Initialize values needed to form NTP request // (see URL above for details on the packets) packetBuffer[0] = 0b11100011; // LI, Version, Mode packetBuffer[1] = 0; // Stratum, or type of clock packetBuffer[2] = 6; // Polling Interval packetBuffer[3] = 0xEC; // Peer Clock Precision // 8 bytes of zero for Root Delay & Root Dispersion packetBuffer[12] = 49; packetBuffer[13] = 0x4E; packetBuffer[14] = 49; packetBuffer[15] = 52; // all NTP fields have been given values, now // you can send a packet requesting a timestamp: udp.beginPacket(address, 123); //NTP requests are to port 123 udp.write(packetBuffer, NTP_PACKET_SIZE); udp.endPacket(); } //======================================================================= // LOOP //======================================================================= void loop() { char hours, minutes, seconds; //get a random server from the pool WiFi.hostByName(ntpServerName, timeServerIP); sendNTPpacket(timeServerIP); // send an NTP packet to a time server // wait to see if a reply is available delay(1000); int cb = udp.parsePacket(); if (!cb) { Serial.println("no packet yet"); } else { Serial.print("packet received, length="); Serial.println(cb); // We've received a packet, read the data from it udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer //the timestamp starts at byte 40 of the received packet and is four bytes, // or two words, long. First, esxtract the two words: unsigned long highWord = word(packetBuffer[40], packetBuffer[41]); unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]); // combine the four bytes (two words) into a long integer // this is NTP time (seconds since Jan 1 1900): unsigned long secsSince1900 = highWord << 16 | lowWord; Serial.print("Seconds since Jan 1 1900 = " ); Serial.println(secsSince1900); // now convert NTP time into everyday time: Serial.print("Unix time = "); // Unix time starts on Jan 1 1970. In seconds, that's 2208988800: const unsigned long seventyYears = 2208988800UL; // subtract seventy years: unsigned long epoch = secsSince1900 - seventyYears; // print Unix time: Serial.println(epoch); // print the hour, minute and second: minutes = ((epoch % 3600) / 60); minutes = minutes + MM; //Add UTC Time Zone hours = (epoch % 86400L) / 3600; if(minutes > 59) { hours = hours + HH + 1; //Add UTC Time Zone minutes = minutes - 60; } else { hours = hours + HH; } Serial.print("The UTC time is "); // UTC is the time at Greenwich Meridian (GMT) Serial.print(hours,DEC); // print the hour (86400 equals secs per day) Serial.print(':'); if ( minutes < 10 ) { // In the first 10 minutes of each hour, we'll want a leading '0' Serial.print('0'); } Serial.print(minutes,DEC); // print the minute (3600 equals secs per minute) Serial.print(':'); seconds = (epoch % 60); if ( seconds < 10 ) { // In the first 10 seconds of each minute, we'll want a leading '0' Serial.print('0'); } Serial.println(seconds,DEC); // print the second } // wait ten seconds before asking for the time again delay(10000); } //=======================================================================

Results

after uploading program open serial monitor.

ESP8266 NTP Time Clock
ESP8266 NTP Clock in Serial Monitor

This way we can get NTP Time in ESP8266.

 

Leave a Reply