97 lines
3.4 KiB
C++
97 lines
3.4 KiB
C++
inline int measure_width(const char* text, esphome::display::BaseFont& font) {
|
|
int width;
|
|
int x_offset;
|
|
int baseline;
|
|
int height;
|
|
font.measure(text, &width, &x_offset, &baseline, &height);
|
|
return width;
|
|
}
|
|
|
|
inline int measure_baseline(const char* text,
|
|
esphome::display::BaseFont& font) {
|
|
int width;
|
|
int x_offset;
|
|
int baseline;
|
|
int height;
|
|
font.measure(text, &width, &x_offset, &baseline, &height);
|
|
return baseline;
|
|
}
|
|
|
|
inline void render_sensor(esphome::display::Display& it, int x, int y,
|
|
float value, std::string unit,
|
|
const std::string& label) {
|
|
int normal_height = measure_baseline("X", id(normal_font));
|
|
char formatted[20];
|
|
if (std::isnan(value)) {
|
|
it.print(x, y, &id(normal_font), TextAlign::TOP_CENTER, "--");
|
|
} else {
|
|
char value_text[20];
|
|
if (std::abs(value) >= 2000) {
|
|
unit = "k" + unit;
|
|
value /= 1000;
|
|
}
|
|
if (std::abs(value) < 10) {
|
|
sprintf(value_text, "%.1f", value);
|
|
} else {
|
|
sprintf(value_text, "%.0f", value);
|
|
}
|
|
int value_width = measure_width(value_text, id(normal_font));
|
|
int unit_width = measure_width(unit.c_str(), id(small_font));
|
|
int width = value_width + unit_width + 3;
|
|
it.print(x - width / 2, y + normal_height, &id(normal_font),
|
|
TextAlign::BASELINE_LEFT, value_text);
|
|
it.print(x + width / 2 - unit_width, y + normal_height, &id(small_font),
|
|
TextAlign::BASELINE_LEFT, unit.c_str());
|
|
}
|
|
it.print(x, y + normal_height + 3, &id(small_font), TextAlign::TOP_CENTER,
|
|
label.c_str());
|
|
}
|
|
|
|
inline void render(esphome::display::Display& it) {
|
|
constexpr int kHeight = 540;
|
|
constexpr int kWidth = 960;
|
|
|
|
// Clock
|
|
ESPTime now = id(rtc_time).now();
|
|
float seconds = now.second + now.minute * 60 + now.hour * 3600;
|
|
int rounded_minutes = static_cast<int>(std::roundf(seconds / 60 / 5)) * 5;
|
|
it.printf(15, 8, &id(clock_font), TextAlign::TOP_LEFT, "%d:%02d",
|
|
rounded_minutes / 60, rounded_minutes % 60);
|
|
|
|
float outside = (!std::isnan(id(ruuvi_outside_temperature).state)
|
|
? id(ruuvi_outside_temperature).state
|
|
: id(outside_temperature).state);
|
|
int right_width = measure_width("123||", id(normal_font));
|
|
render_sensor(it, kWidth - right_width / 2, kHeight * 7 / 100, outside, "°C",
|
|
"Outside");
|
|
render_sensor(it, kWidth - right_width / 2, kHeight * 58 / 100,
|
|
id(scd40_temperature).state, "°C", "Inside");
|
|
|
|
int bottom_width = measure_width("1999|", id(normal_font));
|
|
render_sensor(it, bottom_width / 2 + kWidth * 0 / 100, kHeight * 58 / 100,
|
|
id(scd40_co2).state, "", "CO2 ppm");
|
|
render_sensor(it, bottom_width / 2 + kWidth * 33 / 100, kHeight * 58 / 100,
|
|
id(solar_power).state, "W", "Solar");
|
|
|
|
static const struct {
|
|
float level;
|
|
std::string icon;
|
|
} battery_levels[] = {
|
|
{10, "mdi-battery-alert-variant-outline"},
|
|
{40, "mdi-battery-low"},
|
|
{70, "mdi-battery-medium"},
|
|
{std::numeric_limits<float>::max(), "mdi-battery-high"},
|
|
};
|
|
|
|
// Battery
|
|
float battery_level = id(m5paper_battery_level).state;
|
|
if (!std::isnan(battery_level)) {
|
|
for (const auto& level : battery_levels) {
|
|
if (battery_level <= level.level) {
|
|
it.print(910, 10, &id(battery_font),
|
|
id(material_icons_map)[level.icon].c_str());
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|