Hallo allerseits!
Das folgende Projekt ist eigentlich nicht der Rede Wert, der Nutzen für andere geht wohl auch gegen Null…aber es hat extrem viel Spass gemacht und mein Wissen prächtig erweitert ![]()
Worum geht’s / Problemstellung:
In unseren Schlafzimmern gilt striktes Handy & Tablet Verbot (WAF…) Wenn ich in der Früh erwache, weiss ich nicht was ich anziehen soll. Grundlage hierfür wäre zu wissen, welche aktuelle Temperaturen anliegen, was die Tages-Höchsttemperatur sein wird und eine Zusammenfassung der allgemeinen Lage.
Ich habe keine Lust, am Morgen durch die Villa zu trotten, runter in die Küche, ein Tablet zu suchen oder vor den grossen HA Screen zu stehen und dann wieder nach oben anziehen gehen. Den Wetterbericht am Vorabend zu studieren ist ebenfalls sinnlos, da ich den beim Aufwachen vergessen habe.
Tja, was tun? Ich habe genug Entitäten im HA mit solchen Wetter-Infos, aber wie kann ich die “unsichtbar” in die Reithalle schmuggeln? ![]()
Bei meinen Streifzügen durch’s Internet blieb ich plötzlich bei VahaC und seinen Projekten hängen. Ich hatte mich zuvor noch nie gross mit ESP32 oder sonstigen Mikrokontroller beschäftigt. Aber hier tat sich eine ganz neue Welt für mich auf! Sein sehr gut dokumentiertes Touch-Display-Projekt hat mich sehr inspiriert und mich auf die Idee gebracht, meine Wetterinfos auf so ein Display zu bringen und selbiges im Bett-Rahmen zu verstecken ![]()
Also hopp-hopp bei Aliexpress für ein Appel und 'n Ei eine Handvoll CYD und Guition Displays bestellt. Schon krass wie wenig das kostet! Ich tat mich anfangs sehr schwer mit dem LVGL-GUI Design. Aber die ESPHome Designer Integration und der Online Designer halfen mir gewaltig aus der Patsche.
Nach erfolgreichen Tests konstruierte und druckte ich eine Halterung und fixierte diese mittels Klett an der Innenseite des kleinen in der Bett-Konstruktion integrierten Schrankes. Wenn ich via HA nun sanft zum aufwachen das Licht einschalte, geht das Display an und zeigt mir die benötigten Infos wenn ich die Türe öffne und geht wieder aus wenn das Licht ausschaltet wird. Diese Lösung hat vollumfänglich zu 100% den WAF erfüllt ![]()
So schaut es aus:
Hier der unoptimierte, aber funktionierende Code falls es jemanden interessiert:
# Board: Guition ESP32-S3-4848S040 480*480 Smart Screen
# Definition: definitions/boards/guition_esp32_s3_4848s040/manifest.yaml
esphome:
name: wetterman
friendly_name: WetterMan
esp32:
variant: esp32s3
framework:
type: esp-idf
# Enable logging
logger:
baud_rate: 0
level: INFO
api:
encryption:
key: !secret wetterman__encryption_key
ota:
- platform: esphome
encryption:
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
ap:
ssid: WetterMan Fallback Hotspot
password: "DeinPW"
captive_portal:
debug:
update_interval: 5s
touchscreen:
platform: gt911
id: my_touchscreen
transform:
swap_xy: false
mirror_x: false
mirror_y: false
on_release:
- if:
condition: lvgl.is_paused
then:
- lvgl.resume:
- lvgl.widget.redraw:
- light.turn_on: display_backlight
display:
- platform: st7701s
id: tft_display
spi_id: spihwd
dimensions:
width: 480
height: 480
# rotation: 270 # Uncomment for placement with down-facing USB socket
spi_mode: MODE3
data_rate: 2MHz
color_order: RGB
invert_colors: false
cs_pin: 39
de_pin: 18
hsync_pin: 16
vsync_pin: 17
pclk_pin: 21
pclk_frequency: 12MHz
pclk_inverted: false
hsync_pulse_width: 8
hsync_front_porch: 10
hsync_back_porch: 20
vsync_pulse_width: 8
vsync_front_porch: 10
vsync_back_porch: 10
auto_clear_enabled: false
update_interval: never
init_sequence:
- 1
- [0xFF, 0x77, 0x01, 0x00, 0x00, 0x10] # CMD2_BKSEL_BK0
- [0xCD, 0x00] # Disable MDT flag
data_pins:
red: [11, 12, 13, 14, 0]
green: [8, 20, 3, 46, 9, 10]
blue: [4, 5, 6, 7, 15]
# ====================================
# Device Settings
# ====================================
# Orientation: landscape
# Dark Mode: enabled
# Refresh Interval: 600
# Power Strategy: Backlight Off Schedule
# Deep Sleep: disabled
# Deep Sleep Stay Awake Switch: disabled
# Deep Sleep Stay Awake Entity: input_boolean.esphome_stay_awake
# Deep Sleep Firmware Guard: disabled
# Deep Sleep Interval: Disabled
# Layout Signature: 06db6003
# Layout Summary: mode=lvgl pages=1 widgets=6 types=label:1,lvgl_label:5
# Boot Log Hint: Compare the runtime build signature with this header to spot OTA rollbacks.
# ====================================
output:
- platform: ledc
pin: GPIO38
id: gpio_backlight_pwm
frequency: 100Hz
- id: internal_relay_1
platform: gpio
pin: GPIO40
- id: internal_relay_2
platform: gpio
pin: GPIO02
- id: internal_relay_3
platform: gpio
pin: GPIO01
light:
- platform: monochromatic
output: gpio_backlight_pwm
name: WetterMan Display Backlight
icon: mdi:lightbulb-on
id: wetterman_display_backlight
internal: false # Expose to Home Assistant as a normal light
restore_mode: ALWAYS_ON
gamma_correct: 1.0
spi:
clk_pin: GPIO48
mosi_pin: GPIO47
interface: hardware
id: spihwd
i2c:
id: touchscreen_bus
sda: GPIO19
scl:
number: 45
ignore_strapping_warning: true
psram:
mode: octal
speed: 80MHz
globals:
- id: display_page
type: int
restore_value: true
initial_value: '0'
- id: page_refresh_default_s
type: int
restore_value: true
initial_value: '600'
- id: page_refresh_current_s
type: int
restore_value: false
initial_value: '60'
- id: initial_sensor_sync_pending
type: bool
restore_value: false
initial_value: 'true'
time:
- platform: homeassistant
id: ha_time
# NUR FUER TEXTE
text_sensor:
- platform: debug
device:
name: "Device Info"
reset_reason:
name: "Reset Reason"
- platform: homeassistant
id: sensor_ischpf17_forecast_summary_0d
entity_id: sensor.ischpf17_forecast_summary_0d #Entität aus HA mit dem Kurz-Wetterbericht
on_value:
then:
- lvgl.widget.refresh: w_bericht
internal: true
icon: "mdi:weather-partly-cloudy"
# NUR FUER ZAHLEN ZND FLOATS
sensor:
- platform: homeassistant
id: sensor_ischpf17_temperature
entity_id: sensor.ischpf17_temperature #Entität aus HA mit der aktuellen Temperatur
unit_of_measurement: "°C"
internal: true
on_value:
- lvgl.label.update:
id: w_temp_aktuell
text: !lambda |-
float v = id(sensor_ischpf17_temperature).state;
if (isnan(v)) return "??";
return str_sprintf("%.0f °C", v);
- platform: homeassistant
id: sensor_ischpf17_forecast_temperature_0d
entity_id: sensor.ischpf17_forecast_temperature_0d #Entität aus HA mit der prognost. Tages-Höchsttemperatur
unit_of_measurement: "°C"
internal: true
on_value:
- lvgl.label.update:
id: w_temp_prognose
text: !lambda |-
float v = id(sensor_ischpf17_forecast_temperature_0d).state;
if (isnan(v)) return "??";
return str_sprintf("%.0f °C", v);
switch: #für HA zum Backlight ein- und ausschalten
- platform: homeassistant
id: ha_display_power
entity_id: input_boolean.display_wetterman_aktiv
on_turn_on:
- light.turn_on: display_backlight
on_turn_off:
- light.turn_off: display_backlight
font:
- file:
type: gfonts
family: "Montserrat"
weight: 400
italic: false
id: font_montserrat_400_30
size: 30
glyphsets: [GF_Latin_Kernel]
glyphs: "ÄÖÜäöüß°" # Umlaute etc auch korrekt anzeigen
ignore_missing_glyphs: true
- file:
type: gfonts
family: "Montserrat"
weight: 400
italic: false
id: font_montserrat_400_60
size: 60
glyphsets: [GF_Latin_Kernel]
glyphs: "ÄÖÜäöüß°"
ignore_missing_glyphs: true
- file:
type: gfonts
family: "Roboto"
weight: 400
italic: false
id: font_roboto_400_20
size: 20
glyphsets: [GF_Latin_Kernel]
ignore_missing_glyphs: true
script:
- id: manage_run_and_sleep
mode: restart
then:
- if:
condition:
lambda: 'return !(id(ha_time).now().is_valid() && api_is_connected());'
then:
- logger.log: "Waiting for sync..."
- wait_until:
condition:
lambda: 'return id(ha_time).now().is_valid() && api_is_connected();'
timeout: 120s
- if:
condition:
lambda: 'return id(initial_sensor_sync_pending);'
then:
- logger.log: "ESPHome Designer build: sig=06db6003 mode=lvgl pages=1 widgets=6 types=label:1,lvgl_label:5"
- logger.log: "OTA hint: if this build line does not match the YAML header, the device booted a different image or rolled back."
- logger.log: "Waiting 5s for initial sensor updates..."
- delay: 5s
- lambda: 'id(initial_sensor_sync_pending) = false;'
- lambda: |-
int interval = id(page_refresh_default_s);
id(page_refresh_current_s) = interval;
- delay: !lambda 'return id(page_refresh_current_s) * 1000;'
- script.execute: manage_run_and_sleep
# ============================================================================
# LVGL Configuration
# ============================================================================
lvgl:
id: my_lvgl
log_level: WARN
bg_color: "0x000000"
displays:
- tft_display
touchscreens:
- touchscreen_id: my_touchscreen
pages:
- id: page_0
widgets:
# --- Wetterbericht ---
- label:
id: w_bericht
text: !lambda |-
if (id(sensor_ischpf17_forecast_summary_0d).has_state()) {
return id(sensor_ischpf17_forecast_summary_0d).state;
}
return "Lade...";
text_align: "LEFT"
text_color: "0xB5B5B5"
text_font: font_montserrat_400_30
width: 438
height: 194
x: 22
y: 267
# --- Aktuelle Temperatur ---
- label:
id: w_temp_aktuell
text: !lambda |-
float v = id(sensor_ischpf17_temperature).state;
if (isnan(v)) return "??";
return str_sprintf("%.0f °C", v);
text_align: "CENTER"
text_color: "0xB5B5B5"
text_font: font_montserrat_400_60
width: 200
height: 60
x: 140
y: 37
# --- Prognose Temperatur ---
- label:
id: w_temp_prognose
text: !lambda |-
float v = id(sensor_ischpf17_forecast_temperature_0d).state;
if (isnan(v)) return "??";
return str_sprintf("%.0f °C", v);
text_align: "CENTER"
text_color: "0xB5B5B5"
text_font: font_montserrat_400_60
width: 200
height: 60
x: 140
y: 144
Nun, man muss sich im Leben einfach zu helfen wissen ![]()
