Repository navigation
Expand file tree
/
Copy pathclock.py
More file actions
54 lines (42 loc) · 1.8 KB
/
Copy pathclock.py
File metadata and controls
54 lines (42 loc) · 1.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
"""Pure time-to-display rendering logic.
No hardware, no I/O — just turns a datetime into what the four digits and the
colon should show. Kept separate so it can be unit-tested off-Pi.
"""
from __future__ import annotations
from dataclasses import dataclass
from datetime import datetime
#: What to show before the system clock has synchronized after boot, so the
#: clock never displays a confidently-wrong time.
UNSYNCED_TEXT = "----"
@dataclass(frozen=True)
class DisplayState:
"""Desired display contents: four characters, colon, and sync-indicator dot."""
text: str # exactly 4 chars; space means a blank digit
colon: bool
sync_dot: bool = False
def render(
now: datetime,
synced: bool,
*,
ever_synced: bool = False,
hour24: bool = True,
blink: bool = False,
) -> DisplayState:
"""Render the current local time into a DisplayState.
Until the clock has synced for the first time, returns dashes with the
colon off — never a confidently-wrong time. Once synced, formats HH:MM
with the sync dot lit; in 12-hour mode the leading zero of the hour is
blanked. If sync is later lost (``synced`` False, ``ever_synced`` True)
the time stays up — the system clock free-runs and remains approximately
right — and only the sync dot goes dark. The colon is steady by default;
when ``blink`` is set it is lit only for the first half of each second.
"""
if not synced and not ever_synced:
return DisplayState(UNSYNCED_TEXT, colon=False)
if hour24:
text = f"{now.hour:02d}{now.minute:02d}"
else:
hour12 = (now.hour - 1) % 12 + 1
text = f"{hour12:2d}{now.minute:02d}" # space-pads a single-digit hour
colon = (now.microsecond < 500_000) if blink else True
return DisplayState(text, colon, sync_dot=synced)