Modifying Code for DST

Hi everyone.

I did a project for my 3d printer that created a clock. The person did posted the project lives in Europe and has their day light savings set for them, not myself in the US. I've never done something like this before and I'd like to try to modify the code to work with US Time.

Code is listed below. Any pointers would be greatly appreciated.

#include "TM1637Display.h"
#include "Adafruit_NeoPixel.h"
#include "NTPClient.h"
#include "WiFiManager.h"


// Which pin on the Arduino is connected to the NeoPixels?
#define PIN        17
#define display_CLK 18
#define display_DIO 19

// How many NeoPixels are attached to the Arduino?
#define NUMPIXELS 35


//========================USEFUL VARIABLES=============================
int UTC = -4; // UTC = value in hour (SUMMER TIME) [For example: Paris UTC+2 => UTC=2]
int Display_backlight = 3; // Adjust it 0 to 7
int led_ring_brightness = 50; // Adjust it 0 to 255
int led_ring_brightness_flash = 250; // Adjust it 0 to 255

// ========================================================================
// ========================================================================

const long utcOffsetInSeconds = 3600; // UTC + 1H / Offset in second

// Adjust the color of the led ring
#define red 00
#define green 20
#define blue 255

// When setting up the NeoPixel library, we tell it how many pixels,
Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
TM1637Display display(display_CLK, display_DIO);
int flag = 0;
int Hour = 0;

// Define NTP Client to get time
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", utcOffsetInSeconds*UTC);
bool res;

void setup() {

  pinMode(25, OUTPUT);
  pinMode(26, OUTPUT);

  Serial.begin(115200);
  Serial.println("\n Starting");

  WiFiManager manager;   

  //manager.resetSettings();

  manager.setTimeout(180);
  //fetches ssid and password and tries to connect, if connections succeeds it starts an access point with the name called "IRON_MAN_ARC" and waits in a blocking loop for configuration
  res = manager.autoConnect("IRON_MAN_ARC","password");
  
  if(!res) {
  Serial.println("failed to connect and timeout occurred");
  ESP.restart(); //reset and try again
  }

  timeClient.begin();
  display.setBrightness(Display_backlight);
  pixels.begin(); // INITIALIZE NeoPixel pixels object
  pixels.setBrightness(led_ring_brightness);
  

  for(int i=0; i<35;i++){
  pixels.setPixelColor(i, pixels.Color(red, green, blue));
  pixels.show();
  delay(50);
  }

  flash_cuckoo();// white flash

}

void loop() {

  // Update the time
  timeClient.update();

  Serial.print("Time: ");
  Serial.println(timeClient.getFormattedTime());
  unsigned long epochTime = timeClient.getEpochTime();
  struct tm *ptm = gmtime ((time_t *)&epochTime); 
  int currentYear = ptm->tm_year+1900;
  Serial.print("Year: ");
  Serial.println(currentYear);
  
  int monthDay = ptm->tm_mday;
  Serial.print("Month day: ");
  Serial.println(monthDay);

  int currentMonth = ptm->tm_mon+1;
  Serial.print("Month: ");
  Serial.println(currentMonth);

  if((currentMonth*30 + monthDay) >= 121 && (currentMonth*30 + monthDay) < 331){
  timeClient.setTimeOffset(utcOffsetInSeconds*UTC);} // Change daylight saving time - Summer
  else {timeClient.setTimeOffset((utcOffsetInSeconds*UTC) - 3600);} // Change daylight saving time - Winter

  // switch on the ring in blue
  pixels.clear(); // Set all pixel colors to 'off'
  blue_light();
 if (timeClient.getHours() == 0)
  { 
    Hour = 12;
    Serial.write(" =0");
  }

  else if (timeClient.getHours() == 12)
  { 
    Hour = timeClient.getHours();
    Serial.write(" =12");
  }
  
  else if (timeClient.getHours() >= 13) {
    Hour = timeClient.getHours() - 12;
    Serial.write(" >=13");
  }

  else {
    Hour = timeClient.getHours();
  }

  // write the time on the display
  display.showNumberDecEx(Hour,0b01000000,true,2,0);
  display.showNumberDecEx(timeClient.getMinutes(),0b01000000,true,2,2);

  // switch on the blue leds
  digitalWrite(25,1);
  digitalWrite(26,1);

  // Animation every hour
  if(timeClient.getMinutes()== 00 && flag==0)
  {
    display_cuckoo();
    flag=1;
  }
   if(timeClient.getMinutes()>=01)
  {
    flag=0;
  }



}

void blue_light(){

  pixels.setBrightness(led_ring_brightness);
  pixels.setPixelColor(0, pixels.Color(red, green, blue));
  pixels.setPixelColor(1, pixels.Color(red, green, blue));
  pixels.setPixelColor(2, pixels.Color(red, green, blue));
  pixels.setPixelColor(3, pixels.Color(red, green, blue));
  pixels.setPixelColor(4, pixels.Color(red, green, blue));
  pixels.setPixelColor(5, pixels.Color(red, green, blue));
  pixels.setPixelColor(6, pixels.Color(red, green, blue));
  pixels.setPixelColor(7, pixels.Color(red, green, blue));
  pixels.setPixelColor(8, pixels.Color(red, green, blue));
  pixels.setPixelColor(9, pixels.Color(red, green, blue));
  pixels.setPixelColor(10, pixels.Color(red, green, blue));
  pixels.setPixelColor(11, pixels.Color(red, green, blue));
  pixels.setPixelColor(12, pixels.Color(red, green, blue));
  pixels.setPixelColor(13, pixels.Color(red, green, blue));
  pixels.setPixelColor(14, pixels.Color(red, green, blue));
  pixels.setPixelColor(15, pixels.Color(red, green, blue));
  pixels.setPixelColor(16, pixels.Color(red, green, blue));
  pixels.setPixelColor(17, pixels.Color(red, green, blue));
  pixels.setPixelColor(18, pixels.Color(red, green, blue));
  pixels.setPixelColor(19, pixels.Color(red, green, blue));
  pixels.setPixelColor(20, pixels.Color(red, green, blue));
  pixels.setPixelColor(21, pixels.Color(red, green, blue));
  pixels.setPixelColor(22, pixels.Color(red, green, blue));
  pixels.setPixelColor(23, pixels.Color(red, green, blue));
  pixels.setPixelColor(24, pixels.Color(red, green, blue));
  pixels.setPixelColor(25, pixels.Color(red, green, blue));
  pixels.setPixelColor(26, pixels.Color(red, green, blue));
  pixels.setPixelColor(27, pixels.Color(red, green, blue));
  pixels.setPixelColor(28, pixels.Color(red, green, blue));
  pixels.setPixelColor(29, pixels.Color(red, green, blue));
  pixels.setPixelColor(30, pixels.Color(red, green, blue));
  pixels.setPixelColor(31, pixels.Color(red, green, blue));
  pixels.setPixelColor(32, pixels.Color(red, green, blue));
  pixels.setPixelColor(33, pixels.Color(red, green, blue));
  pixels.setPixelColor(34, pixels.Color(red, green, blue));
  pixels.setPixelColor(35, pixels.Color(red, green, blue));
  pixels.show(); 

}

void flash_cuckoo(){
	pixels.setBrightness(led_ring_brightness_flash);
    pixels.setPixelColor(0, pixels.Color(250,250,250));
    pixels.setPixelColor(1, pixels.Color(250,250,250));
    pixels.setPixelColor(2, pixels.Color(250,250,250));
    pixels.setPixelColor(3, pixels.Color(250,250,250));
    pixels.setPixelColor(4, pixels.Color(250,250,250));
    pixels.setPixelColor(5, pixels.Color(250,250,250));
    pixels.setPixelColor(6, pixels.Color(250,250,250));
    pixels.setPixelColor(7, pixels.Color(250,250,250));
    pixels.setPixelColor(8, pixels.Color(250,250,250));
    pixels.setPixelColor(9, pixels.Color(250,250,250));
    pixels.setPixelColor(10, pixels.Color(250,250,250));
    pixels.setPixelColor(11, pixels.Color(250,250,250));
    pixels.setPixelColor(12, pixels.Color(250,250,250));
    pixels.setPixelColor(13, pixels.Color(250,250,250));
    pixels.setPixelColor(14, pixels.Color(250,250,250));
    pixels.setPixelColor(15, pixels.Color(250,250,250));
    pixels.setPixelColor(16, pixels.Color(250,250,250));
    pixels.setPixelColor(17, pixels.Color(250,250,250));
    pixels.setPixelColor(18, pixels.Color(250,250,250));
    pixels.setPixelColor(19, pixels.Color(250,250,250));
    pixels.setPixelColor(20, pixels.Color(250,250,250));
    pixels.setPixelColor(21, pixels.Color(250,250,250));
    pixels.setPixelColor(22, pixels.Color(250,250,250));
    pixels.setPixelColor(23, pixels.Color(250,250,250));
    pixels.setPixelColor(24, pixels.Color(250,250,250));
    pixels.setPixelColor(25, pixels.Color(250,250,250));
    pixels.setPixelColor(26, pixels.Color(250,250,250));
    pixels.setPixelColor(27, pixels.Color(250,250,250));
    pixels.setPixelColor(28, pixels.Color(250,250,250));
    pixels.setPixelColor(29, pixels.Color(250,250,250));
    pixels.setPixelColor(30, pixels.Color(250,250,250));
    pixels.setPixelColor(31, pixels.Color(250,250,250));
    pixels.setPixelColor(32, pixels.Color(250,250,250));
    pixels.setPixelColor(33, pixels.Color(250,250,250));
    pixels.setPixelColor(34, pixels.Color(250,250,250));
    pixels.setPixelColor(35, pixels.Color(250,250,250));
    pixels.show();

  for (int i=led_ring_brightness_flash; i>10 ; i--){
  pixels.setBrightness(i);
  pixels.show();
  delay(7);
  }
  blue_light();

}

void display_cuckoo(){

for (int i =0 ; i<88 ; i++)
{
  display.showNumberDecEx(i,0b01000000,true,2,0);
  display.showNumberDecEx(i,0b01000000,true,2,2);
}

display.showNumberDecEx(88,0b01000000,true,2,0);
display.showNumberDecEx(88,0b01000000,true,2,2);
flash_cuckoo();
delay(2000);

}


This line sets the two switch-over dates in spring and autumn (fall).
Day 221 and day 331 of the year.

Which Arduino are you using.
This is old code for an ESP8266 or ESP32.
There is now much easier code for those boards.
See this ESP32 example, with automatic DST for Chicago (click on link to change location).
Leo..

#include <WiFi.h> // ESP32
unsigned long prevTime;
time_t now; // epoch
tm tm; // time struct

void setup() {
  Serial.begin(115200);
  WiFi.begin("SSID", "PW"); // your WiFi credentials
  configTime(0, 0, "pool.ntp.org");
  setenv("TZ", "CST6CDT,M3.2.0,M11.1.0", 1); // Chicago
  tzset(); // https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv
}

void loop() {
  time(&now);
  localtime_r(&now, &tm);
  if (now != prevTime) {
    prevTime = now;
    printf("\n%02u:%02u:%02u", tm.tm_hour, tm.tm_min, tm.tm_sec);
  }
}

Yeah I could make out where the designer was using the exact days because apparently France they are much more standardized where the US is not a set day each year.

The board I am using is a D1 Mini ESP32 ESP-WROOM-32 WLAN WiFi+Bluetooth.

So using that code I would have to take out a lot of what he did and I'm not sure what I'll break when doing that. I am in EST5EDT,M3.2.0,M11.1.0

I am using the wifi manager library as I am making this for some friends and want to allow them to configure to their wifi when I give it to them. I see you're example uses hard coded wifi SSID and PW.

Sorry I am a totally new at this.

It's on a Sunday (day 0) of a fixed week of a fixed month.
I think your current code will be taking care of that in the background.

The DST line does the same.
M11.1.0 means month 11, week 1, day 0.

Adding WiFi manager is easy. The basics is only a few lines more. This sketch will likely instantly work on your ESP32, because your SSID/PW are already stored.
See this page (click) if you also want to display month/year/etc.
Leo..

#include <WiFi.h> // ESP32
#include <WiFiManager.h>
unsigned long prevTime;
time_t now; // epoch
tm tm; // time struct

void setup() {
  Serial.begin(115200);

  configTime(0, 0, "pool.ntp.org");
  setenv("TZ", "EST5EDT,M3.2.0,M11.1.0", 1); // location
  tzset(); // https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv

  WiFi.mode(WIFI_STA);
  WiFiManager manager;
  manager.autoConnect("IRON_MAN_ARC", "password");
}

void loop() {
  // update time
  time(&now); // get epoch
  localtime_r(&now, &tm); // add local offset

  // print
  if (now != prevTime) { // if time has changed
    prevTime = now; // remember
    printf("\n%02u:%02u:%02u", tm.tm_hour, tm.tm_min, tm.tm_sec);
  }
}

There's a one-line variant that combines those

  configTzTime("CST6CDT,M3.2.0,M11.1.0", "pool.ntp.org");

In fact, when you pass the two numbers instead, configTime calls another function to construct a TZ string and use it. So with the three-line approach, it is set twice. More importantly, the one-line updated the time within a few seconds, while the three-line consistently took 30 seconds to take effect, at least for the board I have. Didn't dig enough to find out why.

1 Like

Thanks. Will try that single line in my next clock project.

I turn off WiFi between NTP updates.
Then force sntp to restart when an update is due.
Then it only takes about three seconds to update.

  WiFi.begin();
  sntp_restart();

I use the following code in a clock with 12 (3x4) 8*8 matrix displays.
Updates NTP twice a day instead of the default hourly update. Turns WiFi off between updates. Has a sunset/rise code for dimming, and a temp sensor. And a WiFi portal.
Maybe parts of the code are useful.
Leo..

// NTP clock, tested on ESP32-C3 SuperMini, default SPI pins: CLK GPIO_4, Din GPIO_6, CS set to GPIO_7
#include <WiFi.h>
#include <WiFiManager.h> // https://github.com/tzapu/WiFiManager
#include "esp_sntp.h"
#include <MD_Parola.h> // all libraries installed through library manager
#include <MD_MAX72xx.h> //  // powered from 5volt pin, optional 1000uF+ smoothing cap on matrix supply
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW // change if gobbledygook
MD_Parola P = MD_Parola(HARDWARE_TYPE, 7, 12); // CS pin, 12(3*4) MAX72xx devices
const char * wDay[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
#include <OneWire.h> // Paul Stoffregen
#include <DallasTemperature.h> // Miles Burton
const int oneWireBus = 8; // GPIO_8
OneWire oneWire(oneWireBus);
DallasTemperature sensors(&oneWire);
#include <SolarCalculator.h> // jpb10
const float latitude = -45.89854; // negative for southern hemisphere, DecimalDegrees
const float longitude = 170.38657; // positive for east of Greenwich
double az, el; // azimuth, elevation
const int nightBrightness = 1; // min 1
const int dayBrightness = 10; // max 15
int brightness, prevBrightness;
unsigned long prevMillis, prevTime, interval = 4e7; // ~11 hours
bool reSync, nap;
time_t now; // epoch
tm tm; // time struct
char dateStr[6];
char timeStr[9];
char tempStr[4];

void cbSyncTime(struct timeval *tv) { // sync callback
  reSync = true;
}

void setup() {
  pinMode(oneWireBus, INPUT_PULLUP);
  sensors.begin();
  sensors.requestTemperatures(); // pre-read
  sensors.setWaitForConversion(false);
  P.begin(4); // nb zones
  P.setZone(0, 0, 11); // full
  P.setZone(1, 0, 1); // temp
  P.setZone(2, 2, 7); // time
  P.setZone(3, 8, 11); // date
  P.displayZoneText(0, "> > > Connecting > > >", PA_CENTER, 0, 0, PA_PRINT, PA_NO_EFFECT);
  P.displayAnimate(); // write to display
  sntp_set_time_sync_notification_cb(cbSyncTime); // enable callback
  configTzTime("NZST-12NZDT,M9.5.0,M4.1.0/3", "nz.pool.ntp.org"); // https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv
  WiFi.mode(WIFI_STA);
  WiFiManager wm;
  wm.setConnectTimeout(120); // timeout before portal starts (power cut)
  wm.setConfigPortalTimeout(60); // portal active period (safety)
  wm.autoConnect("Portal"); // open, 192.168.4.1
  while (!reSync) yield(); // wait here for a valid time string
}

void loop() {
  time(&now); // load epoch
  localtime_r(&now, &tm); // add local offset
  if (now != prevTime) { // if time has changed
    prevTime = now; // remember
    if (tm.tm_hour == 23 && tm.tm_min == 00 && tm.tm_sec == 00) P.setIntensity(0); // full dim at 23:00
    calcHorizontalCoordinates(now, latitude, longitude, az, el); // calculate sun angle
    brightness = map(el * 100, -400, 200, nightBrightness, dayBrightness); // floats x 100 for higher resolution, then cast to int by map
    brightness = constrain (brightness, nightBrightness, dayBrightness); // limit range
    if (brightness != prevBrightness) { // if changed
      P.setIntensity(brightness); // set
      prevBrightness = brightness; // remember
    }
    sprintf(dateStr, "%s\xA0%02u", wDay[tm.tm_wday], tm.tm_mday); // no-break space (smaller)
    P.displayZoneText(3, dateStr, PA_LEFT, 0, 0, PA_PRINT, PA_NO_EFFECT);
    if (nap) sprintf(timeStr, " %02u:%02u:%02u", tm.tm_hour, tm.tm_min, tm.tm_sec);
    else sprintf(timeStr, " %02u:%02u", tm.tm_hour, tm.tm_min);
    P.displayZoneText(2, timeStr, PA_LEFT, 0, 0, PA_PRINT, PA_NO_EFFECT);
    if (!(now & 0b1111)) { // every 16 seconds
      int tempC = sensors.getTempCByIndex(0);
      sprintf(tempStr, "%i\xB0", tempC); // degree symbol
      P.displayZoneText(1, tempStr, PA_RIGHT, 0, 0, PA_PRINT, PA_NO_EFFECT);
      sensors.requestTemperatures(); // async update
    }
    P.displayAnimate(); // write to display
    if (nap && millis() - prevMillis > interval) { // time to synchronise?
      nap = false;
      WiFi.begin();
      sntp_restart(); // force
    }
    if (reSync) { // when done
      reSync = false;
      nap = true;
      prevMillis = millis();
      WiFi.mode(WIFI_OFF);
    }
  }
  delay(1); // lower current draw?
}

Edit: used the single line successfully.

I got it to work I believe.

I tried using the one line setup that kenb4 listed but it never would work. Not sure.
I posted my code below using Wawa's method which worked.
Maybe see where I went wrong using Ken's method?
I just swapped the 3 lines for his single one and it always defaulted to a time of 1900 hours.

#include <WiFi.h> // ESP32
#include <WiFiManager.h>
#include "TM1637Display.h"
#include "Adafruit_NeoPixel.h"

#define PIN        17
#define display_CLK 18
#define display_DIO 19

#define NUMPIXELS 35

int UTC = -4; // UTC = value in hour (SUMMER TIME) [For example: Paris UTC+2 => UTC=2]
int Display_backlight = 3; // Adjust it 0 to 7
int led_ring_brightness = 50; // Adjust it 0 to 255
int led_ring_brightness_flash = 250; // Adjust it 0 to 255

// When setting up the NeoPixel library, we tell it how many pixels,
Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
TM1637Display display(display_CLK, display_DIO);
int flag = 0;
int Hour = 0;

unsigned long prevTime;
time_t now; // epoch
tm tm; // time struct

void setup() {
  Serial.begin(115200);

  configTime(0, 0, "pool.ntp.org");
  setenv("TZ", "EST5EDT,M3.2.0,M11.1.0", 1); // location
  tzset(); // https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv

  WiFi.mode(WIFI_STA);
  WiFiManager manager;
  manager.autoConnect("IRON_MAN_ARC", "password");
}

void loop() {
  // update time
  time(&now); // get epoch
  localtime_r(&now, &tm); // add local offset

  // print
  if (now != prevTime) { // if time has changed
    prevTime = now; // remember
    printf("\n%02u:%02u:%02u", tm.tm_hour, tm.tm_min, tm.tm_sec);
    
  }

  if (tm.tm_hour == 0)
  { 
    Hour = 12;
    Serial.write(" =0");
  }

  else if (tm.tm_hour == 12)
  { 
    Hour = tm.tm_hour;
    Serial.write(" =12");
  }
  
  else if (tm.tm_hour >= 13) {
    Hour = tm.tm_hour - 12;
    Serial.write(" >=13");
  }

  else {
    Hour = tm.tm_hour;
  }

  // write the time on the display

  // write the time on the display
  display.setBrightness(Display_backlight);
  display.showNumberDecEx(Hour,0b01000000,true,2,0);
  display.showNumberDecEx(tm.tm_min,0b01000000,true,2,2);
}


This if statement runs when time (seconds) has changed.
It makes sense to put the rest of the loop() code inside this if statement.

Post the single-line NTP code. It seems to work fine in my clock.
Leo..

Note that I'm using callback, which waits until a valid NTP string has been received.
These are the elements of it.
Leo..

#include "esp_sntp.h"
bool reSync;

void cbSyncTime(struct timeval *tv) { // sync callback
  reSync = true;
}

void setup() {
  sntp_set_time_sync_notification_cb(cbSyncTime); // enable callback

  while (!reSync) yield(); // wait here for a valid time string
}

Here is the single line code that didn't work for me.

#include <WiFi.h> // ESP32
#include <WiFiManager.h>
#include "TM1637Display.h"
#include "Adafruit_NeoPixel.h"

#define PIN        17
#define display_CLK 18
#define display_DIO 19

#define NUMPIXELS 35

int UTC = -4; // UTC = value in hour (SUMMER TIME) [For example: Paris UTC+2 => UTC=2]
int Display_backlight = 3; // Adjust it 0 to 7
int led_ring_brightness = 50; // Adjust it 0 to 255
int led_ring_brightness_flash = 250; // Adjust it 0 to 255

// When setting up the NeoPixel library, we tell it how many pixels,
Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
TM1637Display display(display_CLK, display_DIO);
int flag = 0;
int Hour = 0;

unsigned long prevTime;
time_t now; // epoch
tm tm; // time struct

void setup() {
  Serial.begin(115200);

  configTzTime("CST6CDT,M3.2.0,M11.1.0", "pool.ntp.org");

  WiFi.mode(WIFI_STA);
  WiFiManager manager;
  manager.autoConnect("IRON_MAN_ARC", "password");
}

void loop() {
  // update time
  time(&now); // get epoch
  localtime_r(&now, &tm); // add local offset

  // print
  if (now != prevTime) { // if time has changed
    prevTime = now; // remember
    printf("\n%02u:%02u:%02u", tm.tm_hour, tm.tm_min, tm.tm_sec);
    
  }

  if (tm.tm_hour == 0)
  { 
    Hour = 12;
    Serial.write(" =0");
  }

  else if (tm.tm_hour == 12)
  { 
    Hour = tm.tm_hour;
    Serial.write(" =12");
  }
  
  else if (tm.tm_hour >= 13) {
    Hour = tm.tm_hour - 12;
    Serial.write(" >=13");
  }

  else {
    Hour = tm.tm_hour;
  }

  // write the time on the display

  // write the time on the display
  display.setBrightness(Display_backlight);
  display.showNumberDecEx(Hour,0b01000000,true,2,0);
  display.showNumberDecEx(tm.tm_min,0b01000000,true,2,2);
}


Code seems ok.
Did you wait long enough. A first time sync can take up to a minute.
That's why I added a callback, to wait for a proper time sync.
Leo..

int UTC = -4 has no function, and can be deleted.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.