arduino-libraries / WiFi101

Wifi library for the Arduino WiFi 101 Shield
158 stars 128 forks source link

No example for the WiFi.getTime() function #124

Open drp0 opened 7 years ago

drp0 commented 7 years ago

The wifi101 library offers WiFi.getTime() to return the epoch time. This can be used with the avr-libc time.h library and not with the library Reference https://github.com/arduino-libraries/WiFi101/issues/111

After a lot of digging I found a mac example demonstrating the time.h library functions I have adapted the code to work with the wifi101 The library is a bit cumbersome to work with and one of the key functions to produce a sdfat timestamp appears not to be correctly linked in the core. Despite this, the library has a lot of very powerful esoteric functions. The first listing is without SdFat support. The second has (my) time/date stamping for SdFat files.

// Timetest.ino

// adapted from Mac example at http://swfltek.com/arduino/builds/1.6.6/

// useful Michael Duane <time.h> source listing http://www.nongnu.org/avr-libc/user-manual/time_8h_source.html
// time manual http://www.nongnu.org/avr-libc/user-manual/group__avr__time.html

// D.R.Patterson
// 17/12/2016

// Tested on a AtMega 2560 

// The time library time.h can be initialsed with an epoch time
// this can be entered from a Serial interface, or
// if WiFi is available the initial time can be set with a call to WiFi.getTime()

// for an led pulse the code requires:
  // two pins with a 1Kohm resistor in series with an led
  // the led cathode grounded to irqpinlo
  // the resistor in series with the anode, connected to irqpin

// To maintain the clock on the Time.h library the function system_tick() must be
// called at one second intervals.
// TimerOne.h library facilitates this
// This has less overhead than repeatedly calling the WiFi.getTime() function

// The code uses "double" for many non-integer variables
// On the Uno and other ATMEGA arduino this is interpreted as float (4-bytes)
// The Arduino Due interprets double as 8-bytes (64 bit) precision

#include <time.h>
//#include <util/usa_dst.h> // usa daylight saving
#include <util/eu_dst.h>    // eu daylight saving
#include <math.h>
#include <time.h>
#include <TimerOne.h>

#define RAD_TO_DEGREE 57.29577951308233
#define BTRA 5.91944444444444
#define BTDECL 7.4071

#define MY_LATITUDE 54.99065 * ONE_DEGREE   // my latitude (degrees) is North, therefore +
#define MY_LONGITUDE -1.59988 * ONE_DEGREE  // my longitude is east therefore -
#define MY_TIME_ZONE 0 * ONE_HOUR           // gmt offset 0
  // The 'time zone'  parameter is given in seconds East of the Prime Meridian.
  // For New York City: -5 * ONE_HOUR
//#define MY_DST usa_dst                    // usa time saving
#define MY_DST eu_dst                       // eu  daylight time saving

// buffer and index to store incoming serial data
char db[19];
int dbi=0;
volatile boolean toggle = false;  // led on off flag
volatile boolean badirq = true;   // signal 1st irq trigger
boolean isSet = false;
boolean clockset=false;

const byte pinirq = 26;   // irq led pulse
const byte pinirqlo = 28; // irq led ground

#include <SPI.h>
#include <WiFi101.h>
const byte wifiSelect = 10; // YiFi101 select (active low)
const byte sdSelect = 53;   // SD select (active low)
int mystatus = WL_IDLE_STATUS;
const char ssid[] = "DRP3";  //  your network SSID (name)
boolean havewifi = true;

void setup(){
// setup wifi and disable sd if used
pinMode(sdSelect, OUTPUT); digitalWrite(sdSelect, HIGH);
pinMode(wifiSelect, OUTPUT); digitalWrite(wifiSelect, LOW);

// setup irq heartbeat
pinMode(pinirq, OUTPUT); digitalWrite(pinirq, LOW);
pinMode(pinirqlo, OUTPUT); digitalWrite(pinirqlo, LOW);

Serial.begin(115200);
  while(!Serial) yield();

  // check for the presence of the shield:
  if (WiFi.status() == WL_NO_SHIELD) {
  Serial.println("WiFi shield not present");
  havewifi = false;
  }else{
  // attempt to connect to Wifi network:
  byte attempts = 0;  
    while ( attempts < 3) {
    attempts++;
    Serial.print("Attempting to connect to SSID: "); Serial.println(ssid);
    mystatus = WiFi.begin(ssid);
    unsigned long tt = millis();
      while ((millis()-tt) < 10000){ // up to 10 second wait
      delay(1000);
      mystatus = WiFi.status();
        if ((mystatus == WL_CONNECTED) || (mystatus == WL_NO_SHIELD)) break;
      }
      if ((mystatus == WL_CONNECTED) || (mystatus == WL_NO_SHIELD)) break;
    }
  }

  if (mystatus == WL_CONNECTED) Serial.println("Wifi Connected\n");
  else{
  havewifi = false;
  Serial.println("Wifi not available\n");
  }

set_dst(MY_DST);        // eu daylight saving in my case
set_zone(MY_TIME_ZONE); // GMT 0 in my case
// set_position( 54.99065 * ONE_DEGREE, -1.59988 * ONE_DEGREE);
set_position(MY_LATITUDE, MY_LONGITUDE);

Serial.println("Enter ISO Date-time (YYYY-MM-DD HH:MM:SSt)");
// NB use of trailing 't' if serial monitor does not send CR or LF!
// do not send brackets! 

Timer1.initialize(1000000); // irq timeout 1 second- increments the clock
Timer1.attachInterrupt(tick);
Timer1.stop();
unsigned int date;
  if (havewifi){
    for(byte i = 0 ; i < 5; i++){
    unsigned long epoch = WiFi.getTime(); // get wifi time
    set_system_time( (time_t)epoch );     // set the time library
    time_t tnow;
    struct tm lt;
    time(&tnow); // store time in variable tnow
    localtime_r(&tnow, &lt);       // place local time in lt
    date = getyear(&lt);
      if(date < 2021) i = 5; else delay(5000);
    }
    if (date > 2020){
    havewifi = false;
    }else{
    badirq = true;                        // flag to prevent 1st triggering of IRQ incrementor 
    Timer1.start();                       // start the IRQ clock, 1 second reload
    toggle = true;                        // led on off control
    clockset = true;                      // flag to show advanced functions once
    isSet = true;                         // flag to show clock is set and can show valid time

    Serial.println("Clock set using WiFi.getTime()");
    }
  }
}

// ******************************* IRQ ************************************
void tick(){ 
  if(badirq){ // irq - will give an initial extra tick when irq initialised
  badirq = false;
  return; // ignore and flag it
  }
system_tick(); // increment clock by 1 second
digitalWrite(pinirq, toggle);
toggle = !toggle;
}
// **************************** End IRQ ***********************************

void loop(){
again:
time_t tnow, d;
struct tm gm, lt, sid, daylen, noon, Srise, Sset;
char buff[26];
double n, decl, eot;
int i, phase;
unsigned long m;
char c;

  // check if user has entered a new date
  if(Serial.available() ) {
  Timer1.stop(); // stop the clock incrementing
  isSet = false;
  digitalWrite(pinirq, LOW);
    while(Serial.available()){
    c=Serial.read(); Serial.write(c);
      if(c == 't') c = 13; // Arduino serial monitor does not send cr/lf
    db[dbi]=c;
      if(c == 13 || c == 10){
        while(Serial.available()) c = Serial.read(); // flush input
      db[dbi] = 0;
      Serial.println();
      setTheClock(db);
      dbi = -1;
      }
    dbi++;
    }
  }else{
    if(isSet){
    time(&tnow);
    localtime_r(&tnow,&lt);
    Serial.println(isotime(&lt));
    delay(1000);
    }
  }

  if(!clockset) goto again; // feel free to mess around with a while loop instead

m = millis(); // measure the time it takes to compute some time functions

time(&tnow); // store time in variable tnow

gmtime_r(&tnow, &gm);          // convert tnow and place GMT in gm time pointer
localtime_r(&tnow, &lt);       // place local time in lt
String ascTime = asctime(&lt); // day and month as text, based on local time

// ***************** Time.h Advanced function calls ************

// call to get a fat file time stamp - this would be very useful,
// however fatfs_time call does not compile
// produces undefined reference- probably a core reference issue?
/*
Serial.print("fs test ");
unsigned long fstest =  fatfs_time(&lt);
Serial.println(fstest);
*/

eot = equation_of_time(&tnow) / 60.0; // convert to minutes

phase = moon_phase(&tnow);

d = lm_sidereal(&tnow);
gmtime_r(&d,&sid);

decl = solar_declination(&tnow) * 57.3;

d = daylight_seconds(&tnow);
gmtime_r(&d,&daylen);

d = solar_noon(&tnow);
localtime_r(&d,&noon);

d = sun_set(&tnow);
localtime_r(&d,&Sset);

d = sun_rise(&tnow);
localtime_r(&d,&Srise);
// ************ End Time.h Advanced function calls ************

m = millis() - m; // elapsed time

Serial.println("===================================================\n");
Serial.print("This Arduino is using AVR-Libc version ");
Serial.print(__AVR_LIBC_VERSION_STRING__);
Serial.print(" and running at ");
n = F_CPU / 1000000L;
Serial.print(n);
Serial.println(" Mhz");
Serial.write(10);

Serial.print(m);
Serial.println(" milliseconds to compute results\n");

Serial.print(isotime(&gm));
Serial.println(" UTC\n");

Serial.println(ascTime);
Serial.print(isotime(&lt)); // The isotime function constructs an ascii string from the time code
Serial.println(" Local time");
  if(lt.tm_isdst > 0) Serial.println("Daylight Savings is in effect");
Serial.write(10);

isotime_r(&sid,buff);
Serial.print(&buff[11]);
Serial.println(" Local Sidereal Time\n");

Serial.print("Solar Declination : ");
Serial.print(decl);
Serial.println(" degrees\n");

isotime_r(&daylen,buff);
Serial.print(&buff[11]);
Serial.println(" hh:mm:ss of daylight today\n");

Serial.print("Equation of time (The difference between\napparent solar time and mean solar time) ");
Serial.print(eot);
Serial.println(" minutes\n");

isotime_r(&noon,buff);
Serial.print("Solar noon : ");
Serial.print(&buff[11]);
Serial.println(" local time\n");

Serial.print("Sunrise : ");
isotime_r(&Srise,buff);
Serial.println(&buff[11]);
Serial.write(10);

Serial.print("Sunset : "); 
isotime_r(&Sset,buff);
Serial.println(&buff[11]);
Serial.write(10);

double az, alt;
SolarPosition(&tnow, &az, &alt);
Serial.print("Azimuth ");
Serial.print(az * RAD_TO_DEGREE);
Serial.print(" Altitude ");
Serial.println(alt * RAD_TO_DEGREE);
Serial.write(10);

StarPosition(&tnow, BTRA, BTDECL, &az, &alt);
Serial.print("Betelguese Azimuth ");
Serial.print(az * RAD_TO_DEGREE);
Serial.print(" Altitude ");
Serial.println(alt * RAD_TO_DEGREE);
Serial.write(10);

Serial.print("Moon phase : ");
  if(phase > 0){
  Serial.print("Waxing ");
  }else{
  Serial.print("Waning ");
  }
Serial.print(abs(phase));
Serial.println("%\n");

MoonPosition(&tnow, &az, &alt);
Serial.print("Azimuth ");
Serial.print(az * RAD_TO_DEGREE);
Serial.print(" Altitude ");
Serial.println(alt * RAD_TO_DEGREE);
Serial.println("===================================================\n");

clockset = false;
}

// ************************** extract Serial data **********************
void setTheClock(char *date){
time_t systime;
struct tm tmptr;
int a[6];
int i=0;
char c;
char * p;

Serial.print("Parsing ");
Serial.println(date);

  // replace '-' and ':' with spaces
  do{
  c=date[i];
  if(c=='-' || c==':') date[i]=' ';
  i++;
  } while(c);

// extract the numbers
p = strtok(date," ");
  for(i=0;i<6;i++){
  a[i] = atoi(p);
  Serial.print(a[i]);
  Serial.write(' ');
  p = strtok(NULL," ");
  }
Serial.write(10);

// set the clock
tmptr.tm_year = a[0]-1900;
tmptr.tm_mon = a[1]-1;
tmptr.tm_mday = a[2];
tmptr.tm_hour = a[3];
tmptr.tm_min = a[4];
tmptr.tm_sec = a[5];
tmptr.tm_isdst = -1;
//tmptr.tm_wday = 5; // can set the week day( 0 = Sunday): works wihout this

systime = mktime(&tmptr);
set_system_time(systime);
badirq = true;  // flag to prevent 1st triggering of IRQ incrementor 
Timer1.start(); // start the IRQ clock
toggle = true;
clockset = true;
isSet = true; 
Serial.println("Clock set!");
}
// ********************** End extract Serial data **********************

unsigned int getyear(const struct tm * timeptr) {
return timeptr->tm_year + 1900;
}

void showdetails(const struct tm * timeptr) {
const String dayName[7] = {"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"};
const String monthName[12] = {"January","February","March","April","May","June","July",
"August","September","October","November","December"};
Serial.println("Time breakdown");
int Year = timeptr->tm_year + 1900;
Serial.print("Year "); Serial.print(Year);
  if ( is_leap_year(Year)) Serial.println(" :Leap year"); else Serial.println(" :Non leap year"); 
byte monthNo =  timeptr->tm_mon;
Serial.print("Month "); Serial.print(monthNo +1); Serial.println(" :"+ monthName[monthNo]);
Serial.print("Day "); Serial.println(timeptr->tm_mday);
byte wday = timeptr->tm_wday;
Serial.print("Week Day "); Serial.print(wday); Serial.println(" :" + dayName[wday]);
Serial.print("Hour "); Serial.println(timeptr->tm_hour);
Serial.print("minute "); Serial.println(timeptr->tm_min);
Serial.print("Second "); Serial.println(timeptr->tm_sec);
Serial.println();
}

// *********************Advanced time libray functions *****************
void SolarPosition(time_t * point_in_time, double * Azimuth, double * Altitude){
time_t noon = solar_noon(point_in_time) % ONE_DAY;// time of noon mod one day
time_t tday = *point_in_time % ONE_DAY; // current time mod one day
long r = tday - noon; // offset from noon, -43200 to + 43200 seconds
double HourAngle = r / 86400.0; // hour angle as percentage of full day
HourAngle = HourAngle * 2.0 * M_PI; // hour angle in radians

double Declination = solar_declination(point_in_time);// declination in radians
AltAz( HourAngle, Declination,Azimuth,Altitude );
} 

void AltAz(double HourAngle, double Declination, double * Azimuth, double * Altitude){
extern long  __latitude;
double Latitude =  __latitude / ( ONE_DEGREE * RAD_TO_DEGREE);          // latitude in radians

double CosHourAngle = cos(HourAngle);
double SinLatitude = sin(Latitude);
double CosLatitude = cos(Latitude);

*Azimuth = atan ( sin(HourAngle) / ( CosHourAngle * SinLatitude - tan(Declination ) * CosLatitude ) );
*Altitude = asin( CosHourAngle * cos(Declination) * CosLatitude + sin(Declination) * SinLatitude );
}

void StarPosition(time_t * point_in_time, double RA, double Decl, double * Azimuth, double * Altitude){
// RA is in hours... convert to seconds
long ra = RA * ONE_HOUR;

// compute hour angle in seconds
long lst = lm_sidereal(point_in_time); 
double HourAngle = lst - ra;

// convert to radians
HourAngle *= M_PI;
HourAngle /= 43200.0;

// pass control to AltAz()
AltAz(HourAngle, Decl / RAD_TO_DEGREE, Azimuth, Altitude);
}

void MoonPosition(time_t * point_in_time, double * Azimuth, double * Altitude){
// at solar noon at new moon, moons ha is same as suns
// the ha 'elongates' as moon progresses to full

time_t noon = solar_noon(point_in_time) % ONE_DAY;// time of noon mod one day
time_t tday = *point_in_time % ONE_DAY; // current time mod one day
long r = tday - noon; // offset from noon, -43200 to + 43200 seconds
// r = HA of sun in seconds

long elongation =moon_phase(point_in_time) * -432L;

r = r + elongation;

double HourAngle = r / 86400.0; // hour angle as percentage of full day
HourAngle = HourAngle * 2.0 * M_PI; // hour angle in radians

double Declination = solar_declination(point_in_time);// declination in radians
AltAz( HourAngle, Declination,Azimuth,Altitude );
}
// *****************End Advanced time libray functions *****************

This version includes a method for producing sdfat time/date stamps

// Timetest.ino

// adapted from Mac example at http://swfltek.com/arduino/builds/1.6.6/

// useful Michael Duane <time.h> source listing http://www.nongnu.org/avr-libc/user-manual/time_8h_source.html
// time manual http://www.nongnu.org/avr-libc/user-manual/group__avr__time.html

// D.R.Patterson
// 17/12/2016

// Tested on a AtMega 2560 

// The time library time.h can be initialsed with an epoch time
// this can be entered from a Serial interface, or
// if WiFi is available the initial time can be set with a call to WiFi.getTime()
// A timestamp call back method is included for the sdfat library

// for an led pulse the code requires:
  // two pins with a 1Kohm resistor in series with an led
  // the led cathode grounded to irqpinlo
  // the resistor in series with the anode, connected to irqpin

// To maintain the clock on the Time.h library the function system_tick() must be
// called at one second intervals.
// TimerOne.h library facilitates this
// This has less overhead than repeatedly calling the WiFi.getTime() function

// The code uses "double" for many non-integer variables
// On the Uno and other ATMEGA arduino this is interpreted as float (4-bytes)
// The Arduino Due interprets double as 8-bytes (64 bit) precision

#include <time.h>
//#include <util/usa_dst.h> // usa daylight saving
#include <util/eu_dst.h>    // eu daylight saving
#include <math.h>
#include <time.h>
#include <TimerOne.h>
// SdFat
#include <SPI.h>
#include <SdFat.h>

#define RAD_TO_DEGREE 57.29577951308233
#define BTRA 5.91944444444444
#define BTDECL 7.4071

#define MY_LATITUDE 54.99065 * ONE_DEGREE   // my latitude (degrees) is North, therefore +
#define MY_LONGITUDE -1.59988 * ONE_DEGREE  // my longitude is east therefore -
#define MY_TIME_ZONE 0 * ONE_HOUR           // gmt offset 0
  // The 'time zone'  parameter is given in seconds East of the Prime Meridian.
  // For New York City: -5 * ONE_HOUR
//#define MY_DST usa_dst                    // usa time saving
#define MY_DST eu_dst                       // eu  daylight time saving

// buffer and index to store incoming serial data
char db[19];
int dbi=0;
volatile boolean toggle = false;  // led on off flag
volatile boolean badirq = true;   // signal 1st irq trigger
boolean isSet = false;
boolean clockset = false;

// SD variables
SdFat sd; // file system object
SdFile myfile;
Sd2Card card;
boolean hascard = false;

const byte pinirq = 26;   // irq led pulse
const byte pinirqlo = 28; // irq led ground

#include <SPI.h>
#include <WiFi101.h>
const byte wifiSelect = 10; // YiFi101 select (active low)
const byte sdSelect = 53;   // SD select (active low)
int mystatus = WL_IDLE_STATUS;
const char ssid[] = "DRP3";  //  your network SSID (name)
boolean havewifi = true;

void setup(){
// setup wifi and sd select
pinMode(sdSelect, OUTPUT); digitalWrite(sdSelect, HIGH);
pinMode(wifiSelect, OUTPUT); digitalWrite(wifiSelect, HIGH);

// setup irq heartbeat
pinMode(pinirq, OUTPUT); digitalWrite(pinirq, LOW);
pinMode(pinirqlo, OUTPUT); digitalWrite(pinirqlo, LOW);

Serial.begin(115200);
  while(!Serial) yield();

hascard = testSDcard();

  // check for the presence of the shield:
digitalWrite(wifiSelect, LOW);
  if (WiFi.status() == WL_NO_SHIELD) {
  Serial.println("WiFi shield not present");
  havewifi = false;
  }else{
  // attempt to connect to Wifi network:
  byte attempts = 0;  
    while ( attempts < 3) {
    attempts++;
    Serial.print("Attempting to connect to SSID: "); Serial.println(ssid);
    mystatus = WiFi.begin(ssid);
    unsigned long tt = millis();
      while ((millis()-tt) < 10000){ // up to 10 second wait
      delay(1000);
      mystatus = WiFi.status();
        if ((mystatus == WL_CONNECTED) || (mystatus == WL_NO_SHIELD)) break;
      }
      if ((mystatus == WL_CONNECTED) || (mystatus == WL_NO_SHIELD)) break;
    }
  }

  if (mystatus == WL_CONNECTED) Serial.println("Wifi Connected\n");
  else{
  havewifi = false;
  Serial.println("Wifi not available\n");
  }

set_dst(MY_DST);        // eu daylight saving in my case
set_zone(MY_TIME_ZONE); // GMT 0 in my case
// set_position( 54.99065 * ONE_DEGREE, -1.59988 * ONE_DEGREE);
set_position(MY_LATITUDE, MY_LONGITUDE);

Serial.println("Enter ISO Date-time (YYYY-MM-DD HH:MM:SSt)");
// NB use of trailing 't' if serial monitor does not send CR or LF!
// do not send brackets! 

Timer1.initialize(1000000); // irq timeout 1 second- increments the clock
Timer1.attachInterrupt(tick);
Timer1.stop();
unsigned int date;
  if (havewifi){
  unsigned long epoch;
    for(byte i = 0 ; i < 10; i++){
      if (i > 0) delay(5000);
    epoch = WiFi.getTime(); // get wifi time
    Serial.print("Epoch "); Serial.println(epoch);
      if(epoch == 0)continue;
    set_system_time( (time_t)epoch );     // set the time library
    time_t tnow;
    struct tm lt;
    time(&tnow); // store time in variable tnow
    localtime_r(&tnow, &lt);       // place local time in lt
    date = lt.tm_year + 1900;
      if(date < 2021) break;
    }
    if ( (date > 2020) || (epoch == 0)){
    havewifi = false;
    }else{
    badirq = true;                        // flag to prevent 1st triggering of IRQ incrementor 
    Timer1.start();                       // start the IRQ clock, 1 second reload
    toggle = true;                        // led on off control
    clockset = true;                      // flag to show advanced functions once
    isSet = true;                         // flag to show clock is set and can show valid time

    Serial.println("Clock set using WiFi.getTime()");
    } 
  }
}

// ******************************* IRQ ************************************
void tick(){ 
  if(badirq){ // irq - will give an initial extra tick when irq initialised
  badirq = false;
  return; // ignore and flag it
  }
system_tick(); // increment clock by 1 second
digitalWrite(pinirq, toggle);
toggle = !toggle;
}
// **************************** End IRQ ***********************************

void loop(){
again:
time_t tnow, d;
struct tm gm, lt, sid, daylen, noon, Srise, Sset;
char buff[26];
double n, decl, eot;
int i, phase;
unsigned long m;
char c;

  // check if user has entered a new date
  if(Serial.available() ) {
  Timer1.stop(); // stop the clock incrementing
  isSet = false;
  digitalWrite(pinirq, LOW);
    while(Serial.available()){
    c=Serial.read(); Serial.write(c);
      if(c == 't') c = 13; // Arduino serial monitor does not send cr/lf
    db[dbi]=c;
      if(c == 13 || c == 10){
        while(Serial.available()) c = Serial.read(); // flush input
      db[dbi] = 0;
      Serial.println();
      setTheClock(db);
      dbi = -1;
      }
    dbi++;
    }
  }else{
    if(isSet){
    time(&tnow);
    localtime_r(&tnow,&lt);
    Serial.println(isotime(&lt));
    delay(1000);
    }
  }

  if(!clockset) goto again; // feel free to mess around with a while loop instead

m = millis(); // measure the time it takes to compute some time functions

time(&tnow); // store time in variable tnow

gmtime_r(&tnow, &gm);          // convert tnow and place GMT in gm time pointer
localtime_r(&tnow, &lt);       // place local time in lt
String ascTime = asctime(&lt); // day and month as text, based on local time

// ***************** Time.h Advanced function calls ************

eot = equation_of_time(&tnow) / 60.0; // convert to minutes

phase = moon_phase(&tnow);

d = lm_sidereal(&tnow);
gmtime_r(&d,&sid);

decl = solar_declination(&tnow) * 57.3;

d = daylight_seconds(&tnow);
gmtime_r(&d,&daylen);

d = solar_noon(&tnow);
localtime_r(&d,&noon);

d = sun_set(&tnow);
localtime_r(&d,&Sset);

d = sun_rise(&tnow);
localtime_r(&d,&Srise);
// ************ End Time.h Advanced function calls ************

m = millis() - m; // elapsed time

Serial.println("===================================================\n");
Serial.print("This Arduino is using AVR-Libc version ");
Serial.print(__AVR_LIBC_VERSION_STRING__);
Serial.print(" and running at ");
n = F_CPU / 1000000L;
Serial.print(n);
Serial.println(" Mhz");
Serial.write(10);

Serial.print(m);
Serial.println(" milliseconds to compute results\n");

Serial.print(isotime(&gm));
Serial.println(" UTC\n");

Serial.println(ascTime);
Serial.print(isotime(&lt)); // The isotime function constructs an ascii string from the time code
Serial.println(" Local time");
  if(lt.tm_isdst > 0) Serial.println("Daylight Savings is in effect");
Serial.write(10);
showdetails(&lt); // display seperate time fields

  if(hascard) { // create a file with a time stamp
  testSdwrite();
  }

isotime_r(&sid,buff);
Serial.print(&buff[11]);
Serial.println(" Local Sidereal Time\n");

Serial.print("Solar Declination : ");
Serial.print(decl);
Serial.println(" degrees\n");

isotime_r(&daylen,buff);
Serial.print(&buff[11]);
Serial.println(" hh:mm:ss of daylight today\n");

Serial.print("Equation of time (The difference between\napparent solar time and mean solar time) ");
Serial.print(eot);
Serial.println(" minutes\n");

isotime_r(&noon,buff);
Serial.print("Solar noon : ");
Serial.print(&buff[11]);
Serial.println(" local time\n");

Serial.print("Sunrise : ");
isotime_r(&Srise,buff);
Serial.println(&buff[11]);
Serial.write(10);

Serial.print("Sunset : "); 
isotime_r(&Sset,buff);
Serial.println(&buff[11]);
Serial.write(10);

double az, alt;
SolarPosition(&tnow, &az, &alt);
Serial.print("Azimuth ");
Serial.print(az * RAD_TO_DEGREE);
Serial.print(" Altitude ");
Serial.println(alt * RAD_TO_DEGREE);
Serial.write(10);

StarPosition(&tnow, BTRA, BTDECL, &az, &alt);
Serial.print("Betelguese Azimuth ");
Serial.print(az * RAD_TO_DEGREE);
Serial.print(" Altitude ");
Serial.println(alt * RAD_TO_DEGREE);
Serial.write(10);

Serial.print("Moon phase : ");
  if(phase > 0){
  Serial.print("Waxing ");
  }else{
  Serial.print("Waning ");
  }
Serial.print(abs(phase));
Serial.println("%\n");

MoonPosition(&tnow, &az, &alt);
Serial.print("Azimuth ");
Serial.print(az * RAD_TO_DEGREE);
Serial.print(" Altitude ");
Serial.println(alt * RAD_TO_DEGREE);
Serial.println("===================================================\n");

clockset = false;
}

// ************************** extract Serial data **********************
void setTheClock(char *date){
time_t systime;
struct tm tmptr;
int a[6];
int i=0;
char c;
char * p;

Serial.print("Parsing ");
Serial.println(date);

  // replace '-' and ':' with spaces
  do{
  c=date[i];
  if(c=='-' || c==':') date[i]=' ';
  i++;
  } while(c);

// extract the numbers
p = strtok(date," ");
  for(i=0;i<6;i++){
  a[i] = atoi(p);
  Serial.print(a[i]);
  Serial.write(' ');
  p = strtok(NULL," ");
  }
Serial.write(10);

// set the clock
tmptr.tm_year = a[0]-1900;
tmptr.tm_mon = a[1]-1;
tmptr.tm_mday = a[2];
tmptr.tm_hour = a[3];
tmptr.tm_min = a[4];
tmptr.tm_sec = a[5];
tmptr.tm_isdst = -1;
//tmptr.tm_wday = 5; // can set the week day( 0 = Sunday): works wihout this

systime = mktime(&tmptr);
set_system_time(systime);
badirq = true;  // flag to prevent 1st triggering of IRQ incrementor 
Timer1.start(); // start the IRQ clock
toggle = true;
clockset = true;
isSet = true; 
Serial.println("Clock set!");
}
// ********************** End extract Serial data **********************

void showdetails(const struct tm * timeptr) {
const String dayName[7] = {"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"};
const String monthName[12] = {"January","February","March","April","May","June","July",
"August","September","October","November","December"};
Serial.println("Time breakdown");
int Year = timeptr->tm_year + 1900;
Serial.print("Year "); Serial.print(Year);
  if ( is_leap_year(Year)) Serial.println(" :Leap year"); else Serial.println(" :Non leap year"); 
byte monthNo =  timeptr->tm_mon;
Serial.print("Month "); Serial.print(monthNo +1); Serial.println(" :"+ monthName[monthNo]);
Serial.print("Day "); Serial.println(timeptr->tm_mday);
byte wday = timeptr->tm_wday;
Serial.print("Week Day "); Serial.print(wday); Serial.println(" :" + dayName[wday]);
Serial.print("Hour "); Serial.println(timeptr->tm_hour);
Serial.print("minute "); Serial.println(timeptr->tm_min);
Serial.print("Second "); Serial.println(timeptr->tm_sec);
Serial.println();
}

void testSdwrite() { // sdfat date/time stamp test
digitalWrite(wifiSelect, HIGH);  // disable wifi
digitalWrite(sdSelect, LOW);   // enable sd card

char testfile[] = "sdtest.txt";
Serial.print("SD fat date/time stamp with "); Serial.println(testfile);

  if(sd.exists(testfile)) sd.remove(testfile);

SdFile::dateTimeCallback(dateTime); // enable time call back function for file create
boolean ok = myfile.open(testfile, O_CREAT | O_WRITE);
  if (ok) {
    for (byte i = 1; i < 11; i++) {
    myfile.println("Test " + String(i) );
    }
  myfile.close();
  SdFile::dateTimeCallbackCancel(); // disable time call back for file write
  Serial.println("File created.");
  dir_t d;
    if(myfile.open(testfile, O_READ)) {
      if (!myfile.dirEntry(&d)) {
      Serial.println("testfile.dirEntry failed");
      }else{
      Serial.println("Reading file...");
          while (myfile.available()) {
          Serial.write(myfile.read());
          }
      Serial.print("Created "); myfile.printFatDate(d.creationDate);
      Serial.print(" "); myfile.printFatTime(d.creationTime); Serial.println();
      Serial.print("Last write "); myfile.printFatDate(d.lastWriteDate);
      Serial.print(" "); myfile.printFatTime(d.lastWriteTime); Serial.println();
      Serial.print("Accessed "); myfile.printFatDate(d.lastAccessDate);
      Serial.println();
      }
    myfile.close();
    }else Serial.println("Unable to open testfile");
  } else {
  Serial.println("Unable to create testfile");
  SdFile::dateTimeCallbackCancel(); // disable time call back for file write
  }
Serial.println();
digitalWrite(sdSelect, HIGH);   // disable sd card
digitalWrite(wifiSelect, LOW);  // enable wifi 
}

void dateTime(uint16_t* thisdate, uint16_t* thistime) { // sd callback function for time and date
time_t tnow;
struct tm lt;
time(&tnow);                      // store time in variable tnow
localtime_r(&tnow, &lt);          // place local time in lt
int myyear = lt.tm_year + 1900;
byte mymonth = lt.tm_mon + 1;
byte myday = lt.tm_mday;
byte myhour = lt.tm_hour;
byte myminute = lt.tm_min;
byte mysecond = lt.tm_sec;
// return date using FAT_DATE macro to format fields
*thisdate = FAT_DATE(myyear, mymonth, myday);
// return time using FAT_TIME macro to format fields
*thistime = FAT_TIME(myhour, myminute, mysecond);
}

boolean testSDcard() {
digitalWrite(wifiSelect, HIGH);
digitalWrite(sdSelect, LOW); // enable sd card
boolean retval = false;
  if(!sd.begin(sdSelect, SPI_FULL_SPEED)){ // SPI_HALF_SPEED SPI_FULL_SPEED
  Serial.println(F("sd.begin failed"));
  }else{
    if (!card.init(SPI_FULL_SPEED, sdSelect)){
    Serial.println(F("card.init failed!"));
    }else {
    retval = true;
    Serial.println(F("SD card ok"));
    }
  }
  if (retval) {
  Serial.print(F("\nSD Volume is FAT"));
  Serial.println(sd.vol()->fatType());
  cid_t cid;
    if (sd.card()->readCID(&cid)) {
    Serial.print(F("Manufacturer ID: Hex ")); Serial.println(cid.mid, HEX);
    Serial.print(F("OEM ID: ")); Serial.print(cid.oid[0]);Serial.println(cid.oid[1]);
    Serial.print(F("Product: "));
      for (byte i = 0; i < 5; i++) Serial.print(cid.pnm[i]);
    Serial.print(F("\nVersion ")); Serial.print(cid.prv_n);
    Serial.print("."); Serial.println(cid.prv_m);
    Serial.print(F("Serial number: Hex ")); Serial.println(cid.psn, HEX);
    Serial.print(F("Manufactured: ")); Serial.print(cid.mdt_month);
    Serial.print("/"); Serial.println(2000 + cid.mdt_year_low + 10 * cid.mdt_year_high);
    } 
  uint32_t working = sd.card()->cardSize();
    if (working != 0) {
    Serial.print(F("Capacity  ")); Serial.print(0.000512 * working + 0.5); Serial.println(F(" Mb"));
    }
  working = sd.vol()->freeClusterCount(); // volume free
  Serial.print(F("FreeSpace ")); Serial.print(0.000512*working*sd.vol()->blocksPerCluster() );
  Serial.println(F(" Mb\n"));
  }
digitalWrite(sdSelect, HIGH); // disable sd card
digitalWrite(wifiSelect, LOW);

return retval;
}

// *********************Advanced time libray functions *****************
void SolarPosition(time_t * point_in_time, double * Azimuth, double * Altitude){
time_t noon = solar_noon(point_in_time) % ONE_DAY;// time of noon mod one day
time_t tday = *point_in_time % ONE_DAY; // current time mod one day
long r = tday - noon; // offset from noon, -43200 to + 43200 seconds
double HourAngle = r / 86400.0; // hour angle as percentage of full day
HourAngle = HourAngle * 2.0 * M_PI; // hour angle in radians

double Declination = solar_declination(point_in_time);// declination in radians
AltAz( HourAngle, Declination,Azimuth,Altitude );
} 

void AltAz(double HourAngle, double Declination, double * Azimuth, double * Altitude){
extern long  __latitude;
double Latitude =  __latitude / ( ONE_DEGREE * RAD_TO_DEGREE);          // latitude in radians

double CosHourAngle = cos(HourAngle);
double SinLatitude = sin(Latitude);
double CosLatitude = cos(Latitude);

*Azimuth = atan ( sin(HourAngle) / ( CosHourAngle * SinLatitude - tan(Declination ) * CosLatitude ) );
*Altitude = asin( CosHourAngle * cos(Declination) * CosLatitude + sin(Declination) * SinLatitude );
}

void StarPosition(time_t * point_in_time, double RA, double Decl, double * Azimuth, double * Altitude){
// RA is in hours... convert to seconds
long ra = RA * ONE_HOUR;

// compute hour angle in seconds
long lst = lm_sidereal(point_in_time); 
double HourAngle = lst - ra;

// convert to radians
HourAngle *= M_PI;
HourAngle /= 43200.0;

// pass control to AltAz()
AltAz(HourAngle, Decl / RAD_TO_DEGREE, Azimuth, Altitude);
}

void MoonPosition(time_t * point_in_time, double * Azimuth, double * Altitude){
// at solar noon at new moon, moons ha is same as suns
// the ha 'elongates' as moon progresses to full

time_t noon = solar_noon(point_in_time) % ONE_DAY;// time of noon mod one day
time_t tday = *point_in_time % ONE_DAY; // current time mod one day
long r = tday - noon; // offset from noon, -43200 to + 43200 seconds
// r = HA of sun in seconds

long elongation =moon_phase(point_in_time) * -432L;

r = r + elongation;

double HourAngle = r / 86400.0; // hour angle as percentage of full day
HourAngle = HourAngle * 2.0 * M_PI; // hour angle in radians

double Declination = solar_declination(point_in_time);// declination in radians
AltAz( HourAngle, Declination,Azimuth,Altitude );
}
// *****************End Advanced time libray functions *****************
sandeepmistry commented 7 years ago

@drp0 where you thinking something like this?

/*

  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 9 Apr 2012
  by Tom Igoe

  This code is in the public domain.

*/

#include <SPI.h>
#include <WiFi101.h>

int status = WL_IDLE_STATUS;
char ssid[] = "mynetwork";  //  your network SSID (name)
char pass[] = "mypassword";       // your network password
int keyIndex = 0;            // your network key Index number (needed only for WEP)

void setup()
{
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  // check for the presence of the shield:
  if (WiFi.status() == WL_NO_SHIELD) {
    Serial.println("WiFi shield not present");
    // don't continue:
    while (true);
  }

  // attempt to connect to Wifi network:
  while ( status != WL_CONNECTED) {
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    status = WiFi.begin(ssid, pass);

    // wait 10 seconds for connection:
    delay(10000);
  }

  Serial.println("Connected to wifi");
  printWifiStatus();
}

void loop() {
  unsigned long epoch = WiFi.getTime();

  if (epoch > 0) {
    // now convert NTP time into everyday time:
    Serial.print("Unix time = ");
    // 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);
}

void printWifiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your WiFi shield's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}

I've modified the WiFiUdpNtpClient example.

drp0 commented 7 years ago

Having examined the time library at some length, there is no need to extract the time by calculation- The library does all that and more (see above) I suggest that end users will want:

1) To ignore epoch values of zero- see if (epoch == 0) continue; section above

(Thought: it may be worth increasing the timeout value for WiFiClass::getTime() )

2) a simple method of getting the time:

#define MY_TIME_ZONE 0 * ONE_HOUR           // gmt offset 0
  // The 'time zone'  parameter is given in seconds East of the Prime Meridian.
  // For New York City: -5 * ONE_HOUR
//#define MY_DST usa_dst                    // usa time saving
#define MY_DST eu_dst                       // eu  daylight time saving

set_dst(MY_DST);        // eu daylight saving in my case
set_zone(MY_TIME_ZONE); // GMT 0 in my case

set_system_time( (time_t)epoch ); 
time(&tnow); // store time in variable tnow

gmtime_r(&tnow, &gm);          // convert tnow and place GMT in gm time pointer
localtime_r(&tnow, &lt);       // place local time in lt
String ascTime = asctime(&lt); // day and month as text, based on local time

3) A method of parsing the time structure- see void showdetails

4) A method of incrementing the time, since the library does not do it automatically see timeone irq above It can take up to 60 seconds to get a valid epoch time, so repeated wifi calls are not useful!

5) A call back function to set sdcard file timestamps see void dateTime

Having chosen to base epoch time on library time.h in wifi101, good examples of the use of time.h should be given. There are no examples of time.h in the arduino release package. I am happy for you to use my examples in whole, or part.

David

sandeepmistry commented 7 years ago

@drp0 right, but time.h is not part of the Arduino libraries, it is bundled with the GCC toolchain, and part of the POSIX API.

drp0 commented 7 years ago

YiFi101 includes time.h in WiFi.cpp Having done so, there should be usable examples as detailed above.