@@ -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
112
112
DS3231 ds3231; // an object to access the ds3231 specifically (temp, etc)
113
113
RTClib rtc; // an object to access a snapshot of the ds3231 rtc via now()
114
114
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
116
116
117
117
// Hardware inputs and value setting
118
118
// AdaEncoder mainRot;
@@ -340,6 +340,7 @@ void ctrlEvt(byte ctrl, byte evt){
340
340
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."
341
341
ds3231.setMonth (fnSetValDate[1 ]);
342
342
ds3231.setDate (fnSetVal);
343
+ ds3231.setDoW (dayOfWeek (fnSetValDate[0 ],fnSetValDate[1 ],fnSetVal));
343
344
clearSet (); break ;
344
345
default : break ;
345
346
} break ;
@@ -464,6 +465,7 @@ void initEEPROM(){
464
465
ds3231.setYear (18 );
465
466
ds3231.setMonth (1 );
466
467
ds3231.setDate (1 );
468
+ ds3231.setDoW (1 ); // 2018-01-01 is Monday. DS3231 will keep count from here
467
469
ds3231.setHour (0 );
468
470
ds3231.setMinute (0 );
469
471
ds3231.setSecond (0 );
@@ -520,7 +522,17 @@ long dateToDayCount(word y, byte m, byte d){
520
522
dc += d-1 ; // every full day since start of this month
521
523
return dc;
522
524
}
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
+ }
524
536
525
537
526
538
// //////// Clock ticking and timed event triggering //////////
@@ -543,10 +555,17 @@ void checkRTC(bool force){
543
555
}
544
556
// Update things based on RTC
545
557
tod = rtc.now ();
546
- // toddow = ds3231.getDoW();
558
+ toddow = ds3231.getDoW ();
547
559
548
560
if (rtcSecLast != tod.second () || force) {
549
561
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
+ }
550
569
551
570
// trip/check for alarm TODO
552
571
// decrement timer TODO
@@ -558,6 +577,45 @@ void checkRTC(bool force){
558
577
} // end if force or new second
559
578
} // end checkRTC()
560
579
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
+ }
561
619
562
620
// //////// Display data formatting //////////
563
621
void updateDisplay (){
@@ -590,8 +648,8 @@ void updateDisplay(){
590
648
case fnIsDate:
591
649
editDisplay (EEPROM.read (optsLoc[2 ])==1 ?tod.month ():tod.day (), 0 , 1 , EEPROM.read (optsLoc[4 ]));
592
650
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?
595
653
break ;
596
654
case fnIsDayCount:
597
655
long targetDayCount; targetDayCount = dateToDayCount (
0 commit comments