Public Access
Stopwatch counts in real time from a start date, kept over a restart
The stopwatch counted with millis(), so it started at 0 after every restart and would overflow after 49 days. It now keeps the real start time (UTC ms) and the time counted before a pause, stored in NVS (system/stopwatch_store) on every change, so it keeps counting while the display is off or restarting. Stop pauses, Start continues, and the Stopwatch tab can set the start to a date and time (local, summer time by mktime) to count from, e.g. days since an event. Start, stop and set need the synced time. New page formats: 12d 4:05:09 and 3w 2d. Version 2.19.0, tested on the display over OTA (set start, future and invalid dates refused, pause, restart). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
f5e77c7eca
commit
0166d0ee46
20 files changed
+278
-67
No files matched your search
@@ -1475,21 +1475,42 @@ void test_countdown_shows_seconds_only_when_needed()
|
||||
|
||||
void test_stopwatch()
|
||||
{
|
||||
const int64_t T = 1760000000000LL; // ms since 1970, in 2025
|
||||
Stopwatch sw;
|
||||
TEST_ASSERT_EQUAL_UINT32(0, sw.elapsed(5000));
|
||||
sw.start(1000);
|
||||
TEST_ASSERT_EQUAL_UINT64(0, sw.elapsed(T));
|
||||
sw.start(T + 1000);
|
||||
TEST_ASSERT_TRUE(sw.running());
|
||||
TEST_ASSERT_EQUAL_UINT32(2000, sw.elapsed(3000));
|
||||
sw.stop(4000);
|
||||
TEST_ASSERT_EQUAL_UINT32(3000, sw.elapsed(9000));
|
||||
sw.start(10000);
|
||||
sw.start(11000); // already running: no restart
|
||||
TEST_ASSERT_EQUAL_UINT32(5000, sw.elapsed(12000));
|
||||
TEST_ASSERT_EQUAL_UINT64(2000, sw.elapsed(T + 3000));
|
||||
sw.stop(T + 4000);
|
||||
TEST_ASSERT_EQUAL_UINT64(3000, sw.elapsed(T + 9000));
|
||||
sw.start(T + 10000);
|
||||
sw.start(T + 11000); // already running: no restart
|
||||
TEST_ASSERT_EQUAL_UINT64(5000, sw.elapsed(T + 12000));
|
||||
TEST_ASSERT_EQUAL_UINT64(3000, sw.elapsed(T + 5000)); // clock set back: never less than before
|
||||
sw.reset();
|
||||
TEST_ASSERT_FALSE(sw.running());
|
||||
TEST_ASSERT_EQUAL_UINT32(0, sw.elapsed(20000));
|
||||
sw.start(0xFFFFFF00u); // across the millis() overflow
|
||||
TEST_ASSERT_EQUAL_UINT32(0x200, sw.elapsed(0x100));
|
||||
TEST_ASSERT_EQUAL_UINT64(0, sw.elapsed(T + 20000));
|
||||
|
||||
// Past 49 days (millis() would overflow)
|
||||
sw.start(T);
|
||||
TEST_ASSERT_EQUAL_UINT64(60ULL * 86400000ULL, sw.elapsed(T + 60LL * 86400000LL));
|
||||
|
||||
// A start date by hand: counts from there, pausing keeps the time
|
||||
TEST_ASSERT_FALSE(sw.setStart(T + 1000, T)); // in the future
|
||||
TEST_ASSERT_TRUE(sw.setStart(T - 3 * 86400000LL, T));
|
||||
TEST_ASSERT_TRUE(sw.running());
|
||||
TEST_ASSERT_EQUAL_UINT64(3 * 86400000ULL, sw.elapsed(T));
|
||||
sw.stop(T);
|
||||
TEST_ASSERT_EQUAL_UINT64(3 * 86400000ULL, sw.elapsed(T + 5000));
|
||||
|
||||
// Kept over a restart (system/stopwatch_store stores the state)
|
||||
Stopwatch copy;
|
||||
copy.restore(sw.state());
|
||||
TEST_ASSERT_FALSE(copy.running());
|
||||
TEST_ASSERT_EQUAL_UINT64(3 * 86400000ULL, copy.elapsed(T + 99999));
|
||||
sw.start(T + 1000);
|
||||
copy.restore(sw.state());
|
||||
TEST_ASSERT_EQUAL_UINT64(3 * 86400000ULL + 1000, copy.elapsed(T + 2000));
|
||||
|
||||
PageElement e; // textOf: 65 s on the stopwatch
|
||||
e.type = ElementType::Stopwatch;
|
||||
@@ -1502,6 +1523,29 @@ void test_stopwatch()
|
||||
TEST_ASSERT_EQUAL_STRING("T 0:01:05", textOf(e).c_str());
|
||||
TEST_ASSERT_TRUE(elementShowsSeconds(e, LocalTime(), true));
|
||||
TEST_ASSERT_FALSE(elementShowsSeconds(e, LocalTime(), false)); // stopped
|
||||
strcpy(e.text, "");
|
||||
|
||||
// Days and weeks
|
||||
ElementValues values;
|
||||
char text[40];
|
||||
e.format = STOPWATCH_D_H_MM_SS;
|
||||
values.stopwatch_ms = 65000;
|
||||
elementText(e, LocalTime(), values, text, sizeof(text));
|
||||
TEST_ASSERT_EQUAL_STRING("0:01:05", text); // below a day: without the days
|
||||
values.stopwatch_ms = (12ULL * 86400 + 4 * 3600 + 5 * 60 + 9) * 1000;
|
||||
elementText(e, LocalTime(), values, text, sizeof(text));
|
||||
TEST_ASSERT_EQUAL_STRING("12d 4:05:09", text);
|
||||
TEST_ASSERT_TRUE(elementShowsSeconds(e, LocalTime(), true));
|
||||
e.format = STOPWATCH_W_D;
|
||||
elementText(e, LocalTime(), values, text, sizeof(text));
|
||||
TEST_ASSERT_EQUAL_STRING("1w 5d", text);
|
||||
TEST_ASSERT_FALSE(elementShowsSeconds(e, LocalTime(), true));
|
||||
values.stopwatch_ms = 2ULL * 86400000 + 5000;
|
||||
elementText(e, LocalTime(), values, text, sizeof(text));
|
||||
TEST_ASSERT_EQUAL_STRING("2d", text);
|
||||
values.stopwatch_ms = 400ULL * 86400000; // more than a year, past 32 bit ms
|
||||
elementText(e, LocalTime(), values, text, sizeof(text));
|
||||
TEST_ASSERT_EQUAL_STRING("57w 1d", text);
|
||||
}
|
||||
|
||||
void test_home_assistant_multiplier()
|
||||
|
||||
Reference in new issue
Block a user