Open Reefs Controllers - Control and monitor your reef aquarium and provide peace of mind wherever you are.

NTP Time Server Update Code Example

Introduction

This code allows your Arduino to sync with a specified NTP time server to synchronize its own time function. It completes this task on boot. The Arduino keeps track of the time from there and it can be called and used in any way you like. The goal of this code is to provide some basics to introduce the time server functions and is a great way to test your networking capabilities to ensure your hardware is properly configured. This is the first sketch you should use to test your Ethernet card.

Special Notes

Using the Arduino 1.0 IDE you may need to alter the Time library. In ...\arduino-1.0\libraries\Time alter the file: Time.cpp look for a single line at the top that looks like this:
#include <WProgram.h>
If you find this line replace it with this:
  1. #if ARDUINO >= 100
  2. #include <Arduino.h>
  3. #else
  4. #include <WProgram.h>
  5. #endif
This will update the time library to work with both older versions of the IDE or newer versions.


When you highlight and copy this code, the line numbers will NOT be copied with the code. Copy freely!

This code is directly linked to the github repository:
https://github.com/OpenReefs/Open-Reefs-Controllers/tree/master/examples/ntpSync


  1. /*
  2.  * Last Updated - March 21, 2012
  3.  * Open Ocean Reef Controller by Brandon Bearden
  4.  *
  5.  * This work is licensed under the Creative Commons
  6.  * Attribution-NonCommercial-ShareAlike 3.0 Unported License.
  7.  * To view a copy of this license, visit
  8.  * http://creativecommons.org/licenses/by-nc-sa/3.0/
  9.  * or send a letter to Creative Commons, 444 Castro Street,
  10.  * Suite 900, Mountain View, California, 94041, USA.
  11.  *
  12.  * IN NO EVENT SHALL THE LICENSE HOLDER BE LIABLE TO ANY
  13.  * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL,
  14.  * OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS
  15.  * SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE COPYRIGHT
  16.  * HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  17.  *
  18.  * THE LICENSE HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES,
  19.  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  20.  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  21.  * THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS,
  22.  * AND THE LICENCE HOLDER HAS NO OBLIGATION TO PROVIDE
  23.  * MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
  24.  * OR MODIFICATIONS.
  25.  *
  26.  */
  27.  
  28. #include <SPI.h>
  29. #include <Ethernet.h>
  30. #include <EthernetUdp.h>
  31. #include <Time.h>
  32.  
  33. /* ******** Ethernet Card Settings ******** */
  34. // Set this to your Ethernet Card Mac Address
  35. byte mac[] = { 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF };
  36.  
  37. /* ******** NTP Server Settings ******** */
  38. /* us.pool.ntp.org NTP server
  39.    (Set to your time server of choice) */
  40. IPAddress timeServer(96, 44, 157, 90);
  41.  
  42. /* Set this to the offset (in seconds) to your local time
  43.    This example is GMT - 6 */
  44. const long timeZoneOffset = -21600L;  
  45.  
  46. /* Syncs to NTP server every 15 seconds for testing,
  47.    set to 1 hour or more to be reasonable */
  48. unsigned int ntpSyncTime = 15;        
  49.  
  50.  
  51. /* ALTER THESE VARIABLES AT YOUR OWN RISK */
  52. // local port to listen for UDP packets
  53. unsigned int localPort = 8888;
  54. // NTP time stamp is in the first 48 bytes of the message
  55. const int NTP_PACKET_SIZE= 48;      
  56. // Buffer to hold incoming and outgoing packets
  57. byte packetBuffer[NTP_PACKET_SIZE];  
  58. // A UDP instance to let us send and receive packets over UDP
  59. EthernetUDP Udp;                    
  60. // Keeps track of how long ago we updated the NTP server
  61. unsigned long ntpLastUpdate = 0;    
  62. // Check last time clock displayed (Not in Production)
  63. time_t prevDisplay = 0;            
  64.  
  65. void setup() {
  66.    Serial.begin(9600);
  67.    
  68.    // Ethernet shield and NTP setup
  69.    int i = 0;
  70.    int DHCP = 0;
  71.    DHCP = Ethernet.begin(mac);
  72.    //Try to get dhcp settings 30 times before giving up
  73.    while( DHCP == 0 && i < 30){
  74.      delay(1000);
  75.      DHCP = Ethernet.begin(mac);
  76.      i++;
  77.    }
  78.    if(!DHCP){
  79.     Serial.println("DHCP FAILED");
  80.      for(;;); //Infinite loop because DHCP Failed
  81.    }
  82.    Serial.println("DHCP Success");
  83.    
  84.    //Try to get the date and time
  85.    int trys=0;
  86.    while(!getTimeAndDate() && trys<10) {
  87.      trys++;
  88.    }
  89. }
  90.  
  91. // Do not alter this function, it is used by the system
  92. int getTimeAndDate() {
  93.    int flag=0;
  94.    Udp.begin(localPort);
  95.    sendNTPpacket(timeServer);
  96.    delay(1000);
  97.    if (Udp.parsePacket()){
  98.      Udp.read(packetBuffer,NTP_PACKET_SIZE);  // read the packet into the buffer
  99.      unsigned long highWord, lowWord, epoch;
  100.      highWord = word(packetBuffer[40], packetBuffer[41]);
  101.      lowWord = word(packetBuffer[42], packetBuffer[43]);  
  102.      epoch = highWord << 16 | lowWord;
  103.      epoch = epoch - 2208988800 + timeZoneOffset;
  104.      flag=1;
  105.      setTime(epoch);
  106.      ntpLastUpdate = now();
  107.    }
  108.    return flag;
  109. }
  110.  
  111. // Do not alter this function, it is used by the system
  112. unsigned long sendNTPpacket(IPAddress& address)
  113. {
  114.   memset(packetBuffer, 0, NTP_PACKET_SIZE);
  115.   packetBuffer[0] = 0b11100011;
  116.   packetBuffer[1] = 0;
  117.   packetBuffer[2] = 6;
  118.   packetBuffer[3] = 0xEC;
  119.   packetBuffer[12]  = 49;
  120.   packetBuffer[13]  = 0x4E;
  121.   packetBuffer[14]  = 49;
  122.   packetBuffer[15]  = 52;                  
  123.   Udp.beginPacket(address, 123);
  124.   Udp.write(packetBuffer,NTP_PACKET_SIZE);
  125.   Udp.endPacket();
  126. }
  127.  
  128. // Clock display of the time and date (Basic)
  129. void clockDisplay(){
  130.   Serial.print(hour());
  131.   printDigits(minute());
  132.   printDigits(second());
  133.   Serial.print(" ");
  134.   Serial.print(day());
  135.   Serial.print(" ");
  136.   Serial.print(month());
  137.   Serial.print(" ");
  138.   Serial.print(year());
  139.   Serial.println();
  140. }
  141.  
  142. // Utility function for clock display: prints preceding colon and leading 0
  143. void printDigits(int digits){
  144.   Serial.print(":");
  145.   if(digits < 10)
  146.     Serial.print('0');
  147.   Serial.print(digits);
  148. }
  149.  
  150. // This is where all the magic happens...
  151. void loop() {
  152.     // Update the time via NTP server as often as the time you set at the top
  153.     if(now()-ntpLastUpdate > ntpSyncTime) {
  154.       int trys=0;
  155.       while(!getTimeAndDate() && trys<10){
  156.         trys++;
  157.       }
  158.       if(trys<10){
  159.         Serial.println("ntp server update success");
  160.       }
  161.       else{
  162.         Serial.println("ntp server update failed");
  163.       }
  164.     }
  165.    
  166.     // Display the time if it has changed by more than a second.
  167.     if( now() != prevDisplay){
  168.       prevDisplay = now();
  169.       clockDisplay();  
  170.     }
  171. }

If you have successfully setup your hardware and this sketch, then you should see something like this on your serial window:

DHCP Success
15:23:42 21 3 2012
15:23:43 21 3 2012
15:23:44 21 3 2012
15:23:45 21 3 2012
15:23:46 21 3 2012
15:23:47 21 3 2012
15:23:48 21 3 2012
15:23:49 21 3 2012
15:23:50 21 3 2012
15:23:51 21 3 2012
15:23:52 21 3 2012
15:23:53 21 3 2012
15:23:54 21 3 2012
15:23:55 21 3 2012
15:23:56 21 3 2012
15:23:57 21 3 2012
ntp server update success
15:23:59 21 3 2012
15:24:00 21 3 2012
15:24:01 21 3 2012
15:24:02 21 3 2012
15:24:03 21 3 2012

Something is not setup correctly or your network does not support DHCP if you see this:
DHCP FAILED