Add Interstellar and Your Name pages

Interstellar: Gargantua with a time dilation clock (Earth today vs.
Miller's planet), TARS with his settings and remarks about the house,
the Endurance spinning at a solar-driven RPM while a Ranger docks, and
the tesseract's bookshelf with the time in binary dust and the Message's
first word in Morse on a watch.

Your Name: comet Tiamat splitting over Itomori's lake, and
kataware-doki, a countdown to sunset from sun.sun where two silhouettes
stand on the crater rim during the twilight hour.

HomeData gains sunset, sunrise and sun elevation (with an ISO time
parser); wrap() and typed() move to el512_pages.h. Share Tech Mono 22
gets the full Latin set. All pages are in the renderer, checked with
normal, busy and empty data.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
mangavalkandClaude Opus 5.5 committed 2026-10-19 18:59:00 +02:00
1 parent a4ce97d744
commit f46f7ab6c5
22 files changed
+1159 -110

No files matched your search

+66
View File
@@ -9,7 +9,9 @@
#include <cstdint>
#include <cstdio>
#include <string>
#include <vector>
#include "el512_helpers.h"
#include "esphome/components/display/display.h"
#include "esphome/core/time.h"
@@ -34,6 +36,9 @@ struct HomeData {
std::string agenda; // sensor.el512_agenda events: "day|time|title;..."
std::string message; // the panel's Message text
std::string printer; // 3D printer state (Moonraker: printing, paused, error, ...)
int64_t sunset{0}; // next sunset, Unix time (sun.sun next_setting); 0 = unknown
int64_t sunrise{0}; // next sunrise, Unix time (sun.sun next_rising); 0 = unknown
float sun_elevation{NAN}; // degrees above the horizon
Reading rooms[4];
// Today's solar power in 15-minute slots (highest value seen per slot; -1 =
@@ -96,6 +101,30 @@ inline std::string upper(std::string s) {
return s;
}
// Days since 1970-01-01 for a civil date (Howard Hinnant's algorithm).
inline int64_t days_from_civil(int y, int m, int d) {
y -= m <= 2;
const int era = (y >= 0 ? y : y - 399) / 400;
const int yoe = y - era * 400;
const int doy = (153 * (m + (m > 2 ? -3 : 9)) + 2) / 5 + d - 1;
const int doe = yoe * 365 + yoe / 4 - yoe / 100 + doy;
return (int64_t) era * 146097 + doe - 719468;
}
// "2026-10-19T16:32:10.123+00:00" (as Home Assistant sends datetimes) to Unix
// time; 0 if it doesn't parse.
inline int64_t parse_iso_utc(const std::string &s) {
int y, mo, d, h, mi, se;
if (sscanf(s.c_str(), "%d-%d-%dT%d:%d:%d", &y, &mo, &d, &h, &mi, &se) != 6)
return 0;
int64_t t = days_from_civil(y, mo, d) * 86400 + h * 3600 + mi * 60 + se;
const size_t p = s.find_first_of("+-", 19);
int oh, om;
if (p != std::string::npos && sscanf(s.c_str() + p + 1, "%d:%d", &oh, &om) == 2)
t -= (s[p] == '+' ? 1 : -1) * (int64_t) (oh * 3600 + om * 60);
return t;
}
inline std::string lower(std::string s) {
for (auto &c : s)
c = (char) tolower((unsigned char) c);
@@ -108,6 +137,43 @@ inline int text_width(display::Display &it, display::BaseFont *font, const char
return w;
}
// Greedy word wrap into at most max_lines lines of `width` pixels; the last
// line ends in "..." when text is left over.
inline std::vector<std::string> wrap(display::Display &it, display::BaseFont *font, const std::string &text, int width,
size_t max_lines) {
std::vector<std::string> lines;
std::string line;
size_t i = 0;
while (i <= text.size()) {
size_t j = text.find(' ', i);
if (j == std::string::npos)
j = text.size();
const std::string word = text.substr(i, j - i);
const std::string joined = line.empty() ? word : line + " " + word;
if (!line.empty() && text_width(it, font, joined.c_str()) > width) {
lines.push_back(line);
line = word;
} else {
line = joined;
}
i = j + 1;
}
if (!line.empty())
lines.push_back(line);
if (lines.size() > max_lines) {
lines.resize(max_lines);
lines.back() += "...";
}
for (auto &l : lines)
l = fit(font, l, width);
return lines;
}
// The part of `s` typed so far at `cps` characters per second.
inline std::string typed(const std::string &s, uint32_t t, int cps) {
return s.substr(0, std::min<size_t>(s.size(), (size_t) t * cps / 1000));
}
// Draw a sprite (optionally only its first `rows` rows), scaled up in blocks.
inline void sprite(display::Display &it, const Sprite &s, int x, int y, int scale = 1, int rows = -1,
Color color = display::COLOR_ON) {