Add four animated Cyberpunk-style ESPHome pages

Netrunner HUD, self-solving breach protocol, optics boot-and-scan and a
split HUD with a mini breach matrix, all in the page rotation. The el512
display gains animated_pages / animation_interval (redraw ~15 fps while
shown), page_age_ms() as animation clock, and shift_rows() / invert_rect()
for glitch effects.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
mangavalkandClaude Opus 5.5 committed 2026-10-18 23:29:12 +02:00
1 parent 6d5e5315f0
commit 50ee17b3f6
7 files changed
+944 -4

No files matched your search

+79 -1
View File
@@ -14,6 +14,9 @@ substitutions:
esphome:
name: ${name}
friendly_name: ${friendly_name}
on_boot:
- lambda: |-
id(cp_fonts) = {id(f_cp_title), id(f_cp_label), id(f_cp_value), id(f_cp_huge), id(f_cp_mono), id(f_cp_code)};
esp32:
board: wemos_d1_mini32
@@ -56,6 +59,11 @@ globals:
- id: np_updated
type: uint32_t
initial_value: "0"
# Cyberpunk pages: their fonts and the home data they show.
- id: cp_fonts
type: el512::cyber::Fonts
- id: cp_home
type: el512::cyber::HomeData
# --- Fonts -------------------------------------------------------------------
font:
@@ -126,6 +134,31 @@ font:
size: 18
glyphs:
- "\U000F054B" # umbrella-outline
# Cyberpunk pages
- file: "gfonts://Orbitron@700"
id: f_cp_title
size: 18
glyphs: " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/_-.:>"
- file: "gfonts://Rajdhani@600"
id: f_cp_label
size: 18
glyphsets: [GF_Latin_Core]
- file: "gfonts://Rajdhani@700"
id: f_cp_value
size: 32
glyphs: " 0123456789.,:-+%°CkWh"
- file: "gfonts://Rajdhani@700"
id: f_cp_huge
size: 104
glyphs: "0123456789:"
- file: "gfonts://Share Tech Mono"
id: f_cp_mono
size: 14
glyphsets: [GF_Latin_Core]
- file: "gfonts://Share Tech Mono"
id: f_cp_code
size: 22
glyphs: " 0123456789ABCDEF."
# --- Data from Home Assistant -------------------------------------------------
text_sensor:
@@ -313,6 +346,10 @@ select:
- Plex
- Solar
- Still Alive
- Cyber HUD
- Cyber Breach
- Cyber Scan
- Cyber Split
initial_option: Clock
set_action:
- lambda: |-
@@ -325,6 +362,10 @@ select:
else if (x == "Now playing") p = id(page_media);
else if (x == "Plex") p = id(page_plex);
else if (x == "Solar") p = id(page_solar);
else if (x == "Cyber HUD") p = id(page_cyber_hud);
else if (x == "Cyber Breach") p = id(page_cyber_breach);
else if (x == "Cyber Scan") p = id(page_cyber_scan);
else if (x == "Cyber Split") p = id(page_cyber_split);
id(panel).show_page(p);
id(panel).update();
@@ -345,7 +386,7 @@ interval:
if (id(sw_pause).state || id(panel).is_still_alive_playing()) { id(rotation_elapsed) = 0; return; }
if (++id(rotation_elapsed) < (int) id(page_interval).state) return;
id(rotation_elapsed) = 0;
for (int i = 0; i < 8; i++) {
for (int i = 0; i < 12; i++) {
id(panel).show_next_page();
const auto *p = id(panel).get_active_page();
const std::string &np = id(np_state).state;
@@ -354,6 +395,22 @@ interval:
break;
}
id(panel).update();
# Home data for the Cyberpunk pages.
- interval: 1s
then:
- lambda: |-
auto &d = id(cp_home);
d.weather = id(weather_cond).state;
d.temp = id(weather_temp).state;
d.humidity = id(weather_hum).state;
d.wind = id(weather_wind).state;
d.solar = id(solar_power).state;
d.house = id(house_power).state;
d.grid = id(grid_import).state - id(grid_export).state;
d.rooms[0] = {"Woonkamer", id(t_woonkamer).state};
d.rooms[1] = {"Voorkamer", id(t_voorkamer).state};
d.rooms[2] = {"Patrick", id(t_patrick).state};
d.rooms[3] = {"Badkamer", id(t_badkamer).state};
# --- The panel and its pages ----------------------------------------------------
display:
@@ -363,6 +420,9 @@ display:
low_power_pin: GPIO26
update_interval: 1s
still_alive_page: page_still_alive
# Redrawn every animation_interval (~15 fps) while shown.
animated_pages: [page_cyber_hud, page_cyber_breach, page_cyber_scan, page_cyber_split]
animation_interval: 66ms
on_page_change:
- then:
- lambda: |-
@@ -374,6 +434,10 @@ display:
else if (to == id(page_plex)) name = "Plex";
else if (to == id(page_solar)) name = "Solar";
else if (to == id(page_still_alive)) name = "Still Alive";
else if (to == id(page_cyber_hud)) name = "Cyber HUD";
else if (to == id(page_cyber_breach)) name = "Cyber Breach";
else if (to == id(page_cyber_scan)) name = "Cyber Scan";
else if (to == id(page_cyber_split)) name = "Cyber Split";
if (id(page_select).current_option() != name) id(page_select).publish_state(name);
pages:
# 1. Clock, date and current weather
@@ -555,3 +619,17 @@ display:
- id: page_still_alive
lambda: |-
id(panel).draw_still_alive();
# 9-12. Cyberpunk-style animated pages (components/el512/cyberpunk.cpp)
- id: page_cyber_hud
lambda: |-
el512::cyber::netrunner_hud(*id(panel), id(cp_fonts), id(cp_home), id(ha_time).now());
- id: page_cyber_breach
lambda: |-
el512::cyber::breach_protocol(*id(panel), id(cp_fonts));
- id: page_cyber_scan
lambda: |-
el512::cyber::optics_scan(*id(panel), id(cp_fonts), id(cp_home), id(ha_time).now());
- id: page_cyber_split
lambda: |-
el512::cyber::split_hud(*id(panel), id(cp_fonts), id(cp_home), id(ha_time).now());