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
pull/133/head v1.3.0
sqfmi 2021-12-29 02:06:38 -05:00
parent 1bfbc55f4a
commit 12915a48e6
7 changed files with 99 additions and 70 deletions

View File

@ -70,7 +70,7 @@ void Watchy7SEG::drawDate(){
} }
display.println(currentTime.Day); display.println(currentTime.Day);
display.setCursor(5, 150); 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(){ void Watchy7SEG::drawSteps(){
// reset step counter at midnight // reset step counter at midnight

View File

@ -1,6 +1,6 @@
{ {
"name": "Watchy", "name": "Watchy",
"version": "1.2.12", "version": "1.3.0",
"description": "Watchy - An Open Source E-Paper Watch by SQFMI", "description": "Watchy - An Open Source E-Paper Watch by SQFMI",
"authors": [ "authors": [
{ {

View File

@ -1,5 +1,5 @@
name=Watchy name=Watchy
version=1.2.12 version=1.3.0
author=SQFMI author=SQFMI
maintainer=SQFMI maintainer=SQFMI
sentence=Watchy - An Open Source E-Paper Watch by SQFMI sentence=Watchy - An Open Source E-Paper Watch by SQFMI

View File

@ -316,7 +316,7 @@ void Watchy::setTime(){
int8_t hour = currentTime.Hour; int8_t hour = currentTime.Hour;
int8_t day = currentTime.Day; int8_t day = currentTime.Day;
int8_t month = currentTime.Month; int8_t month = currentTime.Month;
int8_t year = currentTime.Year; int8_t year = tmYearToY2k(currentTime.Year);
int8_t setIndex = SET_HOUR; int8_t setIndex = SET_HOUR;
@ -452,7 +452,7 @@ void Watchy::setTime(){
tmElements_t tm; tmElements_t tm;
tm.Month = month; tm.Month = month;
tm.Day = day; tm.Day = day;
tm.Year = year; tm.Year = y2kYearToTm(year);
tm.Hour = hour; tm.Hour = hour;
tm.Minute = minute; tm.Minute = minute;
tm.Second = 0; tm.Second = 0;
@ -556,8 +556,9 @@ void Watchy::drawWatchFace(){
weatherData Watchy::getWeatherData(){ weatherData Watchy::getWeatherData(){
if(weatherIntervalCounter >= WEATHER_UPDATE_INTERVAL){ //only update if WEATHER_UPDATE_INTERVAL has elapsed i.e. 30 minutes 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 if(connectWiFi()){
HTTPClient http; RTC.syncNtpTime(); //Sync NTP
HTTPClient http; //Use Weather API for live data if WiFi is connected
http.setConnectTimeout(3000);//3 second max timeout 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); 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()); http.begin(weatherQueryURL.c_str());
@ -715,41 +716,43 @@ void Watchy::_bmaConfig(){
} }
void Watchy::setupWifi(){ void Watchy::setupWifi(){
WiFiManager wifiManager; display.epd2.setBusyCallback(0); //temporarily disable lightsleep on busy
wifiManager.resetSettings(); WiFiManager wifiManager;
wifiManager.setTimeout(WIFI_AP_TIMEOUT); wifiManager.resetSettings();
wifiManager.setAPCallback(_configModeCallback); wifiManager.setTimeout(WIFI_AP_TIMEOUT);
display.setFullWindow(); wifiManager.setAPCallback(_configModeCallback);
display.fillScreen(GxEPD_BLACK); display.setFullWindow();
display.setFont(&FreeMonoBold9pt7b); display.fillScreen(GxEPD_BLACK);
display.setTextColor(GxEPD_WHITE); display.setFont(&FreeMonoBold9pt7b);
if(!wifiManager.autoConnect(WIFI_AP_SSID)) {//WiFi setup failed display.setTextColor(GxEPD_WHITE);
display.println("Setup failed &"); if(!wifiManager.autoConnect(WIFI_AP_SSID)) {//WiFi setup failed
display.println("timed out!"); display.println("Setup failed &");
}else{ display.println("timed out!");
display.println("Connected to"); }else{
display.println(WiFi.SSID()); RTC.syncNtpTime(); //sync ntp
} display.println("Connected to");
display.display(false); //full refresh display.println(WiFi.SSID());
//turn off radios }
WiFi.mode(WIFI_OFF); display.display(false); //full refresh
btStop(); //turn off radios
WiFi.mode(WIFI_OFF);
guiState = APP_STATE; btStop();
display.epd2.setBusyCallback(displayBusyCallback); //enable lightsleep on busy
guiState = APP_STATE;
} }
void Watchy::_configModeCallback (WiFiManager *myWiFiManager) { void Watchy::_configModeCallback (WiFiManager *myWiFiManager) {
display.setFullWindow(); display.setFullWindow();
display.fillScreen(GxEPD_BLACK); display.fillScreen(GxEPD_BLACK);
display.setFont(&FreeMonoBold9pt7b); display.setFont(&FreeMonoBold9pt7b);
display.setTextColor(GxEPD_WHITE); display.setTextColor(GxEPD_WHITE);
display.setCursor(0, 30); display.setCursor(0, 30);
display.println("Connect to"); display.println("Connect to");
display.print("SSID: "); display.print("SSID: ");
display.println(WIFI_AP_SSID); display.println(WIFI_AP_SSID);
display.print("IP: "); display.print("IP: ");
display.println(WiFi.softAPIP()); display.println(WiFi.softAPIP());
display.display(false); //full refresh display.display(false); //full refresh
} }
bool Watchy::connectWiFi(){ bool Watchy::connectWiFi(){

View File

@ -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){ if(rtcType == DS3231){
_DSConfig(datetime); _DSConfig(datetime);
}else{ }else{
@ -43,17 +43,11 @@ void WatchyRTC::clearAlarm(){
void WatchyRTC::read(tmElements_t &tm){ void WatchyRTC::read(tmElements_t &tm){
if(rtcType == DS3231){ if(rtcType == DS3231){
rtc_ds.read(tm); rtc_ds.read(tm);
tm.Year = tm.Year - 30; //reset to offset from 2000
}else{ }else{
tm.Year = y2kYearToTm(rtc_pcf.getYear());
tm.Month = rtc_pcf.getMonth(); 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.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.Hour = rtc_pcf.getHour();
tm.Minute = rtc_pcf.getMinute(); tm.Minute = rtc_pcf.getMinute();
tm.Second = rtc_pcf.getSecond(); tm.Second = rtc_pcf.getSecond();
@ -62,11 +56,14 @@ void WatchyRTC::read(tmElements_t &tm){
void WatchyRTC::set(tmElements_t tm){ void WatchyRTC::set(tmElements_t tm){
if(rtcType == DS3231){ if(rtcType == DS3231){
tm.Year = tm.Year + 2000 - YEAR_OFFSET_DS;
time_t t = makeTime(tm); time_t t = makeTime(tm);
rtc_ds.set(t); rtc_ds.set(t);
}else{ }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); rtc_pcf.setTime(tm.Hour, tm.Minute, tm.Second);
clearAlarm(); 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 != ""){ if(datetime != ""){
tmElements_t tm; 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.Month = _getValue(datetime, ':', 1).toInt();
tm.Day = _getValue(datetime, ':', 2).toInt(); tm.Day = _getValue(datetime, ':', 2).toInt();
tm.Hour = _getValue(datetime, ':', 3).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 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 != ""){ if(datetime != ""){
tmElements_t tm; tmElements_t tm;
int Year = _getValue(datetime, ':', 0).toInt(); tm.Year = CalendarYrToTm(_getValue(datetime, ':', 0).toInt()); //YYYY - 1970
int Month = _getValue(datetime, ':', 1).toInt(); tm.Month = _getValue(datetime, ':', 1).toInt();
int Day = _getValue(datetime, ':', 2).toInt(); tm.Day = _getValue(datetime, ':', 2).toInt();
int Hour = _getValue(datetime, ':', 3).toInt(); tm.Hour = _getValue(datetime, ':', 3).toInt();
int Minute = _getValue(datetime, ':', 4).toInt(); tm.Minute = _getValue(datetime, ':', 4).toInt();
int Second = _getValue(datetime, ':', 5).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) //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 //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(); clearAlarm();
} }
int WatchyRTC::_getDayOfWeek(int d, int m, int y) 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);
static int t[] = { 0, 3, 2, 5, 0, 3, struct tm timeinfo;
5, 1, 4, 6, 2, 4 }; if(!getLocalTime(&timeinfo)){
y -= m < 3; return; //NTP sync failed
return ( y + y / 4 - y / 100 + }
y / 400 + t[m - 1] + d) % 7; /****************************************************
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) String WatchyRTC::_getValue(String data, char separator, int index)

View File

@ -3,6 +3,8 @@
#include <DS3232RTC.h> #include <DS3232RTC.h>
#include <Rtc_Pcf8563.h> #include <Rtc_Pcf8563.h>
#include "config.h"
#include "time.h"
#define DS3231 0 #define DS3231 0
#define PCF8563 1 #define PCF8563 1
@ -19,10 +21,11 @@ class WatchyRTC {
public: public:
WatchyRTC(); WatchyRTC();
void init(); void init();
void config(String datetime); void config(String datetime); //String datetime format is YYYY:MM:DD:HH:MM:SS
void clearAlarm(); void clearAlarm();
void read(tmElements_t &tm); void read(tmElements_t &tm);
void set(tmElements_t tm); void set(tmElements_t tm);
void syncNtpTime();
uint8_t temperature(); uint8_t temperature();
private: private:
void _DSConfig(String datetime); void _DSConfig(String datetime);

View File

@ -48,8 +48,10 @@
#define SET_YEAR 2 #define SET_YEAR 2
#define SET_MONTH 3 #define SET_MONTH 3
#define SET_DAY 4 #define SET_DAY 4
#define YEAR_OFFSET 2000
#define HOUR_12_24 24 #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 //BLE OTA
#define BLE_DEVICE_NAME "Watchy BLE OTA" #define BLE_DEVICE_NAME "Watchy BLE OTA"
#define WATCHFACE_NAME "Watchy 7 Segment" #define WATCHFACE_NAME "Watchy 7 Segment"