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