spudnut1
Created February 24, 2020

Simple Self-Setting Wifi Clock

Simple NTP clock using ESP8266 and Adafruit DS3231 RTC self sets itself and indicates HH:MM very accurately & w/DST adjustment.

BeginnerFull instructions provided28
Simple Self-Setting Wifi Clock

Things used in this project

Hardware components

ESP8266 Processor HiLetgo Amazon
×1
Adafruit DS3231 RTC
×1
Adafruit Seven Segment 1.5" LED Red
×1
Amazon Web Services Generic NO pushbutton
×1
Connectino 4 inch pedestal stand
×1
Power Adapter 5v
×1

Story

Read more

Schematics

Clock connections

Wiring connections for the clock

Code

Arduino NTP Self Setting clock

Arduino
Code for clock. Board is 8266
/*
Simple NTP clock with autoset of RTC DS3231  -- uses 8266 and 7 Segment panel
Sets itself using NTP time and then uses RTC for time updates, display
Adjusts for Daylight Savings time
On Power up will revert to saved RTC time unless battery is removed
[Note: the RTC3231 is so accurate that I've found no 'true up' is required even after months
 but you could add one either with a pushbutton or a check for change of month or whatever]

Indicators:
1.  Shows all "8" to indicate power, working, etc.
2.  Show UTC offset (e.g., -8 for Pacific timezone)
3.  Blinks whole display including 8888, colons, while waiting for wifi
4.  Normal display with middle colon blinking to show time updating
5.  Rapid blink of two left hand colons while regetting and reloading wifi time (either power lost or button pushed)
6.  Upper left hand colon dot becomes "PM" marker

adapted from EasyNTPClient example: NodeMCU
For more details see: https://github.com/aharshac/EasyNTPClient
 
*/

#include <Wire.h>
#include <ESP8266WiFi.h>
#include <EasyNTPClient.h>
#include <WiFiUdp.h>
#include <TimeLib.h>
#include "RTClib.h"
#include <Adafruit_GFX.h>
#include "Adafruit_LEDBackpack.h"

const char *SSID_7912     = "xxxxx";                                               // WiFi SSID goes here
const char *Password_7912 = "yyyyyyyyy";                                      // Password goes here
const int MyOffset =  -8;                                                         // correction to UTC for your timezone goes here (e.g., Pacific TZ is -8)
#define onesecond   1000                                                          // milliseconds to wait


void DDTv(String st, int vt) {              // Print descriptor and value
  Serial.print("  ");
  Serial.print(st);
  Serial.print("  ");
  Serial.print(vt);}
                                              // debugging tools
void DDTl(String st, int vt) {               // Print descriptor and value and new line
  DDTv(st, vt);
  Serial.println(" ");}

void DDTs(String st) {                     // Print string 
  Serial.print(st);}
  
void DDTt(String st) {                     // Print string and new line
  Serial.println(st);}
  
void DDTf(String st, float fi) {          // Print descriptor and floating point value and new line
  Serial.print("  ");
  Serial.print(st);
  Serial.print("  ");
  Serial.println(fi,4);}

void DDTsl(String st, String vt) {               // Print descriptor and string value and new line
  Serial.print(st);
  Serial.println(vt);}

unsigned long t_unix_date;
int MyYear;
int MyMonth;
int MyDay;
int MyHour;
int MyMinute;
int MySecond;
int MyWeekDay;
char MyDaysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};


bool BlinkFlag = true;
byte Colon = 0;                                   // mask for colons
const byte Colon_UL = 0x04;                       // Upper left dot
const byte Colon_LL = 0x08;                       // Lower left dot
const byte Colon_Middle = 0x02;                    // middle colon
const byte Colon_Blank = 0x00;                     //no colon

int Print_Hour = 0;                                //printed hours without am/pm


#define sunday  0                                 // used for the daylight savings time routine
#define monday  1                                 // just for readability
#define tuesday 2                                 // Note well that the 8266 routines return 1-7, NOT 0-6 like the arduino rtc logic
#define wednesday 3                               // but since we use we load the RTC from the 8266 and don't use the 8266's "day of week",
#define thursday  4                               // and instead we use the RTC3231 time and date for the DST logic, and must use 0-6
#define friday 5                                  // to match its 0-6 week for returned day of week
#define saturday 6
#define january 1
#define february 2
#define march 3
#define april 4
#define may 5
#define june 6
#define july 7
#define august 8
#define september 9
#define october 10
#define november 11
#define december 12

RTC_DS3231 rtc;                                                         // Initialize for Adafruit DS3231 RTC real time clock

//ESP 8266 pin analogs
/*
 D0 = GPIO16;
 D1 = GPIO5;
 D2 = GPIO4;
 D3 = GPIO0;
 D4 = GPIO2;
 D5 = GPIO14;
 D6 = GPIO12;
 D7 = GPIO13;
 D8 = GPIO15;
 D9 = GPIO3;
 D10 = GPIO1;
 LED_BUILTIN = GPIO16 (auxiliary constant for the board LED, not a board pin);
*/
#define SDA 4             // 8266 pin D2
#define SCL 5             // 8266 pin D1
#define Reset_Pin 0       // 8266 pin D3  Used to force a wifi NTP time update

WiFiUDP udp;                                                              // start wifi

EasyNTPClient ntpClient(udp, "pool.ntp.org", ((MyOffset*60*60)+(0)));     // initialize wifi/NTP routine

Adafruit_7segment matrix = Adafruit_7segment();                           // set up seven segment LED

void setup(){
   Serial.begin(9600);
   matrix.begin(0x70);
   Wire.begin(SDA, SCL);                                                   // join i2c bus with address defined (int sda, int scl);
   matrix.setBrightness(15);
   matrix.print(8888, DEC);                                               // (1) first show the full display (Indicates Power)
   matrix.drawColon(false); 
   matrix.writeDisplay();
   delay(onesecond*2);                                                           // wait two seconds
   if (! rtc.begin()) {                                                   // check that clock is there
    while (1); }
    matrix.print(MyOffset);                                                 //(2) second show UTC offset (LED Indicates RTC is there)
    matrix.writeDisplay();
    delay(onesecond*2);                                                              // and wait (indicator the clock IS there)
      
  //    if(true) {                                                              //un-comment this line and comment the next to force a reload upon startup
    if (rtc.lostPower()) {                                                   // if power lost force wifi NTP setup, else load 'current' values and go   
      ConnectWiFi();                                                        // did lose power, so connect to wifi network (LED Indicates while blinking that not connected)
      Load_DateTime();                                                      // Note: to force a wifi NTP check each time, just leave out the battery! 
      }  // end of reset time rather than just use last time

      pinMode(Reset_Pin, INPUT_PULLUP);                                       // initialize pin to listen to for forced reset
   
}// end of setup

  
void loop() {
  
    DateTime now = rtc.now();                                                   //load time from the RTC                                  
    MyYear= now.year();
    MyMonth = now.month();
    MyDay = now.day();
    MyHour = now.hour();
    MyMinute= now.minute();
    MySecond = now.second();
    MyWeekDay= now.dayOfTheWeek();
 
 /*                                         // uncomment for debugging
  Serial.print("Today's Date and Time: ");
  Serial.print(MyDaysOfTheWeek[MyWeekDay]);
  Serial.print("  ");
  Serial.print(MyWeekDay);
  Serial.print("  ");
  Serial.print(MyMonth);
  Serial.print("/");
  Serial.print(MyDay);
  Serial.print("/");
  Serial.print(MyYear);
  Serial.print("  ");
  Serial.print(MyHour);
  Serial.print(":");
  if (MyMinute < 10) {Serial.print("0");}
  Serial.print(MyMinute);
  Serial.print(":");
  if (MySecond < 10) {Serial.print("0");}
  Serial.print(MySecond);
  Serial.println(" ");
  if (DSTInEffect()) {Serial.println("DST On");}
*/

//Print hh:mm to LED

   if (DSTInEffect()){MyHour = MyHour + 1;}                                   // Adjust for DST (this only works because we don't care about hour vs. date skew at midnight
   if (MyHour > 12) {Print_Hour = MyHour - 12;} else {Print_Hour = MyHour;}    // Adjust for am,pm
   if (Print_Hour == 0) {Print_Hour = 12;}                                            // and print "12" for "00" (midnight)                                                                           
   if (MySecond%2) {Colon = Colon | Colon_Middle;} else {Colon = Colon_Blank;}                 // center colon only on even seconds else clear it               
   if (MyHour >=12) {Colon = Colon | Colon_UL;}                                     // if its PM then light upper left colon
   matrix.print((Print_Hour*100)+MyMinute, DEC);
   matrix.drawColon(true);                                                        // we want the colon
   matrix.writeDigitRaw(2,  Colon);                                                // draw whatver colons are needed
   matrix.writeDisplay();                                                          // update display
   if ( !digitalRead(Reset_Pin)) {                                                  // read button
       ConnectWiFi();                                                              // Reset button pushed, so connect to wifi network (LED Indicates while blinking that not connected)
       Load_DateTime();                                                              // and reload the time
       delay(onesecond);}                                                                   // give time to get finger off the button
      
   delay(onesecond);                                                                 // wait constant one second between calls for display (mostly for flashing colon)
}    // end of loop


bool DSTInEffect(){                                                                // returns true if DST in effect
                                                                                  // by examing month,day and hour (first Sunday in March at 2am, 2nd Sunday in November at 2am)                                                                                                                                                                                    
 switch (MyMonth){ 
  case april:                                                                  // April thru October, we are in DST if its used
  case may:
  case june:
  case july:
  case august:
  case september:
  case october:
    return true;
  case december:                                                                // December thru February always NOT in DST if used
  case january:
  case february:
    return false;
  case march:                                                                    // in March, we ARE in DST on 2nd Sunday
     if (MyDay < 8) {return false;}                                                   // days 1 thru 7 can't be 2nd sunday
     if (MyDay >13){return true;}                                                   // days 14 and beyond always WILL be DST
     switch (MyWeekDay){
      case sunday: 
        if ((MyDay >= 8 && MyDay <= 13) && (MyHour >= 2) ) {return true;} else return false;   //Sunday AND after 2:00am
      case monday: if (MyDay >=9 && MyDay <= 13) {return true;} else return false;
      case tuesday: if (MyDay >=10 && MyDay <=13) {return true;} else return false;
      case wednesday: if (MyDay >=11 && MyDay <=13) {return true;} else return false;
      case thursday: if (MyDay >=12 && MyDay <=13) {return true;} else return false;
      case friday: if (MyDay == 13) {return true;} else return false;
      case saturday: return false;
                } // end of case on the day for March
 case november:                                                                                 // in November, switch off of DST on first Sunday 
     if (MyDay > 7) {return false;}                                                               // Days 8 through end of month have to be non-DST
     switch (MyWeekDay){                                                                          // use day of week and day of month for days 1-7
      case sunday: if (MyHour <2 ) {return true;} else return false;                              // if its Sunday and its after 2:00am, then adjust
      case monday: if (MyDay >=2) {return false;} else return true;                         
      case tuesday: if (MyDay >=3 ) {return false;} else return true;                      
      case wednesday: if (MyDay >=4) {return false;} else return true;
      case thursday: if (MyDay >=5 ) {return false;} else return true;
      case friday: if (MyDay >=6) {return false;} else return true;
      case saturday: if (MyDay ==7){return false;} else return true;
     } // end of case on the day for November
   
 } // end of case on month      
 } // end of DSTInEffect

 void ConnectWiFi(){                                                                            // routine to connect to wifi network
  
  while (WiFi.status() != WL_CONNECTED) {                                                       //(3) wait til connected and indicate with blink
   matrix.blinkRate(2);                                                                        // 0 = none, 1-3 = rate
    matrix.print(8888, DEC);                                                                    // and also nonsensical display til we have one
    if (BlinkFlag) {matrix.writeDigitRaw(2,Colon_UL | Colon_LL | Colon_Middle);                                   //lower, upper and middle colon on                         
        } else {matrix.writeDigitRaw(2,Colon_Blank);}                                                 // and off in sync with middle                                          
    matrix.writeDisplay();
    BlinkFlag = !BlinkFlag;
    delay(onesecond);
    }  // end of 'not connected'
    matrix.blinkRate(0);                                                                        //(4) stop blinking when we've made it and go to actual time display
    
  }  // end of connect to Wifi

  void Load_DateTime(){
   
    t_unix_date = ntpClient.getUnixTime();                                                     // get the internet time
    MyYear = year(t_unix_date);                                                                // load all the date and time stuff up
    MyMonth = month(t_unix_date);
    MyDay = day(t_unix_date);
    MyHour = hour(t_unix_date);
    MyMinute = minute(t_unix_date);
    MySecond = second(t_unix_date);
    MyWeekDay = weekday(t_unix_date);                                     
    rtc.adjust(DateTime(MyYear, MyMonth, MyDay, MyHour, MyMinute, MySecond));                   // and reset RTC
    for (int i=0; i<12; i++) {                                                                  //(5) blink two left colons  to indicate reloaded time
    if (BlinkFlag) {matrix.writeDigitRaw(2,Colon_UL | Colon_LL );                                   //lower, upper and middle colon on                         
        } else {matrix.writeDigitRaw(2,Colon_Blank);}                                                 // and off in sync with middle                                          
    matrix.writeDisplay();
    DDTv("BlinkFlag",BlinkFlag);
    BlinkFlag = !BlinkFlag;
    delay(onesecond/3);}
  } // end of Load_DateTime



 

Credits

spudnut1
10 projects • 15 followers
Contact

Comments

Please log in or sign up to comment.