Przydatne szablony jinja2 w HA

Przydatne szablony do wyświetlania różnego typu informacji które mogą się przydać.
Zachęcam do dodawania swoich ciekawych użytecznych szablonów które można wykorzystać w powiadomieniach itp. Pomyślałem że zgromadzenie ich w jednym temacie nie jednemu początkującemu i nie tylko może się przydać. Zacznę może ja :stuck_out_tongue:

Informacja kiedy będzie kolejne wydarzenie w kalendarzu. calendar.urodziny (zamień na swoją encje kalendarza)

{% set now = utcnow() %}
{% set calendar_event = state_attr('calendar.urodziny', 'start_time') %} 
{% if calendar_event %}
  {% set event_time = as_datetime(calendar_event).astimezone(now.tzinfo) %}
  {% set time_left = event_time - now %}
  Czas do najbliższego wydarzenia w kalendarzu: {{ time_left.days }} dni, {{ time_left.seconds // 3600 }} godzin, {{ (time_left.seconds % 3600) // 60 }} minut.
{% else %}
  Brak nadchodzącego wydarzenia.
{% endif %}

Ilość dni do Nowego Roku

{% set new_year = now().replace(month=1, day=1, year=now().year + 1).date() %}
{% set days_left = (new_year - now().date()).days %}{{ days_left }}

Kierunek wiatru (u mnie pobiera to z integracji wbudowanej weather.home i atrybutu wind_bearing

{% set winbearing = (state_attr('weather.home', 'wind_bearing') | float / 45) | int | round %}
{% set winddir = ['Północny', 'Północno Wschodni', 'Wschodni', 'Południowo Wschodni', 'Południowy', 'Południowo Zachodni', 'Zachodni', 'Północno Zachodni'] %}
{{ winddir[winbearing % winddir | length] }}

Ilość włączonych świateł i jakie.

{% set lights_on = states.light | selectattr('state', 'equalto', 'on') | list %}
Obecnie włączonych świateł: {{ lights_on | length }}
{% if lights_on | length > 0 %}
    Światła, które są włączone:
    {% for light in lights_on %}
      - {{ light.name }} {% endfor %}
{% else %}
    Brak włączonych świateł.
{% endif %}

Procentowo ilość włączonych i wyłączonych świateł .

{% set lights = states.light %}
{% set total_lights = lights | selectattr('state', 'in', ['on', 'off']) | list %}
{% set on_lights = lights | selectattr('state', 'equalto', 'on') | list %}
{% set off_lights = lights | selectattr('state', 'equalto', 'off') | list %}

{% set on_percentage = (on_lights | length / total_lights | length * 100) | round(2) %}
{% set off_percentage = (off_lights | length / total_lights | length * 100) | round(2) %}

Włączonych świateł : {{ on_percentage }}%
Wyłączonych świateł: {{ off_percentage }}%

Ile dziś zostało uruchomionych automatyzacji.

{% set today = now().strftime('%Y-%m-%d') %}
{% set automations_today = states.automation | selectattr('attributes.last_triggered', 'defined') | selectattr('attributes.last_triggered', 'search', today) | list | length %}
Dziś uruchomiono {{ automations_today }} automatyzacji.

Procent urządzeń o stanie niedostępnym:

{% set unavailable_entities = states | selectattr('state', 'equalto', 'unavailable') | list %}
{% set total_entities = states | list %}
{% if total_entities %}
    Niedostępne: {{ (unavailable_entities | length / total_entities | length * 100) | round(1) }}%
{% else %}
    Brak danych o urządzeniach.
{% endif %}

Średnia temperatura w domu z wszystkich czujników

{% set temp_sensors = states.sensor | selectattr('attributes.device_class', 'equalto', 'temperature') | map(attribute='state') | map('float', default=0) | list %}
{% if temp_sensors %}
    Średnia temperatura: {{ (temp_sensors | sum / temp_sensors | length) | round(1) }} °C
{% else %}
    Brak czujników temperatury.
{% endif %}

Edit.

Pozostały czas do zamknięcia / otwarcia rolet (warunek że zamykają się o zachodzie i otwierają o wschodzie jak u mnie / do zamiany encja rolety lub encja grupy rolet jak w moim przypadku cover.wszystkie_rolety.

{% set sunrise = as_timestamp(state_attr('sun.sun', 'next_rising')) %}
{% set sunset = as_timestamp(state_attr('sun.sun', 'next_setting')) %}
{% set now = as_timestamp(now()) %}

{% if is_state('cover.wszystkie_rolety', 'open') %}
    {% set time_until_event = sunset - now %}
    {% set event_type = 'zamknięcia rolet' %}
{% else %}
    {% set time_until_event = sunrise - now %}
    {% set event_type = 'otwarcia rolet' %}
{% endif %}

{% if time_until_event > 0 %}
Czas do {{ event_type }} : {{ (time_until_event // 3600) | int }} godzin i {{ ((time_until_event % 3600) // 60) | int }} minut{% else %}{% endif %}

Czas zachodu - wschodu słońca.

{% set sunrise = as_datetime(state_attr('sun.sun', 'next_rising')) | as_local %}
{% set sunset = as_datetime(state_attr('sun.sun', 'next_setting')) | as_local %}

Wschód słońca: {{ sunrise.strftime('%H:%M') }}
Zachód słońca: {{ sunset.strftime('%H:%M') }}

Szablon nasłuchujący czy wszystkie okna są zamknięte ,jeśli nie wymienia które.

{% set open_windows = states.binary_sensor | selectattr('attributes.device_class', 'equalto', 'window') | selectattr('state', 'equalto', 'on') | map(attribute='name') | list %}
{% if open_windows %}
    Otwarte okna: {{ open_windows | join(', ') }}
{% else %}
    Wszystkie okna są zamknięte.
{% endif %}

Edit…

Długość dnia

{% set day_length = as_timestamp(state_attr('sun.sun', 'next_setting')) - as_timestamp(state_attr('sun.sun', 'next_rising')) %}
Długość dnia: {{ (day_length // 3600) | int }} godzin i {{ ((day_length % 3600) // 60) | int }} minut

6 polubień

Trzeba wiedzieć, że ta średnia to także z tych, które podają temperaturę np. procesora, (46’C), airly (-1;C), … itd można to zresztą sprawdzić …


{% set temp_sensors = states.sensor | selectattr('attributes.device_class', 'equalto', 'temperature') | list %}
{% if temp_sensors %}
    {% for sensor in temp_sensors %}
        - {{ sensor.name }}: {{ sensor.state }} °C
    {% endfor %}
    Średnia temperatura: {{ (temp_sensors | map(attribute='state') | map('float', default=0) | sum / temp_sensors | length) | round(1) }} °C
{% else %}
    Brak czujników temperatury.
{% endif %}

Wyciągam na wierzch , może ktoś coś ciekawego dołoży :stuck_out_tongue: .

Szablon do użycia w automatyzacji powiadamiania o zmianie strefy. Brak strefy nieznanej (poza domem), jest tylko jeśli osoba wyszła z domu,wróciła do domu, wyszła z danej strefy , weszła do danej strefy. Do zmiany person _name na swój i wiadomo jeśli płeć przeciwna to końcówki wszedł, weszła :smiley: .

variables:
  prev_zone: "{{ trigger.from_state.state | default('unknown') }}"
  current_zone: "{{ trigger.to_state.state | default('unknown') }}"
  person_name: "Rafał"

action:
  - service: notify.mobile_app_lenovo_tb_j606f
    data:
      message: TTS
      data:
        tts_text: >-
          {% if current_zone == 'home' %}
            {{ person_name }} wrócił do domu.
          {% elif prev_zone == 'home' and current_zone != 'not_home' %}
            {{ person_name }} wszedł do strefy {{ current_zone }}.
          {% elif prev_zone == 'home' and current_zone == 'not_home' %}
            {{ person_name }} wyszedł z domu.
          {% elif current_zone != 'home' and prev_zone != 'home' and current_zone != 'not_home' %}
            {{ person_name }} wszedł do strefy {{ current_zone }}.
          {% else %}
            {{ person_name }} wyszedł ze strefy {{ prev_zone }}.
          {% endif %}

Ile minęło od daty (lat, miesięcy, dni) + suma dni

  - sensor:
    - name: xxxx ile żyje 
      icon: mdi:counter
      unique_id: xxxx_ile_zyje
      state: >
          {% set start_date = '2021-11-27' | as_datetime %}
          {% set current_date = now().replace(tzinfo=None) %}
          {% set years = current_date.year - start_date.year %}
          {% set months = current_date.month - start_date.month %}
          {% set days = current_date.day - start_date.day %}
        
          {% if days < 0 %}
          {% set months = months - 1 %}
          {% set days = days + 30 %}
          {% endif %}
        
          {% if months < 0 %}
            {% set years = years - 1 %}
            {% set months = months + 12 %}
          {% endif %}
        
          {% set total_days_all = (current_date - start_date).days %}
  
          {% set years_label = "lat" %}
          {% if years == 1 %}
          {% set years_label = "rok" %}
          {% elif years in [2, 3, 4] %}
          {% set years_label = "lata" %}
          {% endif %}
    
          {% set months_label = "miesięcy" %}
          {% if months == 1 %}
          {% set months_label = "miesiąc" %}
          {% elif months in [2, 3, 4] %}
          {% set months_label = "miesiące" %}
          {% endif %}
  
          {% set days_label = "dni" %}
          {% if days == 1 %}
          {% set days_label = "dzień" %}
          {% endif %}
          "XXXX  2021-11-27 - {{ years }} {{ years_label }}, {{ months }} {{ months_label }}, {{ days }} {{ days_label }}. Czyli: {{ total_days_all }} dni"

Wynik:

XXXX 2021-11-27 - 3 lata, 0 miesięcy, 4 dni. Czyli: 1100 dni

1 polubienie

Sensor typu “trigger-based”, który dodaje do lokalnego kalendarza funkcję powiadomień wysyłanych do aplikacji na telefonie. Powiadomienia są powtarzane aż do “tapnięcia” w wiadomości, że zdarzenie zostało “ogarnięte” (albo skończy się dany dzień).

kod
- trigger:
  - trigger: homeassistant
    event: start
    id: 'ha_start'
  - trigger: event
    event_type: event_template_reloaded
    id: 'template_reload'
  # dodawanie do słownika nowych zdarzeń z kalendarza, gdy się zaczną
  - trigger: calendar
    entity_id: calendar.sprawy_domowe
    event: start
    offset: "0:0:0"
    id: 'calendar'
  # wysyłanie powiadomień
  - trigger: time_pattern
    minutes: /5
    seconds: 15
    id: 'time'
  # usuwanie ze słownika pozycji, które kliknąłem w telefonie jako "zrobione"
  # nie filtruję w tym miejscu po nazwie akcji, gdyż jest ona zmienna
  - trigger: event
    event_type: mobile_app_notification_action
    id: 'handled'
  # usuwanie ze słownika pozycji starszych niż "z dziś", codziennie o 1:01
  - trigger: time_pattern
    hours: 1
    minutes: 1
    id: 'cleaning'
  action:
    - variables:
        # co tyle minut jest wysyłane powiadomienie
        NOTIFY_MINUTES: "{{ 30 }}"
        
        # Timestamp bieżącego momentu, z dokładnością do minuty.
        # Używam go aby zapisać czas wysłania ostatniego powiadomienia dla danego zdarzenia.
        # Ten czas jest precyzyjnie równy minucie odpalenia triggera "time"
        nTs: "{{ as_datetime(now().replace(second=0,microsecond=0)).timestamp()|int }}"

        # timestamp momentu "30 minut temu"; jeśli ten w pozycji jest <= to idzie powiadomienie
        notifyTs: "{{ nTs-NOTIFY_MINUTES*60 }}"

        # Zdarzenia z danego dnia, które miały ostatnie powiadomienie 30 minut temu lub póżniej
        # (lub wcale).
        toAlert: >-
          {% set tsMin = as_datetime(now().date()).astimezone().timestamp()|int|string %}
          {% set a = state_attr('sensor.alarmy_kalendarza', 'calendar_events') or {} %}
          {{ a.items()|selectattr('0','ge',tsMin)|selectattr('1.1','le',notifyTs)|list }}
        
        # Moja nazwa akcji w zdarzeniu 'mobile_app_notification_action'; po tej nazwie rozpoznaję,
        # które akcje przetwarzać. Do nazwy doklejam id usuwanej pozycji ze słownika
        # (bo "actionable notifications" nie dają jednolitego sposobu przesyłania dodatkowych danych,
        # który by działał na iphone i android)
        myAction: "fd9f87ee4dd20193b7b4-"
        
    # wysyłanie powiadomień dla zdarzeń z danego dnia
    - if: "{{ trigger.id == 'time' }}"
      then:
        - repeat:
            for_each: "{{ toAlert }}"
            sequence:
              - action: notify.mobile_app_iphone_maciej
                data:
                  title: Kalendarz
                  message: "{{ repeat.item[1][0] }}"
                  data:
                    actions:
                      # doklejam id pozycji do mojej nazwy akcji
                      - action: "{{ myAction ~ repeat.item[0] }}"
                        title: Zrobione!
              # opóźnienie aby nie spamować kilku powiadomień w tej samej sekundzie
              - delay:
                  hours: 0
                  minutes: 0
                  seconds: 3
                  milliseconds: 0
  sensor:
    - name: Alarmy kalendarza
      unique_id: alarmy_kalendarza_id
      state: "Słownik w atrybucie calendar_events"
      attributes:
        # Atrybut/słownik, tutaj:
        # - dodaję nowe pozycje, czyli zdarzenia z kalendarza
        # - aktualizuję pozycjom czas ostatniego wysłania powiadomienia
        # - usuwam te, które zostały oznaczone jako wykonane
        # - raz na dobę, o 1:01, usuwam pozycje z poprzedniej doby, jeśli coś zostało
        calendar_events: >-
          {% set current = this.attributes.get('calendar_events', {}) %}
          {% if trigger.id == 'calendar' %}
            {% set k = now().timestamp()|string %}
            {% set v = [trigger.calendar_event.summary,0] %}
            {% set new = {k: v} %}
            {{ dict(current, **new) }}
          {% elif trigger.id == 'time' %}
            {% if toAlert|count > 0 %}
              {% set ns = namespace(d=current) %}
              {% for i in toAlert %}
                {% set new = {i[0]: [i[1][0], nTs] } %}
                {% set ns.d = dict(ns.d, **new) %}
              {% endfor %}
              {{ ns.d }}
            {% else %}
              {{ current }}
            {% endif %}
          {% elif trigger.id == 'handled' and trigger.event.data.action.startswith(myAction) %}
            {% set aLen = myAction|length %}
            {% set k = trigger.event.data.action[aLen:] %}
            {{ dict(current.items()|rejectattr('0','eq',k)) }}
          {% elif trigger.id == 'cleaning' %}
            {% set midnight = as_datetime(now().date()).astimezone().timestamp()|int|string %}
            {{ dict(current.items()|rejectattr('0','lt',midnight)) }}
          {% else %}
            {{ current }}
          {% endif %}

Co zmienić w kodzie pod siebie, uwagi:

Pokaż

Trzeba zmienić:

  • nazwa kalendarza (entity_id: calendar.sprawy_domowe)
  • telefon/aplikacja od powiadomień (- action: notify.mobile_app_iphone_maciej)
  • jeśli zmienicie nazwę sensora, to również: state_attr(‘sensor.alarmy_kalendarza’, ‘calendar_events’)

Można zmienić:

  • interwał powtarzania powiadomień, w minutach (NOTIFY_MINUTES: “{{ 30 }}”)
  • częstotliwość “wewnętrznego timera”, w triggerze “time” (minutes: /5)
    To ustawienie decyduje, jak często będzie sprawdzane, czy nie trzeba wysłać powiadomienia. Ciche założenie jest takie, że zdarzenia w kalendarzu robi się w minutach podzielnych przez 5, czyli np. o 10:10 a nie 10:12. Jak będzie zdarzenie o 10:12, to pierwsze powiadomienie przyjdzie nie od razu, tylko o 10:15 - myślę, że to jest jasne :slight_smile: Można to dostosować pod siebie np. “minutes: /1” aby mieć dokładność do 1 minuty, czy “minutes: /15”, jeśli zdarzenia są planowane najwyżej co kwadrans.
    NOTIFY_MINUTES powinno być wielokrotnością częstotliwości timera.

Uwagi:

  • HA odświeża kalendarz co 15 minut, więc testując ten sensor, róbcie zdarzenia przynajmniej 15 minut w przyszłości
  • mam iphone, na androidzie nie testowałem, ale powinno też działać

Edit: poprawiłem kod na bardziej zwięzły :slight_smile:

2 polubienia

Do prezentacji upływu czasu, czy też ile upłynęło dni pomiędzy datami, polecam skorzystanie z gotowca jakim jest Relative Time Plus:

Zamiast za każdym razem tworzyć kolejnego “potworka” wystarczy proste wywołanie.
Można poprzez edycję dopasować sobie efekt końcowy do własnych potrzeb

Zainteresowanym udostępnię zmodyfikowany przez siebie plik, ale obecnie jestem poza domem i nie mam dostępu.

Modyfikacja zostawia tylko polski i angielski język, ustawia język polski jako domyślny, domyślnie wyświetla skróty, domyślnie nie wyświetla tygodni, sekund i milisekund.

Efekt modyfikacji jest mniej więcej taki:

wywołując

{% from 'time_plus.jinja' import time_plus %}
{{ time_plus(states('sensor.nas_last_boot')) }}

uzyskujemy

16d 13g 12m

lub wywołując

{% from 'time_plus.jinja' import time_plus %}
{{ time_plus(states('sensor.nas_last_boot'), abbr=false) }}

uzyskujemy

16 dni 13 godzin 12 minut

EDIT:
Dorzucam plik. Trzeba go po rozpakowaniu skopiować do lokalizacji:

\config\custom_templates

time_plus.zip (3,5 KB)

2 polubienia