Files
planar-EL512.256-H/components/el512/el512_pages.h
T

142 lines
4.1 KiB
C++
Raw Normal View History

2026-10-18 23:46:24 +02:00
// Shared pieces for the themed ESPHome pages (cyberpunk.cpp, konosuba.cpp): the
// Home Assistant values they show, and small drawing helpers.
#pragma once
#include <algorithm>
2026-10-18 23:46:24 +02:00
#include <cctype>
#include <cmath>
#include <cstdarg>
#include <cstdint>
#include <cstdio>
#include <string>
#include "esphome/components/display/display.h"
#include "esphome/core/time.h"
2026-10-18 23:46:24 +02:00
namespace esphome::el512 {
struct Reading {
std::string name;
float value{NAN};
};
// Home Assistant values shown on the pages; NAN or "" when unknown. Filled
// from YAML (see the cp_home global in el512-panel.yaml).
struct HomeData {
std::string weather; // condition, e.g. "partlycloudy"
float temp{NAN}; // °C
float humidity{NAN}; // %
float wind{NAN}; // km/h
float solar{NAN}; // W
float solar_today{NAN}; // Wh produced today
float house{NAN}; // W
float grid{NAN}; // W, > 0 = import
std::string agenda; // sensor.el512_agenda events: "day|time|title;..."
std::string message; // the panel's Message text
2026-10-18 23:46:24 +02:00
Reading rooms[4];
// Today's solar power in 15-minute slots (highest value seen per slot; -1 =
// no data yet). Fed by record(), once a second from YAML.
static constexpr int SLOTS = 96;
float solar_slots[SLOTS];
int slots_day{-1};
HomeData() {
for (auto &s : this->solar_slots)
s = -1;
}
void record(ESPTime now) {
if (!now.is_valid())
return;
if (now.day_of_year != this->slots_day) {
this->slots_day = now.day_of_year;
for (auto &s : this->solar_slots)
s = -1;
}
float &slot = this->solar_slots[now.hour * 4 + now.minute / 15];
if (!std::isnan(this->solar))
slot = std::max(slot, this->solar);
}
};
// 1-bit sprite: rows of '#' (lit) and anything else (dark). Generated by the
// tools/*_sprites.py files.
struct Sprite {
uint8_t w, h;
const char *const *rows;
2026-10-18 23:46:24 +02:00
};
namespace fx {
// Integer hash for repeatable pseudo-random effects (lowbias32).
inline uint32_t hash(uint32_t x) {
x ^= x >> 16;
x *= 0x7feb352d;
x ^= x >> 15;
x *= 0x846ca68b;
x ^= x >> 16;
return x;
}
inline uint32_t hash(uint32_t a, uint32_t b) { return hash(a * 0x9e3779b9u ^ hash(b)); }
inline std::string str(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
inline std::string str(const char *fmt, ...) {
char buf[128];
va_list args;
va_start(args, fmt);
vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
return buf;
}
inline std::string upper(std::string s) {
for (auto &c : s)
c = (char) toupper((unsigned char) c);
return s;
}
inline int text_width(display::Display &it, display::BaseFont *font, const char *text) {
int x, y, w, h;
it.get_text_bounds(0, 0, text, font, display::TextAlign::TOP_LEFT, &x, &y, &w, &h);
return w;
}
// 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) {
const int h = rows < 0 ? s.h : std::min<int>(rows, s.h);
for (int r = 0; r < h; r++) {
for (int c = 0; c < s.w; c++) {
if (s.rows[r][c] != '#')
continue;
if (scale == 1)
it.draw_pixel_at(x + c, y + r, color);
else
it.filled_rectangle(x + c * scale, y + r * scale, scale, scale, color);
}
}
}
// Point on a circle; angle in degrees, 0 = up, clockwise.
inline void polar(int cx, int cy, float r, float a, int *x, int *y) {
constexpr float DEG = 3.14159265f / 180.0f;
*x = cx + (int) std::lround(r * std::sin(a * DEG));
*y = cy - (int) std::lround(r * std::cos(a * DEG));
}
// Circular arc from angle a0 to a1 (degrees, as polar()).
inline void arc(display::Display &it, int cx, int cy, float r, float a0, float a1) {
const int steps = std::max(2, (int) (std::fabs(a1 - a0) / 5));
int px, py;
polar(cx, cy, r, a0, &px, &py);
for (int i = 1; i <= steps; i++) {
int nx, ny;
polar(cx, cy, r, a0 + (a1 - a0) * i / steps, &nx, &ny);
it.line(px, py, nx, ny);
px = nx;
py = ny;
}
}
2026-10-18 23:46:24 +02:00
} // namespace fx
} // namespace esphome::el512