Adding Code For Daylight Savings Time

I am making the hidden digital shelf clock from DIY Machines, I have successfully done this project, but DST breaks the clock, making me have to take the battery out of the RTC and removing all battery, waiting till midnight and then turning everything back on.

Is there a way to add 2 buttons to this easily? Or code that will change based on the timezone?

Here is the code:

/*
 * 3D printed smart shelving with a giant hidden digital clock in the front edges of the shelves - DIY Machines

==========

More info and build instructions: https://www.youtube.com/watch?v=8E0SeycTzHw

3D printed parts can be downloaded from here: https://www.thingiverse.com/thing:4207524

You will need to install the Adafruit Neopixel library which can be found in the library manager.

This project also uses the handy DS3231 Simple library:- https://github.com/sleemanj/DS3231_Simple   Please follow the instruction on installing this provided on the libraries page

Before you install this code you need to set the time on your DS3231. Once you have connected it as shown in this project and have installed the DS3231_Simple library (see above) you
 to go to  'File' >> 'Examples' >> 'DS3231_Simple' >> 'Z1_TimeAndDate' >> 'SetDateTime' and follow the instructions in the example to set the date and time on your RTC

==========


 * SAY THANKS:

Buy me a coffee to say thanks: https://ko-fi.com/diymachines
Support us on Patreon: https://www.patreon.com/diymachines

SUBSCRIBE:
■ https://www.youtube.com/channel/UC3jc4X-kEq-dEDYhQ8QoYnQ?sub_confirmation=1

INSTAGRAM: https://www.instagram.com/diy_machines/?hl=en
FACEBOOK: https://www.facebook.com/diymachines/

*/





#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#endif

#include <DS3231_Simple.h>
DS3231_Simple Clock;

// Create a variable to hold the time data 
DateTime MyDateAndTime;

// Which pin on the Arduino is connected to the NeoPixels?
#define LEDCLOCK_PIN    6
#define LEDDOWNLIGHT_PIN    5

// How many NeoPixels are attached to the Arduino?
#define LEDCLOCK_COUNT 216
#define LEDDOWNLIGHT_COUNT 12

//(red * 65536) + (green * 256) + blue ->for 32-bit merged colour value so 16777215 equals white
// or 3 hex byte 00 -> ff for RGB eg 0x123456 for red=12(hex) green=34(hex), and green=56(hex) 
// this hex method is the same as html colour codes just with "0x" instead of "#" in front
uint32_t clockMinuteColour = 0x800000; // pure red 
uint32_t clockHourColour = 0x008000;   // pure green

int clockFaceBrightness = 0;

// Declare our NeoPixel objects:
Adafruit_NeoPixel stripClock(LEDCLOCK_COUNT, LEDCLOCK_PIN, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel stripDownlighter(LEDDOWNLIGHT_COUNT, LEDDOWNLIGHT_PIN, NEO_GRB + NEO_KHZ800);
// Argument 1 = Number of pixels in NeoPixel strip
// Argument 2 = Arduino pin number (most are valid)
// Argument 3 = Pixel type flags, add together as needed:
//   NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
//   NEO_KHZ400  400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
//   NEO_GRB     Pixels are wired for GRB bitstream (most NeoPixel products)
//   NEO_RGB     Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
//   NEO_RGBW    Pixels are wired for RGBW bitstream (NeoPixel RGBW products)


//Smoothing of the readings from the light sensor so it is not too twitchy
const int numReadings = 12;

int readings[numReadings];      // the readings from the analog input
int readIndex = 0;              // the index of the current reading
long total = 0;                  // the running total
long average = 0;                // the average



void setup() {

  Serial.begin(9600);
  Clock.begin();

  stripClock.begin();           // INITIALIZE NeoPixel stripClock object (REQUIRED)
  stripClock.show();            // Turn OFF all pixels ASAP
  stripClock.setBrightness(100); // Set inital BRIGHTNESS (max = 255)
 

  stripDownlighter.begin();           // INITIALIZE NeoPixel stripClock object (REQUIRED)
  stripDownlighter.show();            // Turn OFF all pixels ASAP
  stripDownlighter.setBrightness(50); // Set BRIGHTNESS (max = 255)

  //smoothing
    // initialize all the readings to 0:
  for (int thisReading = 0; thisReading < numReadings; thisReading++) {
    readings[thisReading] = 0;
  }
  
}

void loop() {
  
  //read the time
  readTheTime();

  //display the time on the LEDs
  displayTheTime();




  //Record a reading from the light sensor and add it to the array
  readings[readIndex] = analogRead(A0); //get an average light level from previouse set of samples
  Serial.print("Light sensor value added to array = ");
  Serial.println(readings[readIndex]);
  readIndex = readIndex + 1; // advance to the next position in the array:

  // if we're at the end of the array move the index back around...
  if (readIndex >= numReadings) {
    // ...wrap around to the beginning:
    readIndex = 0;
  }

  //now work out the sum of all the values in the array
  int sumBrightness = 0;
  for (int i=0; i < numReadings; i++)
    {
        sumBrightness += readings[i];
    }
  Serial.print("Sum of the brightness array = ");
  Serial.println(sumBrightness);

  // and calculate the average: 
  int lightSensorValue = sumBrightness / numReadings;
  Serial.print("Average light sensor value = ");
  Serial.println(lightSensorValue);


  //set the brightness based on ambiant light levels
  clockFaceBrightness = map(lightSensorValue,50, 1000, 200, 1); 
  stripClock.setBrightness(clockFaceBrightness); // Set brightness value of the LEDs
  Serial.print("Mapped brightness value = ");
  Serial.println(clockFaceBrightness);
  
  stripClock.show();

   //(red * 65536) + (green * 256) + blue ->for 32-bit merged colour value so 16777215 equals white
  stripDownlighter.fill(16777215, 0, LEDDOWNLIGHT_COUNT);
  stripDownlighter.show();

  delay(5000);   //this 5 second delay to slow things down during testing

}


void readTheTime(){
  // Ask the clock for the data.
  MyDateAndTime = Clock.read();
  
  // And use it
  Serial.println("");
  Serial.print("Time is: ");   Serial.print(MyDateAndTime.Hour);
  Serial.print(":"); Serial.print(MyDateAndTime.Minute);
  Serial.print(":"); Serial.println(MyDateAndTime.Second);
  Serial.print("Date is: 20");   Serial.print(MyDateAndTime.Year);
  Serial.print(":");  Serial.print(MyDateAndTime.Month);
  Serial.print(":");    Serial.println(MyDateAndTime.Day);
}

void displayTheTime(){

  stripClock.clear(); //clear the clock face 

  
  int firstMinuteDigit = MyDateAndTime.Minute % 10; //work out the value of the first digit and then display it
  displayNumber(firstMinuteDigit, 0, clockMinuteColour);

  
  int secondMinuteDigit = floor(MyDateAndTime.Minute / 10); //work out the value for the second digit and then display it
  displayNumber(secondMinuteDigit, 63, clockMinuteColour);  


  int firstHourDigit = MyDateAndTime.Hour; //work out the value for the third digit and then display it
  if (firstHourDigit > 12){
    firstHourDigit = firstHourDigit - 12;
  }
 
 // Comment out the following three lines if you want midnight to be shown as 12:00 instead of 0:00
  if (firstHourDigit == 0){
    firstHourDigit = 12;
}
 
  firstHourDigit = firstHourDigit % 10;
  displayNumber(firstHourDigit, 126, clockHourColour);


  int secondHourDigit = MyDateAndTime.Hour; //work out the value for the fourth digit and then display it

// Comment out the following three lines if you want midnight to be shwon as 12:00 instead of 0:00
//  if (secondHourDigit == 0){
//    secondHourDigit = 12;
//  }
 
 if (secondHourDigit > 12){
    secondHourDigit = secondHourDigit - 12;
  }
    if (secondHourDigit > 9){
      stripClock.fill(clockHourColour,189, 18); 
    }

  }


void displayNumber(int digitToDisplay, int offsetBy, uint32_t colourToUse){
    switch (digitToDisplay){
    case 0:
    digitZero(offsetBy,colourToUse);
      break;
    case 1:
      digitOne(offsetBy,colourToUse);
      break;
    case 2:
    digitTwo(offsetBy,colourToUse);
      break;
    case 3:
    digitThree(offsetBy,colourToUse);
      break;
    case 4:
    digitFour(offsetBy,colourToUse);
      break;
    case 5:
    digitFive(offsetBy,colourToUse);
      break;
    case 6:
    digitSix(offsetBy,colourToUse);
      break;
    case 7:
    digitSeven(offsetBy,colourToUse);
      break;
    case 8:
    digitEight(offsetBy,colourToUse);
      break;
    case 9:
    digitNine(offsetBy,colourToUse);
      break;
    default:
     break;
  }
}

digits.ino

void digitZero(int offset, uint32_t colour){
    stripClock.fill(colour, (0 + offset), 27);
    stripClock.fill(colour, (36 + offset), 27);
}

void digitOne(int offset, uint32_t colour){
    stripClock.fill(colour, (0 + offset), 9);
    stripClock.fill(colour, (36 + offset), 9);
}

void digitTwo(int offset, uint32_t colour){
    stripClock.fill(colour, (0 + offset), 18);
    stripClock.fill(colour, (27 + offset), 9);
    stripClock.fill(colour, (45 + offset), 18);
}

void digitThree(int offset, uint32_t colour){
    stripClock.fill(colour, (0 + offset), 18);
    stripClock.fill(colour, (27 + offset), 27);
}

void digitFour(int offset, uint32_t colour){
    stripClock.fill(colour, (0 + offset), 9);
    stripClock.fill(colour, (18 + offset), 27);
}

void digitFive(int offset, uint32_t colour){
    stripClock.fill(colour, (9 + offset), 45);
}

void digitSix(int offset, uint32_t colour){
    stripClock.fill(colour, (9 + offset), 54);
}

void digitSeven(int offset, uint32_t colour){
    stripClock.fill(colour, (0 + offset), 18);
    stripClock.fill(colour, (36 + offset), 9);
}

void digitEight(int offset, uint32_t colour){
    stripClock.fill(colour, (0 + offset), 63);
}

void digitNine(int offset, uint32_t colour){
    stripClock.fill(colour, (0 + offset), 45);
}

Wiring Diagram

it looks like there are lots of free pins on your nano to use for clock adjust buttons. Your project has no concept of timezone, so that would be much more difficult.

You realize that what you posted is only part of the code, right?

That makes me doubt what to answer to your first question:

For the time being I can only say it will not be as "easy" cut and paste.

boolean DST = true;        // Pin A3 DST = LOW Std time = HIGH
uint8_t TimeZoneHour = 5;  //GMT offset

void setup()  {
  lcd.begin();
//
  
  pinMode( 18, INPUT);        // DST hi = NO low = YES
  digitalWrite( 18, HIGH);    // turn on pullup resistor

  if( digitalRead(18) ) {     // PB4 low for Daylight Savings Time
    DST = false;              // Default
  } else {
    DST = true;
    TimeZoneHour = TimeZoneHour - 1;
  }


This is all the code that he provides for this project. I have requested him to add the ability to change the time when DST occurs. But that was a year ago and no response.

How would you trigger this event?

My idea was to put 2 buttons in to adjust the hour and then the minute. But am I able to use any pin as long as I declare the pin I’m using for the button in the code? Or are there pins that I can’t use?

Why not use the TimeZone library? Then you can set the RTC to UTC time, provide your local timezone rules, and the clock will automatically change to/from DST at the appropriate times.

How would I go about doing that with the current code?

Did you look at the library? I'm not impressed with the time handling in this code. You would be better off to use the DateTime library for that.

Yes, I’ve been looking at examples and it looks to be the answer I’m looking for. I just don’t know how I would take this individuals code and add that and remove the other stuff. The way he explains to change the time is to use the setDateTime example for the RTC.

boolean DST = true;        // Pin A3 DST = LOW Std time = HIGH

Switch: toggle, push-button, even...

1 Like

And that would be wired up to pin A3? That makes sense, but how could I get that to actually change the hour on the led face? Would I just have it change the variable if it’s true and change it back if it’s false?

else {
    DST = true;
    TimeZoneHour = TimeZoneHour - 1;
  }

Just like with real tic-toc clocks, if it is Noon in London, GMT = 12, and so it would be 12-5, or 7:00 a.m. in New York unless DST = true and then it would be 12-(5-1), or 8:00 a.m. in the Eastern Time Zone.
Spring Forward, Fall Back nonsense.

Essentially, you want your clock module to run on GMT and adjust the hour in software. Just like GPS uses Universal time.

Sure. It's not a completely impractical solution if you aren't paying attention to seconds, and you can do this every few months or years, with a solid coin battery. That is the bonus of making DST automatic, you can set the RTC and forget about it. So yes, you can use a separate sketch for that.

The stand alone clocks that I built, that have no GPS or NTP time synch, are set by means of a simple interactive menu that you can access from the serial port.

I just don’t know how I would take this individuals code and add that and remove the other stuff.

Don't take this as a criticism, I just want to put you on the right track. Actually, you are saying that you don't know how to code. Because the answer is really, "by coding it". So your solution really is to learn to code. Sorry, but that's where it's at.

For a competent coder, the approach would be to:

  1. Read and understand the existing code.
  2. Decide what to keep and what to throw away.
  3. Design replacements for the thrown away code.
  4. Perform a synthesis of the kept code and new code.

WHY should you try not convert zone

Sorry, that was lost in translation.

Another way I've done this, instead of using the TimeZone library, I used the decision routine that is native to AVR C++:

https://github.com/avrdudes/avr-libc/blob/main/include/util/usa_dst.h
or
https://github.com/avrdudes/avr-libc/blob/main/include/util/eu_dst.h

Instructions for use are in the comments.

You're correct, I don't have any experience in an Arduino IDE, but I am willing to learn. That's why I made this post to take the suggestions from you guys and find the best solution and trial and error and put it into the code. I have about another 50 hours of print time to even print the components of this clock, so I have time to figure this out.

I'm not sure what you mean about print time. I'm horrified that you are considering trial and error. That is the absolute worst way to do development. The Arduino environment provides a learning path, which will get you fairly quickly to your first independent projects, but you have to be patient and follow it. Suggestions also are not sufficient to get to where you need to be. Clock applications with RTC are a really common application so there is no shortage of examples... but you need to weed out the garbage. The RTC library itself (well, a good one) already includes some good example sketches that are easy to modify for your purpose. The same thing is true of the DateTime library. So please go to original sources, competent tutorials and official documentation for answers.

The forum is not a lab, it is not a reference library, it is not a classroom.