Get Network Time from Yahoo

This sketch is based on the TimeSerial.pde example. Where TimeSerial got the time from the serial port, this version uses the Ethernet Shield to get the time from the Yahoo Network Time API.

Here is a link to the Yahoo Network Time API page http://developer.yahoo.com/util/timeservice/V1/getTime.html

After setting the time, it syncs the clock periodically to correct for drift that may have crept in.

Requires the Arduino and an Ethernet shield only.

I'm new to C programming and would love to hear comments and suggestions particularly on the topic of getting the text out of String objects to use with Serial.print() and such like.

/* 
 YahooTime.pde
 Jul 25 2011
 Bill Leddy - bill@williesworkshop.net

 Request the network time from a Yahoo server with their Network Time API

 The request returns an XML document wrapped in HTML. I parse out the <Timestamp> element
 and set the clock with that number.

 Every hour I send the request again to update the time of the Arduino clock

 * Based on TimeSerial.pde
 */ 
#include <SPI.h>
#include <Ethernet.h>
#include <Time.h>  

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x51, 0x19 };
byte localIP[] = { 10,0,1,50 };
unsigned long nextTimeSync = millis();
String inputString = ""; // seems to work better if this string is declared globally
                         // when declared in getYahooTime, the string value gets cut off after a couple of interations

void setup()  {
    // start the Ethernet connection:
  Ethernet.begin(mac, localIP);
  // start the serial library:
  Serial.begin(9600);
  // give the Ethernet shield a second to initialize:
  delay(1000);
}

void loop(){    
  if(nextTimeSync < millis() ) {
    // time to refresh the time
    // TODO: Need to account for when millis rolls over to 0 again
    time_t pctime = getYahooTime();
    if(pctime > 0) {
      setTime(pctime);
      //nextTimeSync = millis() + 3600000; // next sync in one hour 
      nextTimeSync = millis() + 30000; // for testing, sync a little more often 
    } // pctime > 0
    else {
      // didn't get the time for some reason, leave it as it is for now.
      nextTimeSync = millis() + 10000; // wait a short time then try again 
    }
  } // time to sync clock?

  if(timeStatus()!= timeNotSet)   
  {
    // display the time on the serial monitor
    digitalClockDisplay();  
  }
  delay(1000);
}

void digitalClockDisplay(){
  // digital clock display of the time
  Serial.print(hour());
  printDigits(minute());
  printDigits(second());
  Serial.print(" ");
  Serial.print(day());
  Serial.print(" ");
  Serial.print(month());
  Serial.print(" ");
  Serial.print(year()); 
  Serial.print(" UTC");
  Serial.println(); 
}

void printDigits(int digits){
  // utility function for digital clock display: prints preceding colon and leading 0
  Serial.print(":");
  if(digits < 10)
    Serial.print('0');
  Serial.print(digits);
}

time_t getYahooTime()
{
  time_t pctime = 0;
  // String inputString = "";  // declare this globally

  Serial.println("connecting...");

  byte timeServerIP[] = { 69,147,91,160 }; // developer.yahooapis.com
  char timeHost[] = "developer.yahooapis.com";
  char appid[] = "YahooDemo"; // the default appid  

  boolean receiving = false;

  // Initialize the Ethernet client library
  // with the IP address and port of the server 
  // that you want to connect to (port 80 is default for HTTP):
  Client client(timeServerIP, 80);

  // get the time stamp from Yahoo
  while (receiving == false) {
    if (client.connect()) {
      Serial.println("connected");
      // Make a HTTP request:
      // Get the current UTC time
      client.print("GET /TimeService/V1/getTime?appid=");
      client.print(appid);
      client.println(" HTTP/1.0");
      client.print("Host: ");
      client.println(timeHost);
      client.println();
      receiving = true;
    } 
    else {
      // kf you didn't get a connection to the server:
      Serial.println("connection failed");
      receiving = true;
    }
  }

  delay (4000);  // time to make the connection

  if (client.connected()) {
    while (client.available()) {
      char c = client.read();
      Serial.print(c);
      inputString += c; // accumulate all the received text
    }

    // parse out the epoch timestamp
    int startPos = inputString.indexOf("<Timestamp>"); // timestamp element
    if(startPos >= 0) {
      startPos += 11; // add length of element tag + 1
      int endPos = inputString.indexOf("</Timestamp>",startPos); // timestamp end
        if(endPos > startPos) {
          inputString = inputString.substring(startPos,endPos);
        }
        else {
           Serial.print("endPos not found : ");
           Serial.println(endPos,DEC);
           inputString = "";
        }
     }
     else {
       Serial.print("startPos not found : ");
       Serial.println(startPos,DEC);
       char echoOut[inputString.length()+1];
       inputString.toCharArray(echoOut,(inputString.length())+1);
       Serial.println(echoOut);
       inputString = ""; 
     }
  }
  else {
    Serial.println("Clent could not connect.");
  }  // Client connected

  Serial.println("disconnecting.");

  client.stop();  // we're done with this client

  if(inputString.length() > 0) {
    // transfer the text value out of inputString and into char echoOut
    // It seems to me there should be an easier way to get the text out of a String. Would love to hear comments.
    char echoOut[inputString.length()+1];
    inputString.toCharArray(echoOut,(inputString.length())+1);

    // display the Time Stamp...
    Serial.print("TimeStamp = ");
    Serial.println(echoOut);

    // convert each charater of echoOut into a number and store in pctime
    for (int i = 0; i < inputString.length(); i++) {
      pctime = (10 * pctime) + (echoOut[i] - '0') ; // convert digits to a number 
    }
    inputString = "";
    Serial.print("pctime = ");
    Serial.println(pctime,DEC);

    // Add back the 4 seconds we waited after making the request
    // this still does not mean the time will be completely accurate.
    pctime +=4;

  } // if inputString != ""
  return pctime; 
} // end getYahooTime

Share