Skip to content

Timezones, NTP, and time

Charles Haynes edited this page Aug 8, 2021 · 6 revisions

Timezones

Daylight savings time

The RTC in Watchy doesn't know anything about timezones. You can set it to your local time, like the default Watchy.cpp does, but that doesn't handle daylight savings time well. To adjust for daylight savings time, that means something has to set the RTC to the new time when the time changes. Until you do, your Watchy will have the wrong time. This may not be a big issue for you, but if it is, read on.

Localtime

The localtime function knows how to convert UTC to your local time, using timezone rules to know when DST starts and ends. It uses the TZ environment variable and the tzset() function. This is explained in the Espressif documentation for timezones. To use this, you set the RTC to UTC, and convert UTC to your local time using localtime or localtime_r whenever you need it.

NTP

You will probably want to synchronize your Watchy with an accurate time source. The most common method is to use the Network Time Protocol - NTP. The ESP documentation for SNTP is oriented towards ESP-IDF users, and is not so Arduino friendly.

A simple synchronous method for setting your Watchy's time from NTP is:

#include <Wifi.h>
#include "time.h"

void timeSyncCallback(struct timeval *tv) {
  RTC.set(tv->tv_sec);  // set RTC
  setTime(tv->tv_sec);          // set system time (optional)
  settimeofday(tv, nullptr);    // set posix time (optional)
  sntp_set_sync_status(SNTP_SYNC_STATUS_COMPLETED);
}

bool syncTime() {
  if (!connectWiFi()) {
    return false;
  }
  if (sntp_get_sync_status() != SNTP_SYNC_STATUS_RESET) {
    // SNTP busy
    return false;
  }
  sntp_set_time_sync_notification_cb(timeSyncCallback);
  configTzTime("UTC0", ntpServer); // sets TZ to UTC0, don't use this in production
  uint32_t timeout = millis() + 5000;  // 5 sec timeout
  bool retVal = false;
  while (millis() < timeout) {
    if (sntp_get_sync_status() == SNTP_SYNC_STATUS_COMPLETED) {
      retVal = true;
      break;
    }
    delay(10);  // or yield
  }
  WiFi.mode(WIFI_OFF);
  btStop();
  return retVal;
}

Time

System time

When Watchy wakes up from deep sleep, the system clock is not set. If you never use now() or time() this is not a problem but if you want now() and time() to return correct results, you will need to set the system time. The easiest way is probably something like:

  tmElements_t currentTime;
  if (RTC.read(currentTime) == 0) {
    time_t t = makeTime(currentTime);
    setTime(t);
    timeval tv = {t, 0};
    settimeofday(&tv, nullptr);
  }

in your Watchy init() function.

Clone this wiki locally