diff --git a/platformio.ini b/platformio.ini index 8b9076c..ae12590 100644 --- a/platformio.ini +++ b/platformio.ini @@ -17,6 +17,7 @@ lib_deps = GxEPD2 Time NTPClient + ArduinoJson lib_ldf_mode = deep+ board_build.partitions = min_spiffs.csv diff --git a/src/Icons.h b/src/Icons.h index 2427196..f1b9d4d 100644 --- a/src/Icons.h +++ b/src/Icons.h @@ -2,11 +2,22 @@ namespace Icons { - const unsigned char steps [] PROGMEM = { + // 19x23 + const unsigned char steps[] PROGMEM = { 0x00, 0x03, 0xc0, 0x00, 0x07, 0xe0, 0x00, 0x07, 0xe0, 0x00, 0x0f, 0xe0, 0x78, 0x0f, 0xe0, 0xfc, 0x0f, 0xe0, 0xfc, 0x0f, 0xe0, 0xfc, 0x0f, 0xe0, 0xfe, 0x0f, 0xe0, 0xfe, 0x07, 0xc0, 0xfe, 0x07, 0xc0, 0xfe, 0x07, 0x80, 0xfe, 0x00, 0x00, 0x7c, 0x0e, 0x00, 0x7c, 0x0f, 0x80, 0x7c, 0x1f, 0x80, 0x20, 0x1f, 0x00, 0x06, 0x0f, 0x00, 0x3e, 0x0e, 0x00, 0x3e, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x1e, 0x00, 0x00 }; -}; \ No newline at end of file + + // 29x23 + const unsigned char city[] PROGMEM = { + 0x00, 0x07, 0xf8, 0x00, 0x00, 0x07, 0xfc, 0x00, 0x00, 0x07, 0xfc, 0x00, 0x0e, 0x07, 0x1c, 0x00, + 0x1f, 0x87, 0x1c, 0x00, 0x3f, 0xc7, 0x1c, 0xc0, 0x3f, 0xc7, 0xfc, 0xc0, 0x3f, 0xc7, 0x1c, 0xc0, + 0x7f, 0xc7, 0x1c, 0xc0, 0x7f, 0xe7, 0x1f, 0xf8, 0xff, 0xe7, 0xff, 0xf8, 0xff, 0xe7, 0x1e, 0x38, + 0xff, 0xe7, 0x1e, 0x38, 0xff, 0xe7, 0x1e, 0x38, 0x06, 0x07, 0x1e, 0x38, 0x06, 0x07, 0xff, 0xf8, + 0x06, 0x07, 0xfe, 0x38, 0x06, 0x07, 0xfe, 0x38, 0x06, 0x07, 0xfe, 0x38, 0x06, 0x07, 0xff, 0xf8, + 0x06, 0x07, 0xff, 0xf8, 0x06, 0x07, 0xff, 0xf8, 0x06, 0x07, 0xff, 0xf8 + }; +} \ No newline at end of file diff --git a/src/WatchFace.cpp b/src/WatchFace.cpp index 900cc93..4aed098 100644 --- a/src/WatchFace.cpp +++ b/src/WatchFace.cpp @@ -18,6 +18,8 @@ void WatchFace::InitBoot() m_features.wifi.Disconnect(); } + static_cast(m_pages[1].get())->Resync(); + for (auto & page : m_pages) { page->InitBoot(); } @@ -118,6 +120,9 @@ void WatchFace::DrawWatchFace(bool partialRefresh) } m_pages[m_watchFacePage]->DrawPage(partialRefresh); + + // Resync weather on matter what + static_cast(m_pages[1].get())->Resync(); } void WatchFace::SetupVolatileMenuStuff() diff --git a/src/WatchFacePages/Clock.cpp b/src/WatchFacePages/Clock.cpp index a2f106f..8a499db 100644 --- a/src/WatchFacePages/Clock.cpp +++ b/src/WatchFacePages/Clock.cpp @@ -102,7 +102,6 @@ void WatchFacePages::Clock::DrawBatteryIcon() m_display.setFont(&FreeSans9pt7b); m_display.setTextColor(GxEPD_BLACK); - int16_t y; uint16_t w, h; m_display.getTextBounds(oss.str().c_str(), 0, 0, &x, &y, &w, &h); diff --git a/src/WatchFacePages/Weather.cpp b/src/WatchFacePages/Weather.cpp index 5ea15ab..dcc6334 100644 --- a/src/WatchFacePages/Weather.cpp +++ b/src/WatchFacePages/Weather.cpp @@ -1,10 +1,17 @@ #include "Weather.h" #include "../SevenSegment.h" #include "../Icons.h" +#include +#include #include +#include +#include RTC_DATA_ATTR uint64_t WatchFacePages::Weather::m_lastSyncTime = 0; RTC_DATA_ATTR int WatchFacePages::Weather::m_lastCalculatedDay = 0XFFFFFFFF; +RTC_DATA_ATTR float WatchFacePages::Weather::m_locationLat = 0.0f; +RTC_DATA_ATTR float WatchFacePages::Weather::m_locationLon = 0.0f; +RTC_DATA_ATTR char WatchFacePages::Weather::m_locationCity[128]; WatchFacePages::Weather::Weather(WatchyDisplay & display, WatchFeatures::WatchFeatures & features) : m_display(display), m_features(features) @@ -21,6 +28,11 @@ void WatchFacePages::Weather::InitWake() void WatchFacePages::Weather::DrawPage(bool partialRefresh) { + Serial.println("Weather:DrawPage"); + if (m_lastSyncTime == 0) { + Resync(); + } + m_display.setFullWindow(); m_display.fillScreen(GxEPD_WHITE); m_display.setTextColor(GxEPD_BLACK); @@ -34,23 +46,69 @@ void WatchFacePages::Weather::DrawPage(bool partialRefresh) m_display.print("Have not synced"); m_display.display(partialRefresh); return; - } else if (m_features.rtc.GetTimestamp() - m_lastSyncTime > 86400) { - m_display.setFont(&FreeSans12pt7b); - m_display.setCursor(20, 110); - m_display.print("Last sync > 1 day"); - m_display.display(partialRefresh); - return; } + + bool weatherOutdated = false; + + if (m_features.rtc.GetTimestamp() - m_lastSyncTime > 86400) { + weatherOutdated = true; + } + + m_display.setFont(&FreeSansBold9pt7b); + int16_t x, y; + uint16_t w, h; + + m_display.drawBitmap(5, 5, Icons::city, 29, 23, GxEPD_BLACK); + + m_display.setCursor(39, 21); + m_display.print(m_locationCity); + m_display.display(partialRefresh); } void WatchFacePages::Weather::Resync() { uint64_t currentTime = m_features.rtc.GetTimestamp(); - if(m_lastSyncTime == 0 || currentTime - m_lastSyncTime > WEATHER_UPDATE_INTERVAL) { + if(m_lastSyncTime > 0 && currentTime - m_lastSyncTime < WEATHER_UPDATE_INTERVAL) { + return; } - // if(!m_features.wifi.Connect()) { - // return; - // } + if(!m_features.wifi.Connect()) { + return; + } + + HTTPClient client; + client.setConnectTimeout(3000); // 3 second max timeout + + client.begin("http://ip-api.com/json/"); + int httpCode = client.GET(); + if (httpCode != 200) { + m_features.wifi.Disconnect(); + return; + } + + String payload = client.getString(); + client.end(); + + DynamicJsonDocument json(1024); + DeserializationError error = deserializeJson(json, payload); + if (error) { + m_features.wifi.Disconnect(); + return; + } + + if (!json.containsKey("lat") || !json.containsKey("lon")) { + m_features.wifi.Disconnect(); + return; + } + + std::string location = json["city"].as(); + location = location.substr(0, 127); + memcpy(m_locationCity, location.c_str(), location.length()); + m_locationCity[location.length()] = '\0'; + m_locationLat = json["lat"]; + m_locationLon = json["lon"]; + m_features.wifi.Disconnect(); + + m_lastSyncTime = currentTime; } \ No newline at end of file diff --git a/src/WatchFacePages/Weather.h b/src/WatchFacePages/Weather.h index f84db95..29720f6 100644 --- a/src/WatchFacePages/Weather.h +++ b/src/WatchFacePages/Weather.h @@ -5,6 +5,7 @@ #include "Page.h" #include "../WatchyDisplay.h" #include "../WatchFeatures/WatchFeatures.h" +#include namespace WatchFacePages { @@ -18,12 +19,14 @@ public: void InitBoot() override; void InitWake() override; void DrawPage(bool partialRefresh = false) override; + void Resync(); private: - void Resync(); WatchyDisplay & m_display; WatchFeatures::WatchFeatures & m_features; static RTC_DATA_ATTR uint64_t m_lastSyncTime; static RTC_DATA_ATTR int m_lastCalculatedDay; + static RTC_DATA_ATTR char m_locationCity[128]; + static RTC_DATA_ATTR float m_locationLat, m_locationLon; }; \ No newline at end of file