Public Access
Driver (components/el512/el512_panel.*, ESP-IDF only): - DMA ring of 8 x 4 lines (17 KB) refilled from the I2S EOF interrupt (IRAM) instead of a 142 KB full-frame stream; ~107 KB heap freed. - 256-entry lookup table encodes 8 pixels per step. - Back buffer + displayed buffer, swapped at the start of a frame. - PlatformIO builds it via lib_extra_dirs (EL512Core); lib/EL512 keeps the Adafruit GFX front end. ESPHome external component (platform: el512): - DisplayBuffer with optional ENABLE / _LOWPWR pins, set_enabled(), set_low_power(), helper functions for page lambdas. - still_alive_page: plays the Portal end-credits show, then returns to the previous page. Still Alive engine moved to components/el512/still_alive.* with a built-in 5x7 font (from Adafruit GFX, BSD); the PlatformIO demo uses the same code. The importer writes components/el512/still_alive_data.h and stops at 200 s (--until-ms), matching the hand-trimmed data. esphome/el512-panel.yaml: 8 pages (clock, forecast, agenda, dashboard, now playing, Plex, solar, Still Alive), page select, rotation, display and low-power switches, message text. home_assistant/packages/el512_panel.yaml: helper template sensors for forecast, agenda, now playing and Plex streams. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
134 lines
5.6 KiB
YAML
134 lines
5.6 KiB
YAML
# Helper sensors for the EL512.256-H ESPHome display (esphome/el512-panel.yaml).
|
|
#
|
|
# Install: put this file in /config/packages/ and make sure configuration.yaml has
|
|
#
|
|
# homeassistant:
|
|
# packages: !include_dir_named packages
|
|
#
|
|
# then restart Home Assistant. All lists use the same compact text format so the
|
|
# ESP32 can split them cheaply: fields separated by "|", entries by ";".
|
|
|
|
template:
|
|
# Forecast and agenda come from actions, so they refresh on a timer.
|
|
- triggers:
|
|
- trigger: time_pattern
|
|
minutes: "/15"
|
|
- trigger: homeassistant
|
|
event: start
|
|
- trigger: event
|
|
event_type: event_template_reloaded
|
|
actions:
|
|
- action: weather.get_forecasts
|
|
target:
|
|
entity_id: weather.knmi_home
|
|
data:
|
|
type: daily
|
|
response_variable: fc
|
|
- action: calendar.get_events
|
|
target:
|
|
entity_id:
|
|
- calendar.mangavalk_gmail_com
|
|
- calendar.li_s_happy_home
|
|
- calendar.feestdagen_in_nederland
|
|
data:
|
|
duration:
|
|
days: 14
|
|
response_variable: cal
|
|
sensor:
|
|
# days: "Sun|cloudy|12|11|0;Mon|partlycloudy|14|10|20;..."
|
|
# weekday|condition|high|low|rain chance %
|
|
- name: EL512 forecast
|
|
unique_id: el512_forecast
|
|
icon: mdi:weather-partly-cloudy
|
|
state: "{{ fc['weather.knmi_home'].forecast | count }}"
|
|
attributes:
|
|
days: >-
|
|
{%- set ns = namespace(out=[]) -%}
|
|
{%- for d in fc['weather.knmi_home'].forecast[:7] -%}
|
|
{%- set ns.out = ns.out + [
|
|
(as_datetime(d.datetime) | as_local).strftime('%a') ~ '|' ~
|
|
d.condition ~ '|' ~
|
|
(d.temperature | round(0) | int) ~ '|' ~
|
|
(d.templow | default(d.temperature) | round(0) | int) ~ '|' ~
|
|
(d.precipitation_probability | default(0) | int)] -%}
|
|
{%- endfor -%}
|
|
{{ ns.out | join(';') }}
|
|
|
|
# events: "Mon 19|11:00|Work;Tue 20||Holiday;..."
|
|
# day|start time (empty = all day)|title
|
|
- name: EL512 agenda
|
|
unique_id: el512_agenda
|
|
icon: mdi:calendar
|
|
state: >-
|
|
{%- set ns = namespace(n=0) -%}
|
|
{%- for c in cal.values() -%}{%- set ns.n = ns.n + c.events | count -%}{%- endfor -%}
|
|
{{ ns.n }}
|
|
attributes:
|
|
events: >-
|
|
{%- set ns = namespace(ev=[]) -%}
|
|
{%- for c in cal.values() -%}
|
|
{%- for e in c.events -%}{%- set ns.ev = ns.ev + [e] -%}{%- endfor -%}
|
|
{%- endfor -%}
|
|
{%- set out = namespace(items=[]) -%}
|
|
{%- for e in (ns.ev | sort(attribute='start'))[:10] -%}
|
|
{%- if e.start | length == 10 -%}
|
|
{%- set day = strptime(e.start, '%Y-%m-%d').strftime('%a %d') -%}
|
|
{%- set time = '' -%}
|
|
{%- else -%}
|
|
{%- set t = as_datetime(e.start) | as_local -%}
|
|
{%- set day = t.strftime('%a %d') -%}
|
|
{%- set time = t.strftime('%H:%M') -%}
|
|
{%- endif -%}
|
|
{%- set title = (e.summary | default('')) | replace('|', '/') | replace(';', ',') -%}
|
|
{%- set out.items = out.items + [day ~ '|' ~ time ~ '|' ~ title[:40]] -%}
|
|
{%- endfor -%}
|
|
{{ out.items | join(';') }}
|
|
|
|
# Whatever media player is playing right now; position advances every 5 s.
|
|
- triggers:
|
|
- trigger: time_pattern
|
|
seconds: "/5"
|
|
sensor:
|
|
- name: EL512 now playing
|
|
unique_id: el512_now_playing
|
|
icon: mdi:play-circle
|
|
state: >-
|
|
{%- set p = states.media_player | selectattr('state', 'eq', 'playing') | list -%}
|
|
{{ p[0].entity_id if p else 'idle' }}
|
|
attributes:
|
|
# "title|artist|album|player|position s|duration s"
|
|
info: >-
|
|
{%- set p = states.media_player | selectattr('state', 'eq', 'playing') | list -%}
|
|
{%- if p -%}
|
|
{%- set a = p[0].attributes -%}
|
|
{%- set pos = a.media_position | default(0) -%}
|
|
{%- if a.media_position_updated_at is defined and a.media_position_updated_at -%}
|
|
{%- set pos = pos + (now() - as_datetime(a.media_position_updated_at)).total_seconds() -%}
|
|
{%- endif -%}
|
|
{%- set dur = a.media_duration | default(0) -%}
|
|
{%- set pos = [pos, dur] | min if dur else pos -%}
|
|
{{ [a.media_title | default(a.app_name | default('')), a.media_artist | default(a.media_series_title | default('')),
|
|
a.media_album_name | default(''), a.friendly_name | default(''), pos | int, dur | int]
|
|
| map('string') | map('replace', '|', '/') | join('|') }}
|
|
{%- endif -%}
|
|
|
|
# Plex: the server sensor has one attribute per stream ("user - client": "title").
|
|
- sensor:
|
|
- name: EL512 Plex streams
|
|
unique_id: el512_plex_streams
|
|
icon: mdi:plex
|
|
state: "{{ states('sensor.mangavalkserver') }}"
|
|
attributes:
|
|
# "user - client|title;..."
|
|
streams: >-
|
|
{%- set s = states.sensor.mangavalkserver -%}
|
|
{%- set ns = namespace(out=[]) -%}
|
|
{%- if s -%}
|
|
{%- for k, v in s.attributes.items()
|
|
if k not in ['unit_of_measurement', 'friendly_name', 'icon', 'device_class', 'state_class'] -%}
|
|
{%- set ns.out = ns.out + [(k | replace('|', '/') | replace(';', ',')) ~ '|' ~
|
|
(v | string | replace('|', '/') | replace(';', ','))] -%}
|
|
{%- endfor -%}
|
|
{%- endif -%}
|
|
{{ ns.out | join(';') }}
|