Add switchable clock display page

This commit is contained in:
2026-09-14 09:43:30 +02:00
parent afaaa9f4eb
commit 1fb90a6144
+103 -7
View File
@@ -149,6 +149,10 @@ globals:
type: bool type: bool
restore_value: true restore_value: true
initial_value: 'false' initial_value: 'false'
- id: clock_digital_view
type: bool
restore_value: true
initial_value: 'false'
- id: device_usage_view - id: device_usage_view
type: int type: int
restore_value: true restore_value: true
@@ -259,20 +263,22 @@ sensor:
script: script:
- id: show_previous_page - id: show_previous_page
then: then:
- lambda: id(page_index) = (id(page_index) + 2 - 1) % 2; - lambda: id(page_index) = (id(page_index) + 3 - 1) % 3;
- component.update: tft - component.update: tft
- id: toggle_page_mode - id: toggle_page_mode
then: then:
- lambda: |- - lambda: |-
if (id(page_index) == 0) { if (id(page_index) == 0) {
id(page_one_gauge_view) = !id(page_one_gauge_view); id(page_one_gauge_view) = !id(page_one_gauge_view);
} else { } else if (id(page_index) == 1) {
id(device_usage_view) = (id(device_usage_view) + 1) % 2; id(device_usage_view) = (id(device_usage_view) + 1) % 2;
} else {
id(clock_digital_view) = !id(clock_digital_view);
} }
- component.update: tft - component.update: tft
- id: show_next_page - id: show_next_page
then: then:
- lambda: id(page_index) = (id(page_index) + 1) % 2; - lambda: id(page_index) = (id(page_index) + 1) % 3;
- component.update: tft - component.update: tft
button: button:
@@ -299,7 +305,7 @@ binary_sensor:
- platform: wireguard - platform: wireguard
enabled: enabled:
name: 'WireGuard Enabled' name: 'WireGuard Enabled'
# M5Stack Core button B (middle) toggles the alternate gauge view on page one. # M5Stack Core button B (middle) switches the current page's view.
- platform: gpio - platform: gpio
pin: pin:
number: GPIO38 number: GPIO38
@@ -462,7 +468,7 @@ display:
} else { } else {
it.printf(gauge_center_x, 169, id(font_title), solar_gauge_color, TextAlign::TOP_CENTER, "-- W"); it.printf(gauge_center_x, 169, id(font_title), solar_gauge_color, TextAlign::TOP_CENTER, "-- W");
} }
} else { } else if (id(page_index) == 1) {
// Page 2 lists nine consumers at once in two columns; button B changes group. // Page 2 lists nine consumers at once in two columns; button B changes group.
const int device_count = 18; const int device_count = 18;
const int usage_group = id(device_usage_view); const int usage_group = id(device_usage_view);
@@ -538,6 +544,93 @@ display:
} }
} }
if (id(page_index) == 2) {
const auto now = id(sntp_time).now();
const Color accent(143, 190, 223);
const Color gold(255, 170, 40);
const Color muted(55, 65, 80);
it.print(12, 10, id(font_device), accent, "Uhr · Berlin");
if (!now.is_valid()) {
it.print(160, 100, id(font_title), accent, TextAlign::TOP_CENTER, "--:--:--");
it.print(160, 190, id(font_small), Color::WHITE, TextAlign::TOP_CENTER,
"Warte auf Zeitsynchronisation");
} else {
if (!id(clock_digital_view)) {
const int cx = 160, cy = 111, radius = 74;
const float tau = 6.28318530718f;
it.filled_circle(cx, cy, radius, Color(12, 18, 28));
it.circle(cx, cy, radius, accent);
it.circle(cx, cy, radius - 3, muted);
for (int tick = 0; tick < 60; tick++) {
const float angle = tick * tau / 60.0f;
const int inner = tick % 5 == 0 ? radius - 13 : radius - 8;
it.line(cx + lroundf(sinf(angle) * inner), cy - lroundf(cosf(angle) * inner),
cx + lroundf(sinf(angle) * (radius - 5)),
cy - lroundf(cosf(angle) * (radius - 5)),
tick % 5 == 0 ? accent : muted);
}
it.print(cx, cy - 49, id(font_device), Color::WHITE, TextAlign::CENTER, "12");
it.print(cx + 50, cy, id(font_device), Color::WHITE, TextAlign::CENTER, "3");
it.print(cx, cy + 49, id(font_device), Color::WHITE, TextAlign::CENTER, "6");
it.print(cx - 50, cy, id(font_device), Color::WHITE, TextAlign::CENTER, "9");
// Round-ended hands; minutes and hours advance with the seconds.
auto hand = [&](float turns, int length, int thickness, Color color) {
const float angle = turns * tau;
for (int r = 0; r <= length; r++) {
it.filled_circle(cx + lroundf(sinf(angle) * r),
cy - lroundf(cosf(angle) * r), thickness, color);
}
};
hand((now.hour % 12 + now.minute / 60.0f + now.second / 3600.0f) / 12.0f,
34, 3, Color::WHITE);
hand((now.minute + now.second / 60.0f) / 60.0f, 51, 2, accent);
const float second_angle = now.second * tau / 60.0f;
it.line(cx - lroundf(sinf(second_angle) * 12), cy + lroundf(cosf(second_angle) * 12),
cx + lroundf(sinf(second_angle) * 60), cy - lroundf(cosf(second_angle) * 60), gold);
it.filled_circle(cx, cy, 4, gold);
it.filled_circle(cx, cy, 1, Color::BLACK);
} else {
// Draw seven-segment digits directly, avoiding an extra font dependency.
const uint8_t masks[10] = {0x3F, 0x06, 0x5B, 0x4F, 0x66,
0x6D, 0x7D, 0x07, 0x7F, 0x6F};
const int digits[6] = {now.hour / 10, now.hour % 10, now.minute / 10,
now.minute % 10, now.second / 10, now.second % 10};
const int positions[6] = {17, 61, 121, 165, 225, 269};
const int y = 77;
for (int digit = 0; digit < 6; digit++) {
const int x = positions[digit];
const Color lit = digit < 4 ? accent : gold;
for (int segment = 0; segment < 7; segment++) {
const Color color = (masks[digits[digit]] & (1 << segment))
? lit : Color(20, 27, 36);
const bool horizontal = segment == 0 || segment == 3 || segment == 6;
const int sx = horizontal ? x + 6 : x + ((segment == 1 || segment == 2) ? 30 : 0);
const int sy = y + (segment == 0 ? 0 : segment == 3 ? 72 : segment == 6 ? 36
: (segment == 1 || segment == 5) ? 6 : 42);
// Taper each segment's ends for the classic LED clock shape.
for (int stripe = 0; stripe < 6; stripe++) {
const int inset = stripe < 3 ? 2 - stripe : stripe - 3;
if (horizontal)
it.line(sx + inset, sy + stripe, sx + 23 - inset, sy + stripe, color);
else
it.line(sx + stripe, sy + inset, sx + stripe, sy + 29 - inset, color);
}
}
}
for (int x : {109, 213}) {
it.filled_circle(x, y + 24, 3, accent);
it.filled_circle(x, y + 54, 3, accent);
}
it.line(40, 172, 280, 172, muted);
}
const char *weekdays[] = {"Sonntag", "Montag", "Dienstag", "Mittwoch",
"Donnerstag", "Freitag", "Samstag"};
it.printf(160, 190, id(font_small), Color::WHITE, TextAlign::TOP_CENTER,
"%s, %02d.%02d.%04d", weekdays[now.day_of_week - 1],
now.day_of_month, now.month, now.year);
}
}
// Labels correspond to the left (A) and right (C) hardware buttons. // Labels correspond to the left (A) and right (C) hardware buttons.
it.printf(8, 239, id(font_small), Color::WHITE, TextAlign::BOTTOM_LEFT, it.printf(8, 239, id(font_small), Color::WHITE, TextAlign::BOTTOM_LEFT,
"< Zurück"); "< Zurück");
@@ -545,8 +638,11 @@ display:
"Weiter >"); "Weiter >");
if (id(page_index) == 0) { if (id(page_index) == 0) {
it.printf(160, 239, id(font_small), Color::WHITE, TextAlign::BOTTOM_CENTER, it.printf(160, 239, id(font_small), Color::WHITE, TextAlign::BOTTOM_CENTER,
"Ansicht · 1 / 2"); "Ansicht · 1 / 3");
} else { } else if (id(page_index) == 1) {
it.printf(160, 239, id(font_small), Color::WHITE, TextAlign::BOTTOM_CENTER, it.printf(160, 239, id(font_small), Color::WHITE, TextAlign::BOTTOM_CENTER,
"Geräte %d / 2", id(device_usage_view) + 1); "Geräte %d / 2", id(device_usage_view) + 1);
} else {
it.printf(160, 239, id(font_small), Color::WHITE, TextAlign::BOTTOM_CENTER,
"%s · 3 / 3", id(clock_digital_view) ? "Analog" : "Digital");
} }