Files
planar-EL512.256-H/home_assistant/packages/el512_panel.yaml
T

158 lines
7.2 KiB
YAML
Raw Normal View History

# 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 streams with play/pause state and position, from the Plex integration's
# media players (media_player.plex_*); position advances every 5 s. Without
# any Plex players, falls back to the server sensor, which has one attribute
# per stream ("user - client": "title") but no state or position.
- triggers:
- trigger: time_pattern
seconds: "/5"
sensor:
- name: EL512 Plex streams
unique_id: el512_plex_streams
icon: mdi:plex
state: "{{ states('sensor.mangavalkserver') }}"
attributes:
# "who|title|playing or paused|position s|duration s;..."
# (fallback: "user - client|title;...")
streams: >-
{%- set ns = namespace(out=[]) -%}
{%- for p in states.media_player
if p.entity_id.startswith('media_player.plex_') and p.state in ['playing', 'paused'] -%}
{%- set a = p.attributes -%}
{%- set pos = a.media_position | default(0) -%}
{%- if p.state == 'playing' and 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 -%}
{%- set title = a.media_title | default('') -%}
{%- if a.media_series_title | default('') -%}
{%- set title = a.media_series_title ~ ' - ' ~ title -%}
{%- endif -%}
{%- set who = a.username | default(a.friendly_name | default(p.entity_id)) -%}
{%- set ns.out = ns.out + [[who, title, p.state, pos | int, dur | int]
| map('string') | map('replace', '|', '/') | map('replace', ';', ',')
| join('|')] -%}
{%- endfor -%}
{%- set s = states.sensor.mangavalkserver -%}
{%- if not ns.out and 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(';') }}