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 <TimeLib.h> library
Reference [https://github.com/arduino-libraries/WiFi101/issues/111](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.
``` C++
// 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, <); // place local time in lt
date = getyear(<);
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,<);
Serial.println(isotime(<));
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, <); // place local time in lt
String ascTime = asctime(<); // 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(<);
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(<)); // 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
``` C++
// 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, <); // 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,<);
Serial.println(isotime(<));
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, <); // place local time in lt
String ascTime = asctime(<); // 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(<)); // 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(<); // 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, <); // 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 *****************
```