diff --git a/clock.cpp b/clock.cpp index f80536e..ab772a6 100644 --- a/clock.cpp +++ b/clock.cpp @@ -1,14 +1,20 @@ #include "clock.h" #include +#include +#include #include +#include +#include Clock::Clock(ClockSettings const& settings): m_settings(settings), m_last_NTP_check(0), m_NTP_waiting_for_response(false), m_UDP(), - m_NTP_ip() + m_NTP_ip(), + m_TZ_offset(0), + m_next_TZ_check(0) { setSyncProvider(RTC.get); m_UDP.begin(NTP_PORT); @@ -17,6 +23,7 @@ Clock::Clock(ClockSettings const& settings): void Clock::internet_update() { ntp_update(); + tz_update(); } void Clock::ntp_update() @@ -87,3 +94,71 @@ void Clock::ntp_checkResponse() Serial.print("Time: "); Serial.println(UNIX_time); } + +void Clock::tz_update() +{ + //it's no use to do anything before we have the right UTC time + if(timeStatus() != timeSet) + return; + + //rate limiting + if(now() <= m_next_TZ_check) + return; + + Serial.println("Updating timezones"); + + WiFiClient client; + HTTPClient http; + + String url = "http://api.timezonedb.com/v2.1/get-time-zone?key="; + url += m_settings.api_key(); + url += "&format=json&by=zone&zone="; + url += m_settings.time_zone(); + + Serial.print("Connecting to \""); + Serial.print(url); + Serial.println("\""); + + if(!http.begin(client, url)) + { + Serial.println("Cannot connect"); + m_next_TZ_check = now() + TZ_RETRY_COOLDOWN; + } + else + { + int response = http.GET(); + if(response <= 0) + { + Serial.print("Error: "); + Serial.println(http.errorToString(response)); + m_next_TZ_check = now() + TZ_RETRY_COOLDOWN; + } + else if(response == HTTP_CODE_OK || response == HTTP_CODE_MOVED_PERMANENTLY) + { + String payload = http.getString(); + + int offset = jsonExtract(payload, "gmtOffset").toInt(); + String end = jsonExtract(payload, "zoneEnd"); + + time_t const zoneEnd = atoll(end.c_str()); + + Serial.print("offset: "); + Serial.println(offset); + Serial.print("Zone end: "); + Serial.println(zoneEnd); + + m_TZ_offset = offset; + + time_t const time = now(); + if(time >= zoneEnd) + m_next_TZ_check = time + TZ_RETRY_COOLDOWN; + else if(zoneEnd - time > TZ_RETRY_COOLDOWN) + m_next_TZ_check = zoneEnd - TZ_RETRY_COOLDOWN; + else + m_next_TZ_check = zoneEnd; + + Serial.print("next check: "); + Serial.println(m_next_TZ_check); + } + } +} diff --git a/clock.h b/clock.h index e4a08aa..f819580 100644 --- a/clock.h +++ b/clock.h @@ -7,6 +7,7 @@ unsigned int const NTP_BUFFER_SIZE = 48; unsigned int const NTP_PORT = 123; +unsigned int const TZ_RETRY_COOLDOWN = 60; class Clock { @@ -20,6 +21,8 @@ class Clock void ntp_ask(); void ntp_checkResponse(); + void tz_update(); + protected: ClockSettings const& m_settings; @@ -29,6 +32,9 @@ class Clock WiFiUDP m_UDP; IPAddress m_NTP_ip; uint8_t m_NTP_buffer[NTP_BUFFER_SIZE]; + + int m_TZ_offset; + time_t m_next_TZ_check; }; #endif //CLOCK_H diff --git a/clock_settings.cpp b/clock_settings.cpp index 1e83006..136f942 100644 --- a/clock_settings.cpp +++ b/clock_settings.cpp @@ -5,13 +5,17 @@ #include ClockSettings::ClockSettings(): - m_server(nullptr) + m_server(nullptr), + m_api_key(nullptr), + m_time_zone(nullptr) { } ClockSettings::~ClockSettings() { delete[] m_server; + delete[] m_api_key; + delete[] m_time_zone; } void ClockSettings::add_info(char const* key, char const* val) @@ -41,6 +45,20 @@ void ClockSettings::add_info(char const* key, char const* val) m_cooldown *= 60; } } + else if(string_equals(key, "key")) + { + if(m_api_key != nullptr) + delete[] m_api_key; + + m_api_key = val; + } + else if(string_equals(key, "zone")) + { + if(m_time_zone != nullptr) + delete[] m_time_zone; + + m_time_zone = val; + } else delete[] val; diff --git a/clock_settings.h b/clock_settings.h index e2f2cd4..c8e7c16 100644 --- a/clock_settings.h +++ b/clock_settings.h @@ -11,10 +11,14 @@ class ClockSettings inline char const*const server() const {return m_server;} inline unsigned int cooldown() const {return m_cooldown;} + inline char const*const api_key() const {return m_api_key;} + inline char const*const time_zone() const {return m_time_zone;} protected: char const* m_server; unsigned int m_cooldown; + char const* m_api_key; + char const* m_time_zone; }; #endif //CLOCK_SETTINGS_H diff --git a/readme.md b/readme.md index 3e9cb94..d22eb78 100644 --- a/readme.md +++ b/readme.md @@ -14,6 +14,8 @@ The time is kept using a real-time clock, coupled with an NTP connection to avoi TODO ##Software installation +Pre-requisite: a [TimeZone database](https://timezonedb.com) API key is needed to convert from UTC to the local timezone + 1. Install the [Arduino IDE](https://www.arduino.cc/en/Main/Software) 2. Install the [ESP8266 arduino extension](https://github.com/esp8266/Arduino) 1. add `https://arduino.esp8266.com/stable/package_esp8266com_index.json` to the "Additional Boards Manager URLs" field in the IDE's preferences diff --git a/settings.ini b/settings.ini index 1759cc1..d58e939 100644 --- a/settings.ini +++ b/settings.ini @@ -13,10 +13,16 @@ ssid=WIFI_SSID password=WIFI_PASSWORD -; Configuration of the NTP connection. +; Configuration of the clock (NTP & time zones) ; Since the RTC module is here to do most of the time keeping, ; the NTP requests can be quite far in between +; The timezone information is provided by https://timezonedb.com +; which provides an easy API instead of the weirdly-formatted IANA database [clock] server=pool.ntp.org ; time between NTP requests, in minutes cooldown=15 +; https://timezonedb.com API key +key=API_KEY +; timezone name (see https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) +zone=Europe/Paris