As we still haven't got rid of this antiquated requirement of adjusting our clocks twice
every year, and as I have a few real-time clocks attached to various mini-projects that
have to be reset every time this happens. I decided it was time to automate this process
a little, using an ESP8266 Node-MCU12-E and I2C.
The wiring is simple:
ESP8266 >>> DS3231
D2 >>> SDA
D1 >>> SCL
G >>> GND
3 >>> VCC
The following code reads the contents of the first 7 DS3231 registers. Then it gets
the current GMT/UTC time from a Network Time Server and performs a local time conversion.
Then it writes the new time to the DS3231 registers and rereads the registers back
to the serial monitor to confirm that the DS3231 has been updated.
/* * KEYWORDS: DS3231, ESP8266, NodeMCU-12E, NTP */ #include <Wire.h> #include <ESP8266WiFi.h> #include <NTPClient.h> #include <WiFiUdp.h> #define bcd2dec(bcd_in) (bcd_in >> 4) * 10 + (bcd_in & 0x0f) #define dec2bcd(dec_in) ((dec_in / 10) << 4) + (dec_in % 10) // Replace with your network credentials const char* ssid = "your_ssid"; const char* password = "your_password"; // Define NTP Client to get time WiFiUDP ntpUDP; NTPClient timeClient(ntpUDP, "pool.ntp.org"); byte mByte[0x07]; // holds the array from the DS3231 register byte tByte[0x07]; // holds the array from the NTP server // change the values here to suit your timezone const long gmtOffset = 3600; // 3600 seconds is +1 hours const long summerTimeOffset = 3600; // change to 0 in winter //Week Days String weekDay[7]={"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; //Month names String month[12]={"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"}; void setup(){ Serial.begin(115200); while(!Serial){} // Wait for serial connection Wire.begin(); // set up wireless internet connection Serial.print("Connecting to "); Serial.println(ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println("\n"); // Initialize a NTPClient to get the time timeClient.begin(); // Set offset time in seconds to adjust for your timezone, for example: // GMT +1 = 3600 // GMT +8 = 28800 // GMT -1 = -3600 // add another 3600 for Summertime if appropriate // GMT 0 = 0 // Example CET = GMT/UTC+1 and CEST = GMT/UTC+2 i.e. 2 x 3600 = 7200 timeClient.setTimeOffset(gmtOffset + summerTimeOffset); //Central European Summer Time //get current time from the RTC registers and store in the mByte[] array Serial.println(F("Old DS3231 register content........\n")); getRTCdatetime(); // get the datetime from the NTP server timeClient.update(); unsigned long epochTime = timeClient.getEpochTime(); tByte[0] = (int)timeClient.getSeconds(); tByte[1] = (int)timeClient.getMinutes(); tByte[2] = (int)timeClient.getHours(); tByte[3] = (int)timeClient.getDay(); // create a struct to hold date, month and year values struct tm *ptm = gmtime ((time_t *)&epochTime); tByte[4] = (int)ptm->tm_mday; tByte[5] = (int)ptm->tm_mon+1; tByte[6] = (int)ptm->tm_year-100; Serial.print(F("NTP Webtime..........\n\n")); Serial.print("Seconds: "); Serial.println(tByte[0]); Serial.print("Minutes: "); Serial.println(tByte[1]); Serial.print("Hours: "); Serial.println(tByte[2]); Serial.print("DoW: "); Serial.println(weekDay[tByte[3]]); Serial.print("Day: "); Serial.println(tByte[4]); Serial.print("Month: "); Serial.println(month[tByte[5]-1]); Serial.print("Year: "); Serial.println(tByte[6]); Serial.print("\n"); /* if the time stored in the DS3231 register does not match * the time retrieved from the NTP server, update the DS3231 * register to the current time. */ if(mByte != tByte){ Wire.beginTransmission (0x68); // Set device to start read reg 0 Wire.write (0x00); for (int idx = 0; idx < 7; idx++){ Wire.write (dec2bcd(tByte[idx])); } Wire.endTransmission (); } Serial.println(F("New DS3231 register content........\n")); getRTCdatetime(); } void loop() {} void getRTCdatetime(){ Wire.beginTransmission (0x68); // Set device to start read reg 0 Wire.write (0x00); Wire.endTransmission (); // request 7 bytes from the DS3231 and release the I2C bus Wire.requestFrom(0x68, 0x07, true); int idx = 0; // read the first seven bytes from the DS3231 module into the array while(Wire.available()) { byte input = Wire.read(); // read each byte from the register mByte[idx] = input; // store each single byte in the array idx++; } // display the current values to the serial monitor Serial.print(F("Register[0] Seconds: ")); Serial.println(bcd2dec(mByte[0])); Serial.print(F("Register[1] Minutes: ")); Serial.println(bcd2dec(mByte[1])); Serial.print(F("Register[2] Hours: ")); Serial.println(bcd2dec(mByte[2])); Serial.print(F("Register[3] DoW: ")); Serial.println(weekDay[bcd2dec(mByte[3])]); Serial.print(F("Register[4] Day: ")); Serial.println(bcd2dec(mByte[4])); Serial.print(F("Register[5] Month: ")); Serial.println(month[bcd2dec(mByte[5]-1)]); Serial.print(F("Register[6] Year: ")); Serial.println(bcd2dec(mByte[6])); Serial.println("\n"); }
I am pretty sure that porting this code to an ESP32, would be reasonably straightforward.
Thats a very good idea indeed. Duly noted and copied to my snippets files 😀. Thanks for sharing.
ah! this is close to what i am trying to achieve in This Post. i will try and work out how to make this fit my project but i am very new to it all. Thanks for posting it!
How does the summertime adjust work. I am on the east coast USA and time.gov says my offset is -4 hrs from UTC in April (EDST). If I use -10800 for offset(3 hrs), and -3600 (1 hr) for summertime adjust, I get the proper time on clock. Will this automatically correct in November?
@royz With any luck, we will be rid of the DST before next November as the US has finally passed the Federal enabling legislation. Now, it is up to the State and, in Canada, the Provincial authorities to make it happen. I know on the west coast that all the players, namely CA, OR, WA, and BC, have an interest in being on the same time due to cross-border trading, I assume equally so on the east coast, but that involves a great deal more players and politicians being what they are will need to be voted out until all players are agreeable. Just because the public wants something doesn't mean we get it, that would be a democracy, and neither country is that close to that lofty goal. In the meantime, seasonal adjustments are not universally supported by the RTC chips themselves. Some may have onboard logic to do that, but generally, it is up to the supporting libraries to do that, and you probably need to seed the library with either a reliable time server like NTP or a GPS source.
First computer 1959. Retired from my own computer company 2004.
Hardware - Expert in 1401, and 360, fairly knowledge in PC plus numerous MPU's and MCU's
Major Languages - Machine language, 360 Macro Assembler, Intel Assembler, PL/I and PL1, Pascal, Basic, C plus numerous job control and scripting languages.
My personal scorecard is now 1 PC hardware fix (circa 1982), 1 open source fix (at age 82), and 2 zero day bugs in a major OS.
On reconsideration, Eastern US is -5 hrs vs GMT. Therefore I believe I should use -18000 for time zone off set and +3600 for summer offset which will result in 4 hrs? If DST is not made permanent, my clocks will hopefully correct if have to "fall back"?
@royz The more self-documenting way to do that is via 2 variables, one for Time Zone commonly named TMZ or perhaps UTC_Offset and another called DST. This way TMZ is tied to your longitude and normally does not change unless you are in a moving vehicle then a GPS will provide the correction, The DST is either 0 or +1 hour and is controlled by the date and location (lots of exceptions, though). To be absolutely accurate, you need to have a list of exceptions by geological location, some as small as a city, township, or entire Canadian Provinces like Saskatchewan or US states like AZ and HI, but with about 19 ready to change now.
I have not looked into it, but I will make a small wager the NTP protocol likely will fulfill your needs.
First computer 1959. Retired from my own computer company 2004.
Hardware - Expert in 1401, and 360, fairly knowledge in PC plus numerous MPU's and MCU's
Major Languages - Machine language, 360 Macro Assembler, Intel Assembler, PL/I and PL1, Pascal, Basic, C plus numerous job control and scripting languages.
My personal scorecard is now 1 PC hardware fix (circa 1982), 1 open source fix (at age 82), and 2 zero day bugs in a major OS.