Display drifitng stats
This commit is contained in:
@@ -112,6 +112,8 @@ STR_SYNCING_CLOCK: "Syncing clock..."
|
|||||||
STR_DETECTING_TIMEZONE: "Detecting timezone..."
|
STR_DETECTING_TIMEZONE: "Detecting timezone..."
|
||||||
STR_TIME_SYNCED: "Time synced"
|
STR_TIME_SYNCED: "Time synced"
|
||||||
STR_TIME_SYNC_FAILED: "Time sync failed"
|
STR_TIME_SYNC_FAILED: "Time sync failed"
|
||||||
|
STR_CLOCK_DRIFT: "Drift: %s"
|
||||||
|
STR_LAST_NTP_SYNC: "Last sync: %s"
|
||||||
STR_TIMEZONE_DETECTED: "Timezone detected"
|
STR_TIMEZONE_DETECTED: "Timezone detected"
|
||||||
STR_TIMEZONE_DETECT_FAILED: "Timezone detect failed"
|
STR_TIMEZONE_DETECT_FAILED: "Timezone detect failed"
|
||||||
STR_DST_ACTIVE: "DST: active"
|
STR_DST_ACTIVE: "DST: active"
|
||||||
|
|||||||
@@ -227,6 +227,8 @@ bool isSynced() {
|
|||||||
|
|
||||||
bool isApproximate() { return clockApproximate; }
|
bool isApproximate() { return clockApproximate; }
|
||||||
|
|
||||||
|
time_t lastSyncTime() { return nvsReadSyncTime(); }
|
||||||
|
|
||||||
void formatTime(char* buf, size_t bufSize, bool use24h) {
|
void formatTime(char* buf, size_t bufSize, bool use24h) {
|
||||||
if (!isSynced()) {
|
if (!isSynced()) {
|
||||||
snprintf(buf, bufSize, "--:--");
|
snprintf(buf, bufSize, "--:--");
|
||||||
|
|||||||
@@ -55,6 +55,10 @@ bool isSynced();
|
|||||||
/// may have drifted. Cleared on NTP sync.
|
/// may have drifted. Cleared on NTP sync.
|
||||||
bool isApproximate();
|
bool isApproximate();
|
||||||
|
|
||||||
|
/// Returns the epoch of the last successful NTP sync (from NVS), or 0 if
|
||||||
|
/// no sync has ever been recorded.
|
||||||
|
time_t lastSyncTime();
|
||||||
|
|
||||||
/// Format the current time for display. Returns "--:--" if the clock was
|
/// Format the current time for display. Returns "--:--" if the clock was
|
||||||
/// never synced, prefixes with "~" if approximate.
|
/// never synced, prefixes with "~" if approximate.
|
||||||
/// When use24h is false, formats as "2:05pm" / "12:30am".
|
/// When use24h is false, formats as "2:05pm" / "12:30am".
|
||||||
|
|||||||
@@ -6,12 +6,48 @@
|
|||||||
#include <Logging.h>
|
#include <Logging.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
#include "CrossPointSettings.h"
|
#include "CrossPointSettings.h"
|
||||||
#include "MappedInputManager.h"
|
#include "MappedInputManager.h"
|
||||||
#include "activities/network/WifiSelectionActivity.h"
|
#include "activities/network/WifiSelectionActivity.h"
|
||||||
#include "components/UITheme.h"
|
#include "components/UITheme.h"
|
||||||
#include "fontIds.h"
|
#include "fontIds.h"
|
||||||
|
|
||||||
|
static void formatDuration(char* buf, size_t bufSize, int32_t totalSeconds) {
|
||||||
|
const char* sign = totalSeconds < 0 ? "-" : "+";
|
||||||
|
int32_t abs = totalSeconds < 0 ? -totalSeconds : totalSeconds;
|
||||||
|
|
||||||
|
int32_t days = abs / 86400;
|
||||||
|
int32_t hours = (abs % 86400) / 3600;
|
||||||
|
int32_t mins = (abs % 3600) / 60;
|
||||||
|
int32_t secs = abs % 60;
|
||||||
|
|
||||||
|
if (days > 0) {
|
||||||
|
snprintf(buf, bufSize, "%s%ldd %ldh %ldm", sign, (long)days, (long)hours, (long)mins);
|
||||||
|
} else if (hours > 0) {
|
||||||
|
snprintf(buf, bufSize, "%s%ldh %ldm %lds", sign, (long)hours, (long)mins, (long)secs);
|
||||||
|
} else if (mins > 0) {
|
||||||
|
snprintf(buf, bufSize, "%s%ldm %lds", sign, (long)mins, (long)secs);
|
||||||
|
} else {
|
||||||
|
snprintf(buf, bufSize, "%s%lds", sign, (long)secs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void formatElapsed(char* buf, size_t bufSize, int32_t totalSeconds) {
|
||||||
|
int32_t days = totalSeconds / 86400;
|
||||||
|
int32_t hours = (totalSeconds % 86400) / 3600;
|
||||||
|
int32_t mins = (totalSeconds % 3600) / 60;
|
||||||
|
|
||||||
|
if (days > 0) {
|
||||||
|
snprintf(buf, bufSize, "%ldd %ldh ago", (long)days, (long)hours);
|
||||||
|
} else if (hours > 0) {
|
||||||
|
snprintf(buf, bufSize, "%ldh %ldm ago", (long)hours, (long)mins);
|
||||||
|
} else {
|
||||||
|
snprintf(buf, bufSize, "%ldm ago", (long)mins);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SyncTimeActivity::onEnter() {
|
void SyncTimeActivity::onEnter() {
|
||||||
Activity::onEnter();
|
Activity::onEnter();
|
||||||
|
|
||||||
@@ -54,7 +90,16 @@ void SyncTimeActivity::onWifiSelectionComplete(bool success) {
|
|||||||
void SyncTimeActivity::onWifiSelectionCancelled() { finish(); }
|
void SyncTimeActivity::onWifiSelectionCancelled() { finish(); }
|
||||||
|
|
||||||
void SyncTimeActivity::performSync() {
|
void SyncTimeActivity::performSync() {
|
||||||
|
hadTimeBeforeSync = HalClock::isSynced();
|
||||||
|
preSyncTime = hadTimeBeforeSync ? time(nullptr) : 0;
|
||||||
|
prevSyncTime = HalClock::lastSyncTime();
|
||||||
|
|
||||||
bool ok = HalClock::syncNtp();
|
bool ok = HalClock::syncNtp();
|
||||||
|
|
||||||
|
if (ok && hadTimeBeforeSync) {
|
||||||
|
driftSeconds = (int32_t)(time(nullptr) - preSyncTime);
|
||||||
|
}
|
||||||
|
|
||||||
HalClock::wifiOff(true);
|
HalClock::wifiOff(true);
|
||||||
|
|
||||||
state = ok ? SUCCESS : FAILED;
|
state = ok ? SUCCESS : FAILED;
|
||||||
@@ -76,7 +121,8 @@ void SyncTimeActivity::render(RenderLock&&) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (state == SUCCESS) {
|
if (state == SUCCESS) {
|
||||||
renderer.drawCenteredText(UI_10_FONT_ID, pageHeight / 2 - 20, tr(STR_TIME_SYNCED), true, EpdFontFamily::BOLD);
|
int y = pageHeight / 2 - 40;
|
||||||
|
renderer.drawCenteredText(UI_10_FONT_ID, y, tr(STR_TIME_SYNCED), true, EpdFontFamily::BOLD);
|
||||||
|
|
||||||
time_t now = HalClock::now();
|
time_t now = HalClock::now();
|
||||||
struct tm timeinfo;
|
struct tm timeinfo;
|
||||||
@@ -86,7 +132,45 @@ void SyncTimeActivity::render(RenderLock&&) {
|
|||||||
char timeStr[32];
|
char timeStr[32];
|
||||||
snprintf(timeStr, sizeof(timeStr), "%s %04d-%02d-%02d", timePart, timeinfo.tm_year + 1900, timeinfo.tm_mon + 1,
|
snprintf(timeStr, sizeof(timeStr), "%s %04d-%02d-%02d", timePart, timeinfo.tm_year + 1900, timeinfo.tm_mon + 1,
|
||||||
timeinfo.tm_mday);
|
timeinfo.tm_mday);
|
||||||
renderer.drawCenteredText(UI_10_FONT_ID, pageHeight / 2 + 10, timeStr);
|
y += 30;
|
||||||
|
renderer.drawCenteredText(UI_10_FONT_ID, y, timeStr);
|
||||||
|
|
||||||
|
int32_t elapsedSinceSync = -1;
|
||||||
|
if (prevSyncTime > 0) {
|
||||||
|
elapsedSinceSync = (int32_t)(now - prevSyncTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
char driftStr[80];
|
||||||
|
if (hadTimeBeforeSync) {
|
||||||
|
char driftFmt[24];
|
||||||
|
formatDuration(driftFmt, sizeof(driftFmt), driftSeconds);
|
||||||
|
|
||||||
|
if (elapsedSinceSync > 0) {
|
||||||
|
double hours = (double)elapsedSinceSync / 3600.0;
|
||||||
|
double rate = (double)driftSeconds / hours;
|
||||||
|
char rateFmt[16];
|
||||||
|
snprintf(rateFmt, sizeof(rateFmt), "%+.2f", rate);
|
||||||
|
|
||||||
|
char driftWithRate[48];
|
||||||
|
snprintf(driftWithRate, sizeof(driftWithRate), "%s (%s s/hr)", driftFmt, rateFmt);
|
||||||
|
snprintf(driftStr, sizeof(driftStr), tr(STR_CLOCK_DRIFT), driftWithRate);
|
||||||
|
} else {
|
||||||
|
snprintf(driftStr, sizeof(driftStr), tr(STR_CLOCK_DRIFT), driftFmt);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
snprintf(driftStr, sizeof(driftStr), tr(STR_CLOCK_DRIFT), "N/A");
|
||||||
|
}
|
||||||
|
y += 30;
|
||||||
|
renderer.drawCenteredText(UI_10_FONT_ID, y, driftStr);
|
||||||
|
|
||||||
|
if (elapsedSinceSync > 0) {
|
||||||
|
char elapsedFmt[24];
|
||||||
|
formatElapsed(elapsedFmt, sizeof(elapsedFmt), elapsedSinceSync);
|
||||||
|
char lastSyncStr[48];
|
||||||
|
snprintf(lastSyncStr, sizeof(lastSyncStr), tr(STR_LAST_NTP_SYNC), elapsedFmt);
|
||||||
|
y += 25;
|
||||||
|
renderer.drawCenteredText(UI_10_FONT_ID, y, lastSyncStr);
|
||||||
|
}
|
||||||
|
|
||||||
const auto labels = mappedInput.mapLabels(tr(STR_BACK), "", "", "");
|
const auto labels = mappedInput.mapLabels(tr(STR_BACK), "", "", "");
|
||||||
GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
|
GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
|
||||||
|
|||||||
@@ -15,6 +15,10 @@ class SyncTimeActivity final : public Activity {
|
|||||||
private:
|
private:
|
||||||
enum State { CONNECTING, SYNCING, SUCCESS, FAILED };
|
enum State { CONNECTING, SYNCING, SUCCESS, FAILED };
|
||||||
State state = CONNECTING;
|
State state = CONNECTING;
|
||||||
|
time_t preSyncTime = 0;
|
||||||
|
time_t prevSyncTime = 0;
|
||||||
|
int32_t driftSeconds = 0;
|
||||||
|
bool hadTimeBeforeSync = false;
|
||||||
void onWifiSelectionComplete(bool success);
|
void onWifiSelectionComplete(bool success);
|
||||||
void onWifiSelectionCancelled();
|
void onWifiSelectionCancelled();
|
||||||
void performSync();
|
void performSync();
|
||||||
|
|||||||
Reference in New Issue
Block a user