From 12915a48e66172f99d38805a724ee292ca176664 Mon Sep 17 00:00:00 2001 From: sqfmi Date: Wed, 29 Dec 2021 02:06:38 -0500 Subject: [PATCH] Native NTP support & bug fixes - Added native NTP sync support - Fixed bug with WiFi AP not working due to busy lightsleep callback - Removed year offsets and use TimeLib macros for consistency --- examples/WatchFaces/7_SEG/Watchy_7_SEG.cpp | 2 +- library.json | 2 +- library.properties | 2 +- src/Watchy.cpp | 75 ++++++++++---------- src/WatchyRTC.cpp | 79 ++++++++++++++-------- src/WatchyRTC.h | 5 +- src/config.h | 4 +- 7 files changed, 99 insertions(+), 70 deletions(-) diff --git a/examples/WatchFaces/7_SEG/Watchy_7_SEG.cpp b/examples/WatchFaces/7_SEG/Watchy_7_SEG.cpp index dbbfe83..275722d 100644 --- a/examples/WatchFaces/7_SEG/Watchy_7_SEG.cpp +++ b/examples/WatchFaces/7_SEG/Watchy_7_SEG.cpp @@ -70,7 +70,7 @@ void Watchy7SEG::drawDate(){ } display.println(currentTime.Day); display.setCursor(5, 150); - display.println(currentTime.Year + YEAR_OFFSET);// offset from 1970, since year is stored in uint8_t + display.println(tmYearToCalendar(currentTime.Year));// offset from 1970, since year is stored in uint8_t } void Watchy7SEG::drawSteps(){ // reset step counter at midnight diff --git a/library.json b/library.json index 0f1b295..429896a 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "Watchy", - "version": "1.2.12", + "version": "1.3.0", "description": "Watchy - An Open Source E-Paper Watch by SQFMI", "authors": [ { diff --git a/library.properties b/library.properties index 42243ba..f1adf4f 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Watchy -version=1.2.12 +version=1.3.0 author=SQFMI maintainer=SQFMI sentence=Watchy - An Open Source E-Paper Watch by SQFMI diff --git a/src/Watchy.cpp b/src/Watchy.cpp index 790543d..f9a8993 100644 --- a/src/Watchy.cpp +++ b/src/Watchy.cpp @@ -316,7 +316,7 @@ void Watchy::setTime(){ int8_t hour = currentTime.Hour; int8_t day = currentTime.Day; int8_t month = currentTime.Month; - int8_t year = currentTime.Year; + int8_t year = tmYearToY2k(currentTime.Year); int8_t setIndex = SET_HOUR; @@ -452,7 +452,7 @@ void Watchy::setTime(){ tmElements_t tm; tm.Month = month; tm.Day = day; - tm.Year = year; + tm.Year = y2kYearToTm(year); tm.Hour = hour; tm.Minute = minute; tm.Second = 0; @@ -556,8 +556,9 @@ void Watchy::drawWatchFace(){ weatherData Watchy::getWeatherData(){ if(weatherIntervalCounter >= WEATHER_UPDATE_INTERVAL){ //only update if WEATHER_UPDATE_INTERVAL has elapsed i.e. 30 minutes - if(connectWiFi()){//Use Weather API for live data if WiFi is connected - HTTPClient http; + if(connectWiFi()){ + RTC.syncNtpTime(); //Sync NTP + HTTPClient http; //Use Weather API for live data if WiFi is connected http.setConnectTimeout(3000);//3 second max timeout String weatherQueryURL = String(OPENWEATHERMAP_URL) + String(CITY_NAME) + String(",") + String(COUNTRY_CODE) + String("&units=") + String(TEMP_UNIT) + String("&appid=") + String(OPENWEATHERMAP_APIKEY); http.begin(weatherQueryURL.c_str()); @@ -715,41 +716,43 @@ void Watchy::_bmaConfig(){ } void Watchy::setupWifi(){ - WiFiManager wifiManager; - wifiManager.resetSettings(); - wifiManager.setTimeout(WIFI_AP_TIMEOUT); - wifiManager.setAPCallback(_configModeCallback); - display.setFullWindow(); - display.fillScreen(GxEPD_BLACK); - display.setFont(&FreeMonoBold9pt7b); - display.setTextColor(GxEPD_WHITE); - if(!wifiManager.autoConnect(WIFI_AP_SSID)) {//WiFi setup failed - display.println("Setup failed &"); - display.println("timed out!"); - }else{ - display.println("Connected to"); - display.println(WiFi.SSID()); - } - display.display(false); //full refresh - //turn off radios - WiFi.mode(WIFI_OFF); - btStop(); - - guiState = APP_STATE; + display.epd2.setBusyCallback(0); //temporarily disable lightsleep on busy + WiFiManager wifiManager; + wifiManager.resetSettings(); + wifiManager.setTimeout(WIFI_AP_TIMEOUT); + wifiManager.setAPCallback(_configModeCallback); + display.setFullWindow(); + display.fillScreen(GxEPD_BLACK); + display.setFont(&FreeMonoBold9pt7b); + display.setTextColor(GxEPD_WHITE); + if(!wifiManager.autoConnect(WIFI_AP_SSID)) {//WiFi setup failed + display.println("Setup failed &"); + display.println("timed out!"); + }else{ + RTC.syncNtpTime(); //sync ntp + display.println("Connected to"); + display.println(WiFi.SSID()); + } + display.display(false); //full refresh + //turn off radios + WiFi.mode(WIFI_OFF); + btStop(); + display.epd2.setBusyCallback(displayBusyCallback); //enable lightsleep on busy + guiState = APP_STATE; } void Watchy::_configModeCallback (WiFiManager *myWiFiManager) { - display.setFullWindow(); - display.fillScreen(GxEPD_BLACK); - display.setFont(&FreeMonoBold9pt7b); - display.setTextColor(GxEPD_WHITE); - display.setCursor(0, 30); - display.println("Connect to"); - display.print("SSID: "); - display.println(WIFI_AP_SSID); - display.print("IP: "); - display.println(WiFi.softAPIP()); - display.display(false); //full refresh + display.setFullWindow(); + display.fillScreen(GxEPD_BLACK); + display.setFont(&FreeMonoBold9pt7b); + display.setTextColor(GxEPD_WHITE); + display.setCursor(0, 30); + display.println("Connect to"); + display.print("SSID: "); + display.println(WIFI_AP_SSID); + display.print("IP: "); + display.println(WiFi.softAPIP()); + display.display(false); //full refresh } bool Watchy::connectWiFi(){ diff --git a/src/WatchyRTC.cpp b/src/WatchyRTC.cpp index 298c7b6..5656e9c 100644 --- a/src/WatchyRTC.cpp +++ b/src/WatchyRTC.cpp @@ -20,7 +20,7 @@ void WatchyRTC::init(){ } } -void WatchyRTC::config(String datetime){ +void WatchyRTC::config(String datetime){ //String datetime format is YYYY:MM:DD:HH:MM:SS if(rtcType == DS3231){ _DSConfig(datetime); }else{ @@ -43,17 +43,11 @@ void WatchyRTC::clearAlarm(){ void WatchyRTC::read(tmElements_t &tm){ if(rtcType == DS3231){ rtc_ds.read(tm); - tm.Year = tm.Year - 30; //reset to offset from 2000 }else{ + tm.Year = y2kYearToTm(rtc_pcf.getYear()); tm.Month = rtc_pcf.getMonth(); - if(tm.Month == 0){ //PCF8563 POR sets month = 0 for some reason - tm.Month = 1; - tm.Year = 21; - }else{ - tm.Year = rtc_pcf.getYear(); - } tm.Day = rtc_pcf.getDay(); - tm.Wday = rtc_pcf.getWeekday() + 1; + tm.Wday = rtc_pcf.getWeekday() + 1; //TimeLib & DS3231 has Wday range of 1-7, but PCF8563 stores day of week in 0-6 range tm.Hour = rtc_pcf.getHour(); tm.Minute = rtc_pcf.getMinute(); tm.Second = rtc_pcf.getSecond(); @@ -62,11 +56,14 @@ void WatchyRTC::read(tmElements_t &tm){ void WatchyRTC::set(tmElements_t tm){ if(rtcType == DS3231){ - tm.Year = tm.Year + 2000 - YEAR_OFFSET_DS; time_t t = makeTime(tm); rtc_ds.set(t); }else{ - rtc_pcf.setDate(tm.Day, _getDayOfWeek(tm.Day, tm.Month, tm.Year+YEAR_OFFSET_PCF), tm.Month, 0, tm.Year); + time_t t = makeTime(tm); //make and break to calculate tm.Wday + breakTime(t, tm); + //day, weekday, month, century(1=1900, 0=2000), year(0-99) + rtc_pcf.setDate(tm.Day, tm.Wday - 1, tm.Month, 0, tmYearToY2k(tm.Year)); //TimeLib & DS3231 has Wday range of 1-7, but PCF8563 stores day of week in 0-6 range + //hr, min, sec rtc_pcf.setTime(tm.Hour, tm.Minute, tm.Second); clearAlarm(); } @@ -80,10 +77,10 @@ uint8_t WatchyRTC::temperature(){ } } -void WatchyRTC::_DSConfig(String datetime){ +void WatchyRTC::_DSConfig(String datetime){ //String datetime is YYYY:MM:DD:HH:MM:SS if(datetime != ""){ tmElements_t tm; - tm.Year = _getValue(datetime, ':', 0).toInt() - YEAR_OFFSET_DS;//offset from 1970, since year is stored in uint8_t + tm.Year = CalendarYrToTm(_getValue(datetime, ':', 0).toInt()); //YYYY - 1970 tm.Month = _getValue(datetime, ':', 1).toInt(); tm.Day = _getValue(datetime, ':', 2).toInt(); tm.Hour = _getValue(datetime, ':', 3).toInt(); @@ -98,30 +95,54 @@ void WatchyRTC::_DSConfig(String datetime){ rtc_ds.alarmInterrupt(ALARM_2, true); //enable alarm interrupt } -void WatchyRTC::_PCFConfig(String datetime){ +void WatchyRTC::_PCFConfig(String datetime){ //String datetime is YYYY:MM:DD:HH:MM:SS if(datetime != ""){ tmElements_t tm; - int Year = _getValue(datetime, ':', 0).toInt(); - int Month = _getValue(datetime, ':', 1).toInt(); - int Day = _getValue(datetime, ':', 2).toInt(); - int Hour = _getValue(datetime, ':', 3).toInt(); - int Minute = _getValue(datetime, ':', 4).toInt(); - int Second = _getValue(datetime, ':', 5).toInt(); + tm.Year = CalendarYrToTm(_getValue(datetime, ':', 0).toInt()); //YYYY - 1970 + tm.Month = _getValue(datetime, ':', 1).toInt(); + tm.Day = _getValue(datetime, ':', 2).toInt(); + tm.Hour = _getValue(datetime, ':', 3).toInt(); + tm.Minute = _getValue(datetime, ':', 4).toInt(); + tm.Second = _getValue(datetime, ':', 5).toInt(); + time_t t = makeTime(tm); //make and break to calculate tm.Wday + breakTime(t, tm); //day, weekday, month, century(1=1900, 0=2000), year(0-99) - rtc_pcf.setDate(Day, _getDayOfWeek(Day, Month, Year), Month, 0, Year - YEAR_OFFSET_PCF);//offset from 2000 + rtc_pcf.setDate(tm.Day, tm.Wday - 1, tm.Month, 0, tmYearToY2k(tm.Year)); //TimeLib & DS3231 has Wday range of 1-7, but PCF8563 stores day of week in 0-6 range //hr, min, sec - rtc_pcf.setTime(Hour, Minute, Second); + rtc_pcf.setTime(tm.Hour, tm.Minute, tm.Second); } + //on POR event, PCF8563 sets month to 0, which will give an error since months are 1-12 clearAlarm(); } -int WatchyRTC::_getDayOfWeek(int d, int m, int y) -{ - static int t[] = { 0, 3, 2, 5, 0, 3, - 5, 1, 4, 6, 2, 4 }; - y -= m < 3; - return ( y + y / 4 - y / 100 + - y / 400 + t[m - 1] + d) % 7; +void WatchyRTC::syncNtpTime(){ //NTP sync - call after connecting to WiFi and remember to turn it back off + configTime(GMT_OFFSET_SEC, DST_OFFSET_SEC, NTP_SERVER); + struct tm timeinfo; + if(!getLocalTime(&timeinfo)){ + return; //NTP sync failed + } + /**************************************************** + struct tm + { + int tm_sec; // Seconds [0,60]. + int tm_min; // Minutes [0,59]. + int tm_hour; // Hour [0,23]. + int tm_mday; // Day of month [1,31]. + int tm_mon; // Month of year [0,11]. + int tm_year; // Years since 1900. + int tm_wday; // Day of week [0,6] (Sunday =0). + int tm_yday; // Day of year [0,365]. + int tm_isdst; // Daylight Savings flag. + } + ****************************************************/ + tmElements_t tm; + tm.Year = CalendarYrToTm(timeinfo.tm_year + 1900); + tm.Month = timeinfo.tm_mon + 1; //tm.Month 1 - 12 + tm.Day = timeinfo.tm_mday; + tm.Hour = timeinfo.tm_hour; + tm.Minute = timeinfo.tm_min; + tm.Second = timeinfo.tm_sec; + set(tm); } String WatchyRTC::_getValue(String data, char separator, int index) diff --git a/src/WatchyRTC.h b/src/WatchyRTC.h index ea5350b..1dcfd91 100644 --- a/src/WatchyRTC.h +++ b/src/WatchyRTC.h @@ -3,6 +3,8 @@ #include #include +#include "config.h" +#include "time.h" #define DS3231 0 #define PCF8563 1 @@ -19,10 +21,11 @@ class WatchyRTC { public: WatchyRTC(); void init(); - void config(String datetime); + void config(String datetime); //String datetime format is YYYY:MM:DD:HH:MM:SS void clearAlarm(); void read(tmElements_t &tm); void set(tmElements_t tm); + void syncNtpTime(); uint8_t temperature(); private: void _DSConfig(String datetime); diff --git a/src/config.h b/src/config.h index 36815fb..3ae4a97 100644 --- a/src/config.h +++ b/src/config.h @@ -48,8 +48,10 @@ #define SET_YEAR 2 #define SET_MONTH 3 #define SET_DAY 4 -#define YEAR_OFFSET 2000 #define HOUR_12_24 24 +#define NTP_SERVER "pool.ntp.org" +#define GMT_OFFSET_SEC 3600 * -5 //New York is UTC -5 +#define DST_OFFSET_SEC 3600 //BLE OTA #define BLE_DEVICE_NAME "Watchy BLE OTA" #define WATCHFACE_NAME "Watchy 7 Segment"