Arduino Time Sync from NTP Server using ESP8266 WiFi module

Time is the unit measuring our life. Every mechanism in the world of electronics and computers is based on time. Automation as a concept is defined by intelligent actions coordinated by time or in time. When talking about automation engineering, smart projects are driven by very precise triggers and calculations based on timing and synchronization. But how can we get the perfect time without manual adjusting? One way to accomplish that is by asking an NTP Server. In this article you will find everything about how to use ESP8266 as a time source for your Arduino projects without an RTC external module.

Using WiFi ESP8266 Arduino compatible module as a Real Time Source

What is NTP Server?

The NTP acronym stands for Network Time Protocol, a networking communication protocol for clock synchronization between network clients, operating since 1980’s. The NTP job is to synchronize all network participants to Coordinated Universal Time (UTC) within a few milliseconds. To accomplish this task it uses the “intersection algorithm”, an agreement algorithm invented by Keith Marlzullo to estimate accurate time from different noisy sources. NTP can maintain time with a precision under 50 milliseconds over the public Internet and under 5 milliseconds in a LAN environment. In a more friendly description I would say that a NTP is a client-server service that can be implemented by sending or receiving timestamps via UDP requests or by broadcasting / multicasting.

How can we use NTP Servers?

NTP implementations can be found in many applications. Your operating systems most probably get the time from a NTP server, time servers, databases, weather stations, brokerage and online market exchange applications also get benefits from NTP servers by requesting accurate time. In order to interrogate an NTP server your environment should be able to open an UDP connection on a local port and then send and receive UDP packages in the same network with the server. The packages received are containing multiple information like UNIX timestamp, accuracy, delay or timezone and many development environments are providing friendly methods to extract the data in a pretty objectual format.

How accurate is an NTP server?

Before knowing how accurate an NTP server can be you need to know its architecture. A NTP server is is a hierarchical, semi-layered system of levels of clocks. See below NTP strata levels:

There are many factors that can affect the accuracy of time synchronized by NTP. A visible influence can have the following:

Speed (latency) of the client internet connection.

Strata of the time server(s) chosen for synchronization.

Signal distance from the servers (including to and from orbiting satellites).

The quality and complexity of the software algorithm used.

Note: To have a better accuracy is recommended to choose servers that are physically close to your exit point (internet provider end point). This will lessen the chance that the signal is not routed up to a geostationary satellite. Public server examples:

Global; www.pool.ntp.org/zone/@

Asia; www.pool.ntp.org/zone/asia

Iran; www.pool.ntp.org/zone/ir

Typically, the URL will be something like x.asia.pool.ntp.org where x = 0,1,2 or 3.

Arduino code example for ESP8266 – NTP Server pooling

In order to get data from the NTP server we need to program the ESP module to be an UDP Client. I prefer to program the ESP8266 using the Arduino IDE, but the same result can be achieved with LUA code or via AT Commands. To accomplish that with Arduino, I used two available libraries: ESP8266WiFi.h and WiFiUdp.h. First library allow and manage WiFi connections while the second handle sending and receiving UDP packages. Both libraries are available after installing the ESP8266 board from board manager in the Arduino IDE.

Replace SSID and password with your home router WiFi credentials, replace the ntpServerName with the server you want to get time from and upload the following code to your ESP. You can point a direct IP address of the NTP Server but most likely you will loose the POOL benefits.

This code example was inspired from here. Open your Serial monitoring terminal and reset the ESP module. You should see a result like this:

In this example I used a global NTP server (time.nist.gov), but being from Europe it is not the best choice. For my projects I use an NTP Server which is closer to my physically location like in the following example:

const char* ntpServerName = "0.europe.pool.ntp.org";

To get the NTP that match your location go to www.pool.ntp.org and in the right sidebar click on your zone / continent to see a complete list:

Configuring ESP8266 as a Time source

There are several ways to use the ESP module as a time source, but we have to choose one with the best performance during the transaction, in order to reduce or eliminate the additional time. The fastest way, and the way I used in my projects, is to get the time from the ESP8266 via serial terminals. Another way is to setup a web server on the ESP and return the time via HTTP response on demand, but this is network dependent and requires a network connected project. Keep in mind that any delay created by the output transaction will directly affect the accuracy of the time returned.

In the following example we will connect the ESP8266 with a standard Arduino UNO R3 via Serial terminals, and setup the Arduino UNO internal RTC to synchronize with the NTP given time. To do that, we will have to use the SoftwareSerial library in order to emulate serial communication on the digital GPIOs 2 and 3 and reserve this line for listening the ESP module.

As you probably know from the previous tutorials, I strongly recommend you to use a solid external 3.3v power supply for ESP8266, but for the sake of demonstration we will use UNO’s 3.3v VCC. Before doing anything on your Arduino UNO, first we should cleanup the code we just uploaded on ESP8266.

Because the Arduino Time library gives us the possibility to synchronize the internal or external RTC only by passing the UNIX time parameter, we wont need the other Serial output used in example, so the production code for ESP module should look like this:

As you can see we only print the UNIX time (epoch), because we will use it to pass as a parameter to the Arduino internal clock setup configuration. I also printed a string “UNX” token before the timestamp just to be sure that ESP doesn’t gives us garbage data.

Now, on the Arduino UNO, we need to listen for the ESP8266 serial transmission. When the ESP sends data on the TX serial channel, we need to check if what is coming is the actual UNIX time and not some garbage or errors. We can do that by checking the first 3 characters which should be = “UNX” token. If this is true, then the next 10 characters should represent the UNIX epoch time. See the demonstration in the example below:

The setTime() method has many overloading versions and can be used with UNIX timestamp parameter but also can take as parameters specific time parts like hour, minutes, seconds. Documentation extras from Arduino official:

/********************
- www.geekstips.com
- Arduino Time Sync from NTP Server using ESP8266 WiFi module
- Arduino code example
********************/
setTime(t); // Set the system time to the
// give time t UNX timestamp
setTime(hr,min,sec,day,month,yr); // Another way to set
// the time with time parts
adjustTime(adjustment); // Adjust system time by adding
// the adjustment value
// WARNING: this is not compatible with using a sync provider as it
// only adjusts the library system time and not time in the sync provider.
// This offset adjustment will be lost on the next time sync.
// If the time is moved forward, an immediate call to now() can get the time
// from the sync provider rather than the adjusted library system time.
// i.e. do not depend on now() to return an adjusted time when using
// a sync provider even when called immediately after adjustTime()
timeStatus(); // Indicates if time has been set and
// recently synchronized
// returns one of the following
// enumerations:
* timeNotSet // The time has never been set,
// the clock started at Jan 1 1970
* timeNeedsSync // The time had been set but a sync
// attempt did not succeed
* timeSet // The time is set and is synced
// Time and Date values are not valid if
// the status is timeNotSet. Otherwise
// values can be used but the returned
// time may have drifted if the status is
// timeNeedsSync.
setSyncProvider(getTimeFunction);// Set the external time
// provider
setSyncInterval(interval); // Set the number of
// seconds between re-sync

After updating the time with UNIX timestamp, you can check the results by calling a function like in the following example:

I used the exact same principle to make a self adjusting digital clock in my house and is working pretty well so far. I also implemented few fail-proof for those situations when requests are failing or the internet connection is dead. You should make some checks and test if the difference between UNIX time received from the NTP and the current timestamp from the RTC isn’t much bigger than the delay between the requests sent to the Server. For example you can save in a variable the last UNIX timestamp received from the ESP module and compare with the current one. The difference between them should be ~ equal with the interval used in ESP loop structure for delay.

This is how my digital clock project looks like:

It displays the clock from an NTP server on a 16×2 common LCD display, using big custom fonts, and also displays the indoor temperature and humidity on a SSD1306 OLED display measured by a DHT22 sensor. I update the time every 10 minutes and make a correction off 2 seconds each time to have a perfect GMT match.

If you are interested to get parts for your project here is what I’ve used (links from Amazon.com):

This is just a way to take advantage of an NTP in your Internet of things projects. You can probably find allot of other methods more complex or maybe better coded to accomplish this task. Also, there are quite many UDP libraries and examples out there, nothing stops you to try them and find the best solution that fits to your project. At the end of the day you should end up getting a good accurate time reference over the internet without doing manually adjustments.

Hoping that this article inspired you, i kindly invite you share this article, subscribe my YouTubechannel and join the communities on social networks. Feel free to comment or send suggestions / remarks so i can improve the content quality.

27 Replies to “Arduino Time Sync from NTP Server using ESP8266 WiFi module”

dannysays:

Nice work! Think this will be perfect for my linux server that does not have wake on lan/wlan. With a few modifications, this will allow me to take my server out of standby at different times and always be accurate even after a brown/black out. May even cut out the Arduino and wire ESP directly to motherboard paralleling my power button.

Happy to be helpful, maybe you let us know when you manage to hook them up together! Good luck!

Rafael Csays:

Thanks, this is of great help. avoid the use of RTC and adds more precision for my project

Anonymoussays:

ok, but could you tell me witch firmware should be in esp?

Anthonysays:

This is a really interesting article, thanks! Can you please help me to understand why you add a 2 second offset to match GMT? Also do you know or have a way to tell what is the delay to receive the time from the server – i.e. how accurate is this method?

” I update the time every 10 minutes and make a correction off 2 seconds each time to have a perfect GMT match.”

I do this correction in order to cover all the time lost during the serial transaction processing, and also during request reading. This is totally project related, depending of hardware speed and connection. In my example I found a ~2 seconds difference on a 10 minutes interval because of the miliseconds losts via SERIAL transactions. You can easiliy measure the data transfer and estimate your loss.

Thank you for your work, this was really helpful!
But I found a mistake in the Arduino-Program:
When reading the Serial from ESP and reading the “UNX”, the comparison should look like:
if ((buffer[0] == ‘U’) && (buffer[1] == ‘N’) && (buffer[2] == ‘X’))

Doesn’t NTP actually return a higher precision than just seconds? Every Arduino project I have seen ignores the values in the return packet at locations 44, 45, 46 and 47. Can’t these be used to set an ESP8266’s clock more accurately? I am working with multiple ESP’s and syncing them to within a half a second of each other (or even less) would be great, if achievable.

Polling an ntp.org server every 10 seconds (as shown in code), or even every 10 minutes (as stated) is abusive and a violation of the ntp.org terms of service (http://www.pool.ntp.org/tos.html). Some servers will flag you as abusive and stop responding.

Thank you Mike for your heads-up! Of course, this is just a demo sketch, is all up to you to read API disclaimers and adjust your code. Also it does not make sense to sync so often. I did 10 seconds just to have better testing environment.

Breixosays:

Before putting this interesting article into practice, I would like to know if once the ESP8266 firmware has been modified as a time server, it can be used simultaneously with an Android app for data input/output.

I am not 100% sure that I understand your question but I will answer this: you can have ESP use this NTP sketch and beside this, you can add you code to make some REST calls to your android or another API in order to maybe push time data.

Hey, thanks a lot , this has put my project back on rails …
although …

I keep getting strange values from the ESP-01. Did you experience this also while testing ?
See below …

TIME FROM ESP: 18:15:41
TIME FROM ESP: 18:14:12
TIME FROM ESP: 21:2:43
TIME FROM ESP: 18:16:14
TIME FROM ESP: 18:16:25
TIME FROM ESP: 18:16:36
TIME FROM ESP: 14:30:7
TIME FROM ESP: 18:17:9
TIME FROM ESP: 14:30:40
TIME FROM ESP: 18:17:53
TIME FROM ESP: 4:13:29
TIME FROM ESP: 16:31:35
TIME FROM ESP: 18:18:26
TIME FROM ESP: 8:31:57
TIME FROM ESP: 18:18:48
TIME FROM ESP: 16:32:19
TIME FROM ESP: 18:17:30
TIME FROM ESP: 18:19:31
TIME FROM ESP: 18:19:33
TIME FROM ESP: 12:6:24