Skip to content

Commit 4c226b0

Browse files
committed
Fix weekday; implement automatic DST
1 parent 9291cf9 commit 4c226b0

File tree

2 files changed

+174
-5
lines changed

2 files changed

+174
-5
lines changed

sixtube_lm/sixtube_lm.ino

Lines changed: 63 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ const word optsMax[] = {0, 2, 2, 2, 1,50, 1, 6, 4,60,999, 2,1439,1439, 2, 6, 6,1
112112
DS3231 ds3231; //an object to access the ds3231 specifically (temp, etc)
113113
RTClib rtc; //an object to access a snapshot of the ds3231 rtc via now()
114114
DateTime tod; //stores the now() snapshot for several functions to use
115-
//byte toddow; //stores the day of week snapshot as now() doesn't capture it (bug report? TODO)
115+
byte toddow; //stores the day of week as calculated from tod
116116

117117
// Hardware inputs and value setting
118118
//AdaEncoder mainRot;
@@ -340,6 +340,7 @@ void ctrlEvt(byte ctrl, byte evt){
340340
ds3231.setYear(fnSetValDate[0]%100); //TODO: do we store century on our end? Per ds3231 docs, "The century bit (bit 7 of the month register) is toggled when the years register overflows from 99 to 00."
341341
ds3231.setMonth(fnSetValDate[1]);
342342
ds3231.setDate(fnSetVal);
343+
ds3231.setDoW(dayOfWeek(fnSetValDate[0],fnSetValDate[1],fnSetVal));
343344
clearSet(); break;
344345
default: break;
345346
} break;
@@ -464,6 +465,7 @@ void initEEPROM(){
464465
ds3231.setYear(18);
465466
ds3231.setMonth(1);
466467
ds3231.setDate(1);
468+
ds3231.setDoW(1); //2018-01-01 is Monday. DS3231 will keep count from here
467469
ds3231.setHour(0);
468470
ds3231.setMinute(0);
469471
ds3231.setSecond(0);
@@ -520,7 +522,17 @@ long dateToDayCount(word y, byte m, byte d){
520522
dc += d-1; //every full day since start of this month
521523
return dc;
522524
}
523-
525+
byte dayOfWeek(word y, byte m, byte d){
526+
//DS3231 doesn't really calculate the day of the week, it just keeps a counter.
527+
//When setting date, we'll calculate per https://en.wikipedia.org/wiki/Zeller%27s_congruence
528+
byte yb = y%100; //2-digit year
529+
byte ya = y/100; //century
530+
//For this formula, Jan and Feb are considered months 11 and 12 of the previous year.
531+
//So if it's Jan or Feb, add 10 to the month, and set back the year and century if applicable
532+
if(m<3) { m+=10; if(yb==0) { yb=99; ya-=1; } else yb-=1; }
533+
else m -= 2; //otherwise subtract 2 from the month
534+
return (d + ((13*m-1)/5) + yb + (yb/4) + (ya/4) + 5*ya) %7;
535+
}
524536

525537

526538
////////// Clock ticking and timed event triggering //////////
@@ -543,10 +555,17 @@ void checkRTC(bool force){
543555
}
544556
//Update things based on RTC
545557
tod = rtc.now();
546-
//toddow = ds3231.getDoW();
558+
toddow = ds3231.getDoW();
547559

548560
if(rtcSecLast != tod.second() || force) {
549561
rtcSecLast = tod.second();
562+
563+
//check for timed trips
564+
if(!force && tod.second()==0) { //new minute, not forced
565+
if(tod.minute()==0) { //new hour
566+
if(tod.hour()==2) autoDST();
567+
}
568+
}
550569

551570
//trip/check for alarm TODO
552571
//decrement timer TODO
@@ -558,6 +577,45 @@ void checkRTC(bool force){
558577
} //end if force or new second
559578
} //end checkRTC()
560579

580+
bool fellBack = false;
581+
void autoDST(){
582+
//Call daily when clock reaches 2am.
583+
//If rule matches, will set to 3am in spring, 1am in fall (and set fellBack so it only happens once)
584+
if(fellBack) { fellBack=false; return; } //If we fell back at last 2am, do nothing.
585+
if(toddow==0) { //is it sunday? currently all these rules fire on Sundays only
586+
switch(readEEPROM(optsLoc[7],false)){
587+
case 1: //second Sunday in March to first Sunday in November (US/CA)
588+
if(tod.month()==3 && tod.day()>=8 && tod.day()<=14) setDST(1);
589+
if(tod.month()==11 && tod.day()<=7) setDST(-1);
590+
break;
591+
case 2: //last Sunday in March to last Sunday in October (UK/EU)
592+
if(tod.month()==3 && tod.day()>=25) setDST(1);
593+
if(tod.month()==10 && tod.day()>=25) setDST(-1);
594+
break;
595+
case 3: //first Sunday in April to last Sunday in October (MX)
596+
if(tod.month()==4 && tod.day()<=7) setDST(1);
597+
if(tod.month()==10 && tod.day()>=25) setDST(-1);
598+
break;
599+
case 4: //last Sunday in September to first Sunday in April (NZ)
600+
if(tod.month()==9 && tod.day()>=24) setDST(1); //30 days hath September: last Sun will be 24-30
601+
if(tod.month()==4 && tod.day()<=7) setDST(-1);
602+
break;
603+
case 5: //first Sunday in October to first Sunday in April (AU)
604+
if(tod.month()==10 && tod.day()<=7) setDST(1);
605+
if(tod.month()==4 && tod.day()<=7) setDST(-1);
606+
break;
607+
case 6: //third Sunday in October to third Sunday in February (BZ)
608+
if(tod.month()==10 && tod.day()>=15 && tod.day()<=21) setDST(1);
609+
if(tod.month()==2 && tod.day()>=15 && tod.day()<=21) setDST(-1);
610+
break;
611+
default: break;
612+
} //end setting switch
613+
} //end is it sunday
614+
}
615+
void setDST(char dir){
616+
if(dir==1) ds3231.setHour(3); //could set relatively if we move away from 2am-only sets
617+
if(dir==-1 && !fellBack) { ds3231.setHour(1); fellBack=true; }
618+
}
561619

562620
////////// Display data formatting //////////
563621
void updateDisplay(){
@@ -590,8 +648,8 @@ void updateDisplay(){
590648
case fnIsDate:
591649
editDisplay(EEPROM.read(optsLoc[2])==1?tod.month():tod.day(), 0, 1, EEPROM.read(optsLoc[4]));
592650
editDisplay(EEPROM.read(optsLoc[2])==1?tod.day():tod.month(), 2, 3, EEPROM.read(optsLoc[4]));
593-
blankDisplay(4, 5);
594-
//editDisplay(toddow, 4, 4, false); //TODO is this 0=Sunday, 6=Saturday?
651+
blankDisplay(4, 4);
652+
editDisplay(toddow, 5, 5, false); //TODO is this 0=Sunday, 6=Saturday?
595653
break;
596654
case fnIsDayCount:
597655
long targetDayCount; targetDayCount = dateToDayCount(

weekday_test/weekday_test.ino

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
// #include <EEPROM.h>
2+
3+
// #include <Wire.h>
4+
// #include <DS3231.h>
5+
// DS3231 ds3231;
6+
// RTClib rtc;
7+
// DateTime tod;
8+
// byte toddow;
9+
10+
////////// Main code control //////////
11+
12+
void setup(){
13+
Serial.begin(9600);
14+
//Wire.begin();
15+
//ds3231.setDate(2);
16+
Serial.println();
17+
testDate(1900,1,1);
18+
testDate(1985,10,7);
19+
testDate(1996,2,15);
20+
testDate(1996,3,15);
21+
testDate(1997,2,15);
22+
testDate(1997,3,15);
23+
testDate(2000,2,15);
24+
testDate(2000,3,15);
25+
testDate(2018,3,8);
26+
testDate(2018,3,9);
27+
testDate(2018,3,10);
28+
testDate(2018,3,11);
29+
testDate(2018,3,12);
30+
testDate(2018,3,13);
31+
testDate(2018,3,14);
32+
testDate(2018,3,15);
33+
testDate(2040,3,15);
34+
}
35+
36+
byte testDate(word y, byte m, byte d){
37+
Serial.print(y,DEC);
38+
Serial.print("-");
39+
Serial.print(m,DEC);
40+
Serial.print("-");
41+
Serial.print(d,DEC);
42+
Serial.print(" is ");
43+
Serial.println(dayOfWeek(y,m,d),DEC);
44+
}
45+
46+
47+
byte dayOfWeek(word y, byte m, byte d){
48+
//DS3231 doesn't really calculate the day of the week, it just keeps a counter.
49+
//We'll calculate per https://en.wikipedia.org/wiki/Zeller%27s_congruence
50+
byte yb = y%100; //2-digit year
51+
byte ya = y/100; //century
52+
//For this formula, Jan and Feb are considered months 11 and 12 of the previous year.
53+
//So if it's Jan or Feb, add 10 to the month, and set back the year and century if applicable
54+
if(m<3) { m+=10; if(yb==0) { yb=99; ya-=1; } else yb-=1; }
55+
else m -= 2; //otherwise subtract 2 from the month
56+
return (d + ((13*m-1)/5) + yb + (yb/4) + (ya/4) + 5*ya) %7;
57+
}
58+
59+
void loop(){
60+
//Things done every "clock cycle"
61+
//checkRTC(); //if clock has ticked, decrement timer if running, and updateDisplay
62+
}
63+
64+
////////// Clock ticking and timed event triggering //////////
65+
unsigned long rtcPollLast = 0; //maybe don't poll the RTC every loop? would that be good?
66+
byte rtcSecLast = 61;
67+
bool h12=false;
68+
bool PM=false;
69+
bool century=false;
70+
void checkRTC(){
71+
// //Checks for new time-of-day second; decrements timer; checks for timed events;
72+
// //updates display for running time or date.
73+
// if(rtcPollLast<millis()+50) { //check every 1/20th of a second
74+
// rtcPollLast=millis();
75+
// //Check for timeouts based on millis
76+
// //Update things based on RTC
77+
// tod = rtc.now();
78+
// toddow = ds3231.getDoW();
79+
//
80+
// if(rtcSecLast != tod.second()) {
81+
// rtcSecLast = tod.second();
82+
// Serial.print("It is now ");
83+
// Serial.print(tod.year(),DEC);
84+
// Serial.print("-");
85+
// Serial.print(tod.month(),DEC);
86+
// Serial.print("-");
87+
// Serial.print(tod.day(),DEC);
88+
// Serial.print(" ");
89+
// Serial.print(tod.hour(),DEC);
90+
// Serial.print(":");
91+
// Serial.print(tod.minute(),DEC);
92+
// Serial.print(":");
93+
// Serial.print(tod.second(),DEC);
94+
// Serial.print(" --or-- ");
95+
// Serial.print(ds3231.getYear(),DEC);
96+
// Serial.print("-");
97+
// Serial.print(ds3231.getMonth(century),DEC);
98+
// Serial.print("-");
99+
// Serial.print(ds3231.getDate(),DEC);
100+
// Serial.print(" (");
101+
// Serial.print(ds3231.getDoW(),DEC);
102+
// Serial.print(") ");
103+
// Serial.print(ds3231.getHour(h12,PM),DEC);
104+
// Serial.print(":");
105+
// Serial.print(ds3231.getMinute(),DEC);
106+
// Serial.print(":");
107+
// Serial.print(ds3231.getSecond(),DEC);
108+
// Serial.println();
109+
// }
110+
// }
111+
}

0 commit comments

Comments
 (0)