ESPHome - Pogodynka na ekranie e-ink ☁

OPIS

Przedstawiam projekt pogodynki na ekranie e-ink z układem ESP32.
Kod nie jest mój, jest to zlepek kilku projektów i dostosowany do moich danych w Home Assistant.
Ekran odświeża się domyślnie przy wykryciu ruchu w pomieszczeniu, jeśli dane z czujników się zmieniły.
Ja zrobiłem pomocnika przełącznik, który robi za fałszywy czujnik ruchu, wtedy ekran odświeża się przy odebraniu danych, pozwala mi to na wyłączanie odświeżania ekranu, jeśli nikogo nie ma w domu, czy podczas snu.
Sam projekt można przerobić na układ z baterią i użyć funkcji deep sleep.
W samym Home Assistant mamy podgląd ilości, czasu odświeżania itp.

image




Sprzęt

Oprogramowanie

  • ESPHome
  • Home Assistant

Źródła danych

  • Integracja Met.no
  • Integracja Thermal Comfort
  • Integracja sun oraz moon
  • Lokalny czujnik temperatury, wilgotności oraz ciśnienia
  • Sensor z dniem, nazwą tygodnia i miesiąca link

Instalacja

Nie jest wymagane lutowanie, ponieważ ekran e-ink należy połączyć taśmą z płytą ESP32.
Skopiować /font do folderu /config/esphome/
font.zip (727,8 KB)

Utworzyć w Home Assistant template

  - binary_sensor:
      - name: Weatherman Motion Detected
        unique_id: "dfa78de7-d761-425f-9731-86f1af332eac"
        device_class: "occupancy"
        delay_off: 1min
        state: >-
          {%- if states('input_boolean.eink_czujnik_ruchu') == 'on' %}
            on
          {%- else -%}
            off
          {%- endif -%}
  # Bundle up all the data to send over to Weatherman (ESPHome device).

  - trigger:
      platform: time_pattern
      minutes: "/1"
    action:
      - service: weather.get_forecasts
        data:
          type: hourly
        target:
          entity_id: weather.forecast_home
        response_variable: hourly
    sensor:
      - name: Weatherman Data
        state: "OK"
        attributes:
          weather_condition_now: >
            {% set cond_now = states('weather.forecast_home') %}
            {% if states('sun.sun') == 'below_horizon' %}
                {% if cond_now == 'sunny' %} night {% elif cond_now == 'partlycloudy' %} night-partly-cloudy {% else %} {{ cond_now }} {% endif %}
            {% else %}
                {{ cond_now }}
            {% endif %}
            
          weather_condition_0: >
            {% set cond0 = hourly["weather.forecast_home"].forecast[0].condition %}
            {% set next_setting = as_timestamp(state_attr('sun.sun', 'next_setting')) %}
            {% set next_rising = as_timestamp(state_attr('sun.sun', 'next_rising')) %}
            {% set cond0_time = as_timestamp(hourly["weather.forecast_home"].forecast[0].datetime) %}
            {% if cond0_time < next_rising and next_rising < next_setting %}
                {% if cond0 == 'sunny' %} night {% elif cond0 == 'partlycloudy' %} night-partly-cloudy {% else %} {{ cond0 }} {% endif %}
            {% else %}
                {{ cond0 }}
            {% endif %}
          weather_temperature_0: >
            {{ hourly["weather.forecast_home"].forecast[0].temperature | round }}
          weather_timestamp_0: >
            {{ as_timestamp(hourly["weather.forecast_home"].forecast[0].datetime) | timestamp_custom('%H') | int }}
            
          weather_condition_1: >
            {% set cond1 = hourly["weather.forecast_home"].forecast[1].condition %}
            {% set next_setting = as_timestamp(state_attr('sun.sun', 'next_setting')) %}
            {% set next_rising = as_timestamp(state_attr('sun.sun', 'next_rising')) %}
            {% set cond1_time = as_timestamp(hourly["weather.forecast_home"].forecast[1].datetime) %}
            {% if cond1_time < next_rising and next_rising < next_setting %}
                {% if cond1 == 'sunny' %} night {% elif cond1 == 'partlycloudy' %} night-partly-cloudy {% else %} {{ cond1 }} {% endif %}
            {% else %}
                {{ cond1 }}
            {% endif %}
          weather_temperature_1: >
            {{ hourly["weather.forecast_home"].forecast[1].temperature | round }}
          weather_timestamp_1: >
            {{ as_timestamp(hourly["weather.forecast_home"].forecast[1].datetime) | timestamp_custom('%H') | int }}
            
          weather_condition_2: >
            {% set cond2 = hourly["weather.forecast_home"].forecast[2].condition %}
            {% set next_setting = as_timestamp(state_attr('sun.sun', 'next_setting')) %}
            {% set next_rising = as_timestamp(state_attr('sun.sun', 'next_rising')) %}
            {% set cond2_time = as_timestamp(hourly["weather.forecast_home"].forecast[2].datetime) %}
            {% if cond2_time < next_rising and next_rising < next_setting %}
                {% if cond2 == 'sunny' %} night {% elif cond2 == 'partlycloudy' %} night-partly-cloudy {% else %} {{ cond2 }} {% endif %}
            {% else %}
                {{ cond2 }}
            {% endif %}
          weather_temperature_2: >
            {{ hourly["weather.forecast_home"].forecast[2].temperature | round }}
          weather_timestamp_2: >
            {{ as_timestamp(hourly["weather.forecast_home"].forecast[2].datetime) | timestamp_custom('%H') | int }}
            
          weather_condition_3: >
            {% set cond3 = hourly["weather.forecast_home"].forecast[3].condition %}
            {% set next_setting = as_timestamp(state_attr('sun.sun', 'next_setting')) %}
            {% set next_rising = as_timestamp(state_attr('sun.sun', 'next_rising')) %}
            {% set cond3_time = as_timestamp(hourly["weather.forecast_home"].forecast[3].datetime) %}
            {% if cond3_time < next_rising and next_rising < next_setting %}
                {% if cond3 == 'sunny' %} night {% elif cond3 == 'partlycloudy' %} night-partly-cloudy {% else %} {{ cond3 }} {% endif %}
            {% else %}
                {{ cond3 }}
            {% endif %}
          weather_temperature_3: >
            {{ hourly["weather.forecast_home"].forecast[3].temperature | round }}
          weather_timestamp_3: >
            {{ as_timestamp(hourly["weather.forecast_home"].forecast[3].datetime) | timestamp_custom('%H') | int }}

Zainstalować poniższy kod na płytę ESP32 za pomocą ESPHome.

# WEATHERMAN DASHBOARD
# For Home Assistant and ESPHome
# Designed by Madelena Mak 2022 - https://mmak.es

# Cue "Blame it on the Weatherman" by B*Witched!
esphome:
  name: eink
  friendly_name: eink
  on_boot:
      priority: 200.0
      then:
        - component.update: eink_display
        - wait_until:
            condition:
              lambda: 'return id(data_updated) == true;'
              # Poczekaj trochę dłużej, aby wszystkie elementy zostały odebrane
        - delay: 5s
        - logger.log: "Odebrano wstępne dane czujnika: Odświeżanie ekranu..."
        - lambda: 'id(initial_data_received) = true;'
        - script.execute: update_screen
esp32:
  board: esp32dev
  framework:
    type: arduino

logger:

api:
  encryption:
    key: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

ota:
  password: "xxxxxxxxxxxxxxxxxxxxxxx"

web_server:
  port: 80

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  ap:
    ssid: "Eink Fallback Hotspot"
    password: "xxxxxxxxx"
   
captive_portal:

# Dołącz czas
# Sprawdź, czy wyświetlacz wymaga odświeżania co minutę,
# w zależności od tego, czy odebrano nowe dane, czy wykryto ruch. (Thanks @paviro!)
time:
  - platform: homeassistant
    id: homeassistant_time
    on_time:
      - seconds: 0
        minutes: /30
        then:
          - if:
              condition:
                lambda: 'return id(data_updated) == true;'
              then:
                - if:
                    condition:
                      binary_sensor.is_on: motion_detected
                    then:
                      - logger.log: "Zaktualizowano dane czujnika i wykryto aktywność w domu: odświeżanie wyświetlacza..."
                      - script.execute: update_screen
                    else:
                      - logger.log: "Dane czujnika zostały zaktualizowane, ale w domu brak aktywności – pominięto odświeżanie wyświetlacza."
              else:
                - logger.log: "Brak aktualizacji czujników – pominięto odświeżanie wyświetlacza."


# Przyciski
button:
  - platform: shutdown
    name: "eink - Wyłączenie"
  - platform: restart
    name: "eink - Restart"
  - platform: template
    name: "eink - Odświeżanie ekranu"
    entity_category: config
    on_press:
      - script.execute: update_screen

# Zmienne globalne do wykrywania, czy ekran wymaga odświeżenia. (Thanks @paviro!)
globals:
  - id: data_updated
    type: bool
    restore_value: no
    initial_value: 'false'
  - id: initial_data_received
    type: bool
    restore_value: no
    initial_value: 'false'
  - id: recorded_display_refresh
    type: int
    restore_value: yes
    initial_value: '0'


# Skrypt do aktualizacji ekranu - Odśwież wyświetlacz i opublikuj liczbę i czas odświeżenia. (Thanks @paviro!)
script:
  - id: update_screen
    then:
      - lambda: 'id(data_updated) = false;'
      - component.update: eink_display
      - lambda: 'id(recorded_display_refresh) += 1;'
      - lambda: 'id(display_last_update).publish_state(id(homeassistant_time).now().timestamp);'
      

# Dołącz niestandardową czcionkę
font:
  - file: 'font/GothamRnd-Bold.ttf'
    id: font_large_bold
    size: 125
  - file: 'font/GothamRnd-Bold.ttf'
    id: font_large_bold_c
    size: 90
  - file: 'font/GothamRnd-Book.ttf'
    id: font_time
    size: 150
  - file: 'font/RobotoCondensed-Regular.ttf'
    id: font_weekday
    size: 50
    glyphs: ['A', 'B', 'C', 'D', 'E',
       'F', 'G', 'H', 'I', 'J', 'K', 'L', 'Ł', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
       'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'Ż', 'Ź', 'Ó', 'Ę', 'Ą', 'Ś', 'Ć', 'Ń', 'a', 'b', 'c', 'd', 'e', 'f',
       'g', 'h', 'i', 'j', 'k', 'l', 'ł', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
       'u', 'v', 'w', 'x', 'y', 'z','ż', 'ź', 'ę', 'ą', 'ś', 'ć', 'ń', 'ó']
  - file: 'font/RobotoCondensed-Light.ttf'
    id: font_day
    size: 50
    glyphs: ['A', 'B', 'C', 'D', 'E',
       'F', 'G', 'H', 'I', 'J', 'K', 'L', 'Ł', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
       'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'Ż', 'Ź', 'Ó', 'Ę', 'Ą', 'Ś', 'Ć', 'Ń', 'a', 'b', 'c', 'd', 'e', 'f',
       'g', 'h', 'i', 'j', 'k', 'l', 'ł', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
       'u', 'v', 'w', 'x', 'y', 'z','ż', 'ź', 'ę', 'ą', 'ś', 'ć', 'ń', 'ó']
  - file: 'font/GothamRnd-Bold.ttf'
    id: font_month
    size: 50
  - file: 'font/GothamRnd-Bold.ttf'
    id: font_medium_bold
    size: 42
  - file: 'font/GothamRnd-Bold.ttf'
    id: font_small_bold
    size: 22

  # Dołącz czcionkę Material Design Icons
  # Dzięki https://community.home-assistant.io/t/display-materialdesign-icons-on-esphome-attached-to-screen/199790/16
  - file: 'font/materialdesignicons-webfont.ttf'
    id: font_mdi_extra_large
    size: 140
    glyphs: &mdi-weather-glyphs
      - "\U000F0590" # mdi-weather-cloudy
      - "\U000F0F2F" # mdi-weather-cloudy-alert
      - "\U000F0E6E" # mdi-weather-cloudy-arrow-right
      - "\U000F0591" # mdi-weather-fog
      - "\U000F0592" # mdi-weather-hail
      - "\U000F0F30" # mdi-weather-hazy
      - "\U000F0898" # mdi-weather-hurricane
      - "\U000F0593" # mdi-weather-lightning
      - "\U000F067E" # mdi-weather-lightning-rainy
      - "\U000F0594" # mdi-weather-night
      - "\U000F0F31" # mdi-weather-night-partly-cloudy
      - "\U000F0595" # mdi-weather-partly-cloudy
      - "\U000F0F32" # mdi-weather-partly-lightning
      - "\U000F0F33" # mdi-weather-partly-rainy
      - "\U000F0F34" # mdi-weather-partly-snowy
      - "\U000F0F35" # mdi-weather-partly-snowy-rainy
      - "\U000F0596" # mdi-weather-pouring
      - "\U000F0597" # mdi-weather-rainy
      - "\U000F0598" # mdi-weather-snowy
      - "\U000F0F36" # mdi-weather-snowy-heavy
      - "\U000F067F" # mdi-weather-snowy-rainy
      - "\U000F0599" # mdi-weather-sunny
      - "\U000F0F37" # mdi-weather-sunny-alert
      - "\U000F14E4" # mdi-weather-sunny-off
      - "\U000F059A" # mdi-weather-sunset
      - "\U000F059B" # mdi-weather-sunset-down
      - "\U000F059C" # mdi-weather-sunset-up
      - "\U000F0F38" # mdi-weather-tornado
      - "\U000F059D" # mdi-weather-windy
      - "\U000F059E" # mdi-weather-windy-variant
      - "\U000F058E" # mdi-water-percent
      - "\U000F04C5" # mdi-spedometer
      - "\U000F0F29" # mdi-snowflake-alert
      - "\U000F002A" # mdi-alert-outline
      - "\U000F15FA" # mdi-windsock
      - "\U000F19B3" # mdi-arrow-down-thin
      - "\U000F19B2" # mdi-arrow-up-thin
      - "\U000F19B4" # mdi-arrow-top-right-thin
      - "\U000F19B7" # mdi-arrow-bottom-right-thin
      - "\U000F00A5" # mdi-binoculars
      - "\U000F018C" # mdi-compass-outline
      - "\U000F0E03" # mdi-thermometer-chevron-up
      - "\U000F0E02" # mdi-thermometer-chevron-down
      - "\U000F1A09" # mdi-triangle-small-down
      - "\U000F1A0A" # mdi-triangle-small-up
      - "\U000F02CA" # mdi-hadrdisk
      - "\U000F029A" # mdi-gauge
  - file: 'font/materialdesignicons-webfont.ttf'
    id: font_mdi_moon
    size: 60
    glyphs:
      - "\U000F058E" # mdi-water-percent
      - "\U000F04C5" # mdi-spedometer
      - "\U000F0F29" # mdi-snowflake-alert
      - "\U000F002A" # mdi-alert-outline
      - "\U000F15FA" # mdi-windsock
      - "\U000F0F61" # mdi-moon-first-quarter
      - "\U000F0F62" # mdi-moon-full
      - "\U000F0F63" # mdi-moon-last-quarter
      - "\U000F0F64" # mdi-moon-new
      - "\U000F0F65" # mdi-moon-waning-crescent
      - "\U000F0F66" # mdi-moon-waning-gibbous
      - "\U000F0F67" # mdi-moon-waxing-crescent
      - "\U000F0F68" # mdi-moon-waxing-gibbous
  - file: 'font/materialdesignicons-webfont.ttf'
    id: font_mdi_medium
    size: 50
    glyphs: *mdi-weather-glyphs
  - file: 'font/materialdesignicons-webfont.ttf'
    id: font_mdi_large
    size: 80
    glyphs: *mdi-weather-glyphs

# Sprawdź, czy w salonie wykryto ruch. (czy załączony pomocnik ruch)
binary_sensor:
  - platform: homeassistant
    entity_id: input_boolean.eink_czujnik_ruchu
    id: motion_detected

# Czujniki pogodowe z HA
sensor:
  # Twórz czujniki do zdalnego monitorowania Weatherman.
  - platform: template
    name: "eink - Czas aktualizacji wyświetlacza"
    device_class: timestamp
    entity_category: "diagnostic"
    id: display_last_update
    
  - platform: template
    name: "eink - Zarejestrowane Oswieżanie wyświetlacza"
    accuracy_decimals: 0
    unit_of_measurement: "Odświeżenia"
    state_class: "total_increasing"
    entity_category: "diagnostic"
    lambda: 'return id(recorded_display_refresh);'

  # Temperatura — moja stacja pogodowa
  - platform: homeassistant
    entity_id: sensor.netatmo_ogrod_temperature
    id: weather_temperature
    on_value:
      then:
        - lambda: 'id(data_updated) = true;'
        
  # Wilgotność - moja stacja pogodowa
  - platform: homeassistant
    entity_id: sensor.netatmo_ogrod_humidity
    id: weather_humidity
    on_value:
      then:
        - lambda: 'id(data_updated) = true;'

  # Ciśnienie - moja stacja pogodowa
  - platform: homeassistant
    entity_id: sensor.netatmo_wewnatrz_pressure
    id: weather_pressure
    on_value:
      then:
        - lambda: 'id(data_updated) = true;'

  # Ilość opadu deszczu
  - platform: homeassistant
    entity_id: sensor.netatmo_czujnik_deszczu_rain_today
    id: ilosc_opadu
    on_value:
      then:
        - lambda: 'id(data_updated) = true;'

  # Weatherman encje
  - platform: homeassistant
    entity_id: sensor.weatherman_data
    attribute: weather_temperature_0
    id: weather_temperature_0
    on_value:
      then:
        - lambda: 'id(data_updated) = true;'

  - platform: homeassistant
    entity_id: sensor.weatherman_data
    attribute: weather_temperature_1
    id: weather_temperature_1
    on_value:
      then:
        - lambda: 'id(data_updated) = true;'

  - platform: homeassistant
    entity_id: sensor.weatherman_data
    attribute: weather_temperature_2
    id: weather_temperature_2
    on_value:
      then:
        - lambda: 'id(data_updated) = true;'

  - platform: homeassistant
    entity_id: sensor.weatherman_data
    attribute: weather_temperature_3
    id: weather_temperature_3
    on_value:
      then:
        - lambda: 'id(data_updated) = true;'

text_sensor:
  # Dzień tygodnia
  - platform: homeassistant
    entity_id: sensor.dzien_tygodnia
    id: nazwa_dnia
    on_value:
      then:
        - lambda: 'id(data_updated) = true;'

  # Miesiąc
  - platform: homeassistant
    entity_id: sensor.miesiac
    id: miesiac
    on_value:
      then:
        - lambda: 'id(data_updated) = true;'

  # Dzień
  - platform: homeassistant
    entity_id: sensor.dzien_miesiaca
    id: dzien
    on_value:
      then:
        - lambda: 'id(data_updated) = true;'

  # Weatherman encje
  - platform: homeassistant
    entity_id: sensor.weatherman_data
    attribute: weather_condition_now
    id: weather_condition_now
    on_value:
      then:
        - lambda: 'id(data_updated) = true;'

  - platform: homeassistant
    entity_id: sensor.weatherman_data
    attribute: weather_condition_0
    id: weather_condition_0
    on_value:
      then:
        - lambda: 'id(data_updated) = true;'

  - platform: homeassistant
    entity_id: sensor.weatherman_data
    attribute: weather_timestamp_0
    id: weather_timestamp_0
    on_value:
      then:
        - lambda: 'id(data_updated) = true;'

  - platform: homeassistant
    entity_id: sensor.weatherman_data
    attribute: weather_condition_1
    id: weather_condition_1
    on_value:
      then:
        - lambda: 'id(data_updated) = true;'

  - platform: homeassistant
    entity_id: sensor.weatherman_data
    attribute: weather_timestamp_1
    id: weather_timestamp_1
    on_value:
      then:
        - lambda: 'id(data_updated) = true;'

  - platform: homeassistant
    entity_id: sensor.weatherman_data
    attribute: weather_condition_2
    id: weather_condition_2
    on_value:
      then:
        - lambda: 'id(data_updated) = true;'

  - platform: homeassistant
    entity_id: sensor.weatherman_data
    attribute: weather_timestamp_2
    id: weather_timestamp_2
    on_value:
      then:
        - lambda: 'id(data_updated) = true;'

  - platform: homeassistant
    entity_id: sensor.weatherman_data
    attribute: weather_condition_3
    id: weather_condition_3
    on_value:
      then:
        - lambda: 'id(data_updated) = true;'

  - platform: homeassistant
    entity_id: sensor.weatherman_data
    attribute: weather_timestamp_3
    id: weather_timestamp_3
    on_value:
      then:
        - lambda: 'id(data_updated) = true;'

  # Wschód słońca
  - platform: homeassistant
    entity_id: sensor.czas_wschodu_slonca
    id: sun_sunrise
    on_value:
      then:
        - lambda: 'id(data_updated) = true;'

  # Zachód słońca
  - platform: homeassistant
    entity_id: sensor.czas_zachodu_slonca
    id: sun_sunset
    on_value:
      then:
        - lambda: 'id(data_updated) = true;'

  # Ryzyko mrozu
  - platform: homeassistant
    entity_id: sensor.thermal_comfort_frostrisk
    id: frost_risk
    on_value:
      then:
        - lambda: 'id(data_updated) = true;'

  # Meteoalarm
  - platform: homeassistant
    entity_id: binary_sensor.meteoalarm
    id: meteoalarm
    on_value:
      then:
        - lambda: 'id(data_updated) = true;'

  # Faza Księżyca
  - platform: homeassistant
    entity_id: sensor.ksiezyc
    id: moon_phase
    on_value:
      then:
        - lambda: 'id(data_updated) = true;'

# Poprawka odświeżania
#external_components:
#  - source:
#      type: git
#      url: https://github.com/prapador/esphome_waveshare_fix
#      ref: dev
#    components: [ waveshare_epaper ]

# Zdefiniuj kolory
color:
  - id: color_black
    red: 0%
    green: 0%
    blue: 0%
    white: 50%
  - id: color_white
    red: 0%
    green: 0%
    blue: 0%
    white: 0%


# Piny Waveshare ePaper ESP Board
spi:
  clk_pin: GPIO13
  mosi_pin: GPIO14


# Teraz wyrenderuj wszystko na ekranie ePaper.
display:
  - platform: waveshare_epaper
    id: eink_display
    cs_pin: GPIO15
    dc_pin: GPIO27
    busy_pin: GPIO25
    reset_pin: GPIO26
    reset_duration: 2ms
    model: 7.50inV2alt
    update_interval: never
    rotation: 90°
    auto_clear_enabled: false
    lambda: |-
      // Map weather states to MDI characters.
      std::map<std::string, std::string> moon_icon_map
        {
          {"first_quarter", "\U000F0F61"},
          {"full_moon", "\U000F0F62"},
          {"last_quarter", "\U000F0F63"},
          {"new_moon", "\U000F0F64"},
          {"waning_crescent", "\U000F0F65"},
          {"waning_gibbous", "\U000F0F66"},
          {"waxing_crescent", "\U000F0F67"},
          {"waxing_gibbous", "\U000F0F68"},
          
        };
      std::map<std::string, std::string> weather_icon_map
        {
          {"cloudy", "\U000F0590"},
          {"cloudy-alert", "\U000F0F2F"},
          {"cloudy-arrow-right", "\U000F0E6E"},
          {"fog", "\U000F0591"},
          {"hail", "\U000F0592"},
          {"hazy", "\U000F0F30"},
          {"hurricane", "\U000F0898"},
          {"lightning", "\U000F0593"},
          {"lightning-rainy", "\U000F067E"},
          {"night", "\U000F0594"},
          {"clear-night", "\U000F0594"},
          {"night-partly-cloudy", "\U000F0F31"},
          {"partlycloudy", "\U000F0595"},
          {"partly-lightning", "\U000F0F32"},
          {"partly-rainy", "\U000F0F33"},
          {"partly-snowy", "\U000F0F34"},
          {"partly-snowy-rainy", "\U000F0F35"},
          {"pouring", "\U000F0596"},
          {"rainy", "\U000F0597"},
          {"snowy", "\U000F0598"},
          {"snowy-heavy", "\U000F0F36"},
          {"snowy-rainy", "\U000F067F"},
          {"sunny", "\U000F0599"},
          {"sunny-alert", "\U000F0F37"},
          {"sunny-off", "\U000F14E4"},
          {"sunset", "\U000F059A"},
          {"sunset-down", "\U000F059B"},
          {"sunset-up", "\U000F059C"},
          {"tornado", "\U000F0F38"},
          {"windy", "\U000F059D"},
          {"windy-variant", "\U000F059E"},
        };

      // Wypełnij tło
      it.fill(color_white);

      // ------------------------------------------------------------Pokaż ekran ładowania przed odebraniem danych. ------------------------------------------------------
      if (id(initial_data_received) == false) {
        it.printf(300, 250, id(font_mdi_extra_large), color_black, TextAlign::CENTER_RIGHT, "\U000F02CA");
        it.printf(240, 390, id(font_medium_bold), color_black, TextAlign::TOP_CENTER, "Czekam na dane...");
      } else {
      // ----------------------------------------------------------------------------------- Dzień tygodnia ------------------------------------------------------------
      it.printf(210, 70, id(font_weekday), color_black, TextAlign::TOP_LEFT, "%s", id(nazwa_dnia).state.c_str());
      // ----------------------------------------------------------------------------------- Dzień miesiąca duże ------------------------------------------------------
      it.printf(220, 65, id(font_time), color_black, TextAlign::TOP_RIGHT, "%s", id(dzien).state.c_str());
      // ----------------------------------------------------------------------------------- Miesiąc ------------------------------------------------------------------
      it.printf(210, 140, id(font_day), color_black, TextAlign::TOP_LEFT, "%s", id(miesiac).state.c_str());

      // ----------------------------------------------------------------------------------- Wschód słońca ------------------------------------------------------------
        if(id(sun_sunrise).has_state ()) {
            it.printf(95, 235, id(font_mdi_medium), color_black, TextAlign::CENTER_RIGHT, "\U000F059C");
            it.printf(105, 235, id(font_small_bold), color_black, TextAlign::CENTER_LEFT, "%s", id(sun_sunrise).state.c_str());
        }      
      // ----------------------------------------------------------------------------------- Zachód słońca ------------------------------------------------------------
        if(id(sun_sunset).has_state ()) {
            it.printf(450, 235, id(font_mdi_medium), color_black, TextAlign::CENTER_RIGHT, "\U000F059B");
            it.printf(395, 235, id(font_small_bold), color_black, TextAlign::CENTER_RIGHT, "%s", id(sun_sunset).state.c_str());
        }
      // ----------------------------------------------------------------------------------- Faza księżyca ikona ------------------------------------------------------
        if(id(moon_phase).has_state ()) {
            it.printf(255, 240, id(font_mdi_moon), color_black, TextAlign::CENTER, "%s", moon_icon_map[id(moon_phase).state.c_str()].c_str());
        }     
      // ----------------------------------------------------------------------------------- Wilgotność ----------------------------------------------------------------
        if(id(weather_humidity).has_state ()) {
            it.printf(88, 332, id(font_mdi_medium), color_black, TextAlign::BASELINE_RIGHT, "\U000F058E");
            it.printf(151, 330, id(font_month), color_black, TextAlign::BASELINE_RIGHT, "%2.0f", id(weather_humidity).state);
            it.printf(155, 330, id(font_small_bold), color_black, TextAlign::BASELINE_LEFT, "%s", "%");
        }      
      // ----------------------------------------------------------------------------------- Ciśnienie -----------------------------------------------------------------
        if(id(weather_pressure).has_state ()) {
            it.printf(293, 332, id(font_mdi_medium), color_black, TextAlign::BASELINE_RIGHT, "\U000F04C5");
            it.printf(415, 330, id(font_month), color_black, TextAlign::BASELINE_RIGHT, "%2.0f", id(weather_pressure).state);
            it.printf(420, 330, id(font_small_bold), color_black, TextAlign::BASELINE_LEFT, "hPa");
        }
      // ----------------------------------------------------------------------------------- Meteoalarm ----------------------------------------------------------------
        if(id(meteoalarm).has_state ()) {
            if(id(meteoalarm).state != "off") {
                it.printf(350, 440, id(font_mdi_large), color_black, TextAlign::BASELINE_LEFT, "\U000F002A");
            }
        }
      // ----------------------------------------------------------------------------------- Ostrzeżenie przed mrozem --------------------------------------------------
        if(id(frost_risk).has_state ()) {
            if(id(frost_risk).state != "no_risk") {
                it.printf(75, 440, id(font_mdi_large), color_black, TextAlign::BASELINE_LEFT, "\U000F0F29");
            }
        }
      // ----------------------------------------------------------------------------------- Ilość opadu deszczu -------------------------------------------------------
        if(id(ilosc_opadu).has_state ()) {
            if(id(ilosc_opadu).state > 0) {
            it.printf(370, 470, id(font_small_bold), color_black, TextAlign::BASELINE_RIGHT, "%.1f", id(ilosc_opadu).state);
            it.printf(375, 470, id(font_small_bold), color_black, TextAlign::BASELINE_LEFT, "mm");
            }
        }

      // ----------------------------------------------------------------------------------- Stan pogody ikona ---------------------------------------------------------
            it.printf(252, 340, id(font_mdi_extra_large), color_black, TextAlign::TOP_CENTER, "%s", weather_icon_map[id(weather_condition_now).state.c_str()].c_str());
      // ----------------------------------------------------------------------------------- TEMPERATURA ---------------------------------------------------------------
            it.printf(330, 482, id(font_large_bold), color_black, TextAlign::TOP_RIGHT, "%.1f", id(weather_temperature).state);
            it.printf(460, 508, id(font_large_bold_c), color_black, TextAlign::TOP_RIGHT, "°C");
      // ----------------------------------------------------------------------------------- Prognoza + 1 ---------------------------------------------------------------
        if(id(weather_temperature_0).has_state ()) {
            it.printf(83, 602, id(font_small_bold), color_black, TextAlign::TOP_CENTER, "%s", id(weather_timestamp_0).state.c_str());
            it.printf(83, 630, id(font_mdi_medium), color_black, TextAlign::TOP_CENTER, "%s", weather_icon_map[id(weather_condition_0).state.c_str()].c_str());
            it.printf(83, 680, id(font_small_bold), color_black, TextAlign::TOP_CENTER, "%2.0f°C", id(weather_temperature_0).state);
        }
      // ----------------------------------------------------------------------------------- Prognoza + 2 ---------------------------------------------------------------  
        if(id(weather_temperature_1).has_state ()) {
            it.printf(195, 602, id(font_small_bold), color_black, TextAlign::TOP_CENTER, "%s", id(weather_timestamp_1).state.c_str());
            it.printf(195, 630, id(font_mdi_medium), color_black, TextAlign::TOP_CENTER, "%s", weather_icon_map[id(weather_condition_1).state.c_str()].c_str());
            it.printf(195, 680, id(font_small_bold), color_black, TextAlign::TOP_CENTER, "%2.0f°C", id(weather_temperature_1).state);
        }
      // ----------------------------------------------------------------------------------- Prognoza + 3 ---------------------------------------------------------------
        if(id(weather_temperature_2).has_state ()) {
            it.printf(305, 602, id(font_small_bold), color_black, TextAlign::TOP_CENTER, "%s", id(weather_timestamp_2).state.c_str());
            it.printf(305, 630, id(font_mdi_medium), color_black, TextAlign::TOP_CENTER, "%s", weather_icon_map[id(weather_condition_2).state.c_str()].c_str());
            it.printf(305, 680, id(font_small_bold), color_black, TextAlign::TOP_CENTER, "%2.0f°C", id(weather_temperature_2).state);
        }
      // ----------------------------------------------------------------------------------- Prognoza + 4 ---------------------------------------------------------------
        if(id(weather_temperature_3).has_state ()) {
            it.printf(415, 602, id(font_small_bold), color_black, TextAlign::TOP_CENTER, "%s", id(weather_timestamp_3).state.c_str());
            it.printf(415, 630, id(font_mdi_medium), color_black, TextAlign::TOP_CENTER, "%s", weather_icon_map[id(weather_condition_3).state.c_str()].c_str());
            it.printf(415, 680, id(font_small_bold), color_black, TextAlign::TOP_CENTER, "%2.0f°C", id(weather_temperature_3).state);
        }
      } 

9 polubień

Wygląda świetnie. Gratulacje.

Nie potrafię utworzyc sensora z dniem, nazwą tygodnia i miesiąca, ktoś podpowie?

w configuration.yaml mam dodane

sensor: !include sensor.yaml

a w utworzonym pliku sensor.yaml

  - platform: template
    sensors:
      dzien_tygodnia:
        friendly_name: "Dzień tygodnia"
        icon_template: mdi:calendar-range-outline
        value_template: "{{ ['Poniedziałek','Wtorek','Środa','Czwartek','Piątek','Sobota','Niedziela'][now().weekday()] }}"

      dzien_miesiaca:
        friendly_name: "Dzień miesiąca"
        icon_template: mdi:calendar-outline
        value_template: "{{ ['1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16','17','18','19','20','21','22','23','24','25','26','27','28','29','30','31' ][ now().day-1] }}"

      miesiac:
        friendly_name: "Miesiąc"
        icon_template: mdi:calendar-month-outline
        value_template: "{{ ['Styczeń','Luty','Marzec','Kwiecień','Maj','Czerwiec','Lipiec','Sierpień','Wrzesień','Październik','Listopad','Grudzień'][now().month-1] }}"
1 polubienie

Dziękuję bardzo za naprowadzenie. Pozdrawiam