Arduino Ethernet Client - NTP Time Sync

Hey arduiners!

I am trying to sync my program with internet time, but unfortunately the library "Time.h" has some bugs.
The NTP ime example doesn;t work as well as every other code on the net cause of arduino version compatibility issues.

Can someon post here a working simple sketch of getting time from a server?

Thanks in advance,
Nick Athanasoulas

the library "Time.h" has some bugs.

No, it has some incompatibility issues with 1.0+, all of which are solvable.

Dear PaulS,
I managed to read time but I need a better sketch so I can have date displayed too.
I also need DST (auto GMT change) everytime the GMT changes in my country.
I am willing to make the code with some help.
But is there a server that sends the local time in my country? But I want to read it as NTp...
Do you know anything to point at me, so maybe I work things out?

Nick Athanasoulas

	/*
	Udp NTP Client with DNS

	I updated the example code to use DNS resolution from the Arduino 1.0 IDE

	Basically tries to use the load-balanced NTP servers which are
	  "magically" returned from DNS queries on pool.ntp.org
	If DNS fails, fall back to the hardcoded IP address
	  for time.nist.gov

	bearpaw7 (github), 01DEC2011

	This code is also in the public domain.
*/

/*

 Udp NTP Client
 
 Get the time from a Network Time Protocol (NTP) time server
 Demonstrates use of UDP sendPacket and ReceivePacket 
 For more on NTP time servers and the messages needed to communicate with them, 
 see http://en.wikipedia.org/wiki/Network_Time_Protocol
 
 created 4 Sep 2010 
 by Michael Margolis
 modified 17 Sep 2010
 by Tom Igoe
 
 This code is in the public domain.

 */

#include <SPI.h>		 
#include <Ethernet.h>
#include <EthernetUdp.h>
#include "Dns.h"

// Enter a MAC address for your controller below.
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
byte mac[] = {  0x00, 0x00, 0xAA, 0xBB, 0xCC, 0xDD};
unsigned int localPort = 80;				// local port to listen for UDP packets
IPAddress timeServer(193,92,150,3); 		// time.nist.gov NTP server (fallback)
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 
const char* host = "nsath.forthnet.gr";			// Use random servers through DNS

// A UDP instance to let us send and receive packets over UDP
EthernetUDP Udp;
DNSClient Dns;
IPAddress rem_add;

void setup() 
{
	Serial.begin(9600);
	
	// start Ethernet and UDP
	if (Ethernet.begin(mac) == 0) {
		Serial.println("Failed to configure Ethernet using DHCP");
		// no point in carrying on, so do nothing forevermore:
		while(true);
	}
	Udp.begin(localPort);
	Dns.begin(Ethernet.dnsServerIP() );
}

void loop()
{
	if(Dns.getHostByName(host, rem_add) == 1 ){
		Serial.println("DNS resolve...");	 
		Serial.print(host);
		Serial.print("  = ");
		Serial.println(rem_add);
		sendNTPpacket(rem_add);
	}else{
		Serial.print("DNS fail...");
		Serial.print("time.nist.gov = ");
		Serial.println(timeServer);	// fallback
		sendNTPpacket(timeServer); 	// send an NTP packet to a time server
	}
	delay(1000);	// wait to see if a reply is available
	if ( Udp.parsePacket() ) {  
		// 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:
		Serial.print("The UTC time is ");		// UTC is the time at Greenwich Meridian (GMT)
		Serial.print((epoch	 % 86400L) / 3600); 	// print the hour (86400 equals secs per day)
		Serial.print(':');	
		if ( ((epoch % 3600) / 60) < 10 ) {
			// In the first 10 minutes of each hour, we'll want a leading '0'
			Serial.print('0');
		}
		Serial.print((epoch	 % 3600) / 60); // print the minute (3600 equals secs per minute)
		Serial.print(':'); 
		if ( (epoch % 60) < 10 ) {
			// In the first 10 seconds of each minute, we'll want a leading '0'
			Serial.print('0');
		}
		Serial.println(epoch %60); // print the second
	}
	// wait ten seconds before asking for the time again
	delay(10000); 
	Serial.println(" ");
}

// send an NTP request to the time server at the given address 
unsigned long sendNTPpacket(IPAddress& address)
{
	// 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(); 
}

But is there a server that sends the local time in my country?

No. All time servers report time in Greenwich mean time. You need to adjust for your local time.

That code does something. You want it to do something. How are those two somethings different?

Its a lot of trouble to make the seconds into date according to the different days each year and some times the leap years.
I also have to customize the sketch to be able to auto-select the GMT time zone according to the date.
I maybe capture date data from another server/site and compare those ones.

Its a lot of trouble to make the seconds into date according to the different days each year and some times the leap years.

I don't see why. There is, in the Time library, a function to set the time based on the number of seconds sine Jan. 1, 1970. That would be the value in epoch in the code you posted. Once you have done that, you simply call year(), month(), day(), hour(), minute(), and second().

There is a function to adjust the time. Set the time based on Greenwich mean time. Then, call adjustTime() with the offset for your local time, and let it deal with the fact that you don't live in Greenland.

I'll look into it. If I make it through I'll post the code. I've laready added code for GMT +/- time zones 2&3 because I am from Greece.
It's easy to adapt to any zone.

Can someone please advise how to make the date and time library to work on Arduino 1.0.1 as it gives some bug when trying to compile.

Can someone please advise how to make the date and time library to work on Arduino 1.0.1 as it gives some bug when trying to compile.

No problem. See that search bar? Use it to search for the other 50 bazillion times the question has been asked and answered.

Or search for the specific error message. I'm certain that you didn't get the Italian version of the compiler that just waves its hands and says "I can't do that".

Hi, I was just working on the same thing for a few days. What I wanted is almost the same thing. Local Timezone, Date & Time and so on. Heres my code (I also included the Timezone-Library to handle the offset to NTP-UTC Time). Since I am using the 'older' Ethernet Shield with the W5100 Chip (wich has a bug), I have inserted subroutines to activate ethernet or the SD-Card. If an SD-Card is inserted at startup (when Ethernet.begin(mac) Function is called) it will fail with a DHCP-Failure, if SD-Card SS-Pin is not set to HIGH.

See my code in the attachement 8)

NTP_Example.ino (8.11 KB)

nathanas:
I am trying to sync my program with internet time

Look at this
Ways to update the RTC DS3231 from NTP server

Thanks K5CZ, as you can see I am still a beginner and this was my first working code for getting NTP-Time. I have made a few DS1307 programs, but since I don't have the correct crystal oscillator with 12.5pf my RTC is extremly inaccurate. It is a 32'768 Mhz, but not the correct pf. In order to keep my RTC accurate I attached a DCF-77 Receiver but I don't receive a signal everywhere in the house. Thats why I was making a testprogram to figure out how I can compare the RTC-Time with NTP. Thanks a lot for the link. I will verify my code again. I am always willing to learn new and better ways of coding AVR's.

Regards dragonfly

I'm still a beginner too :slight_smile: I posted my latest version of the program in the topic above.

For anyone who still get into this topic and wants to get accurate time using NTP servers here is a good resource:
Arduino Time Sync from NTP Server using ESP8266 WiFi module

http://www.zago.site/Tema-Hora-real-y-exacta-cliente-NTP-arduino-Ethernet
here a basic example

nathanas:
Hey arduiners!

I am trying to sync my program with internet time, but unfortunately the library "Time.h" has some bugs.
The NTP ime example doesn;t work as well as every other code on the net cause of arduino version compatibility issues.

Can someon post here a working simple sketch of getting time from a server?

Thanks in advance,
Nick Athanasoulas

What, specifically is the problem? You can't get NTP data at all, or you don't know how to convert the data to date and time?
If it's the latter, look into "Zeller's congruence" (link https://en.m.wikipedia.org/wiki/Zeller%27s_congruence ).

Note you must implement the algorithm using integers, else it fails.

Here's a snippet from some of my code that implements Zeller:

//////////////////////////////////////////////////////////////////////////
// zeller's congruence (calculates day of week) modified so that
// sunday == 0, monday == 1 .... friday == 5, saturday == 6
// reference: http://en.wikipedia.org/wiki/Zeller's_congruence
//////////////////////////////////////////////////////////////////////////
//
//      |     |(m + 1) * 26|       | y |       | y |   | y |     |
//  h = | q + |------------| + y + |---| + 6 * |---| + |---| - 1 | mod 7
//      |     |     10     |       | 4 |       |100|   |400|     |
//
//////////////////////////////////////////////////////////////////////////
uint8_t zeller (uint8_t m, uint8_t d, uint16_t y)
{
	if (m < 3) { // convert months to 2...14
		m += 12;
		y -= 1;
	}

	return (((d + (((m + 1) * 26) / 10) + y + (y / 4) + (6 * (y / 100)) + (y / 400)) - 1) % 7);
}