ESP32-4848S040C_I 4 inch capacitive touch screen weather display

If it can help. With the help of Claude AI, we were able to set up a ESP32-4848S04C_I display to show inside/outside temp/humidity and the HA default weather actual state. It was quite a challenge. Next change will be to allow touch screen to change the weather actual state to the day's forecast.
The ESP32 configuration is as follow:

# ════════════════════════════════════════════════════════════════════
#  Tableau de Bord ESPHome — ESP32-4848S040C_I (480×480, tactile)
#  Affiche: Temp. intérieure, temp. extérieure, météo HA avec icônes
# ════════════════════════════════════════════════════════════════════

substitutions:
  device_name: esp32-dashboard
  friendly_name: "Tableau de Bord"

esphome:
  name: ${device_name}
  friendly_name: ${friendly_name}
  platformio_options:
    board_build.flash_mode: dio
    board_upload.maximum_size: 16777216
  on_boot:
    priority: -100
    then:
      - light.turn_on:
          id: backlight_light
          brightness: 100%

# ─────────────────────────────────────────────────────────────────────
# ESP32-S3 — 16 Mo Flash, 8 Mo PSRAM OPI (requis pour LVGL + RGB LCD)
# ─────────────────────────────────────────────────────────────────────
esp32:
  board: esp32-s3-devkitc-1
  variant: esp32s3
  flash_size: 16MB
  framework:
    type: esp-idf
    version: recommended
    sdkconfig_options:
      CONFIG_ESP32S3_DATA_CACHE_LINE_64B: "y"

psram:
  mode: octal
  speed: 80MHz

# ─────────────────────────────────────────────────────────────────────
# Réseau & intégration
# ─────────────────────────────────────────────────────────────────────
wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  ap:
    ssid: "${friendly_name} AP"
    password: "configureme"

captive_portal:

logger:
  level: DEBUG
  hardware_uart: UART0   # libère GPIO19/GPIO20 du USB Serial JTAG

api:
  encryption:
    key: !secret api_encryption_key

ota:
  - platform: esphome
    password: !secret ota_password

# ─────────────────────────────────────────────────────────────────────
# I2C — Contrôleur tactile GT911
#   SDA: GPIO19 / SCL: GPIO45 (vérifier selon révision de carte)
# ─────────────────────────────────────────────────────────────────────
i2c:
  id: i2c_touch
  sda: GPIO19
  scl: GPIO45            # ✅ confirmé par source communautaire
  scan: false
  frequency: 10kHz

# ─────────────────────────────────────────────────────────────────────
# Rétroéclairage PWM (GPIO38)
# ─────────────────────────────────────────────────────────────────────
output:
  - platform: ledc
    id: backlight_output
    pin: GPIO38

light:
  - platform: monochromatic
    id: backlight_light
    name: "Rétroéclairage"
    output: backlight_output
    restore_mode: ALWAYS_ON
    default_transition_length: 0s

# ─────────────────────────────────────────────────────────────────────
# Écran tactile GT911
# ─────────────────────────────────────────────────────────────────────
touchscreen:
  - platform: gt911
    id: touch_panel
    i2c_id: i2c_touch
    address: 0x14          # ✅ confirmé par le log précédent
    # interrupt_pin retiré — GPIO18 utilisé par de_pin du display

# ─────────────────────────────────────────────────────────────────────
# Bus SPI — requis par st7701s. GPIO47/48 = init uniquement.
# miso_pin: GPIO41 requis par cette carte (confirmé par tests)
# ─────────────────────────────────────────────────────────────────────
spi:
  clk_pin: GPIO48
  mosi_pin: GPIO47
  miso_pin: GPIO41

# ─────────────────────────────────────────────────────────────────────
# Affichage ST7701S — RGB 480×480
# ✅ Paramètres CONFIRMÉS par tests sur la carte physique
# ─────────────────────────────────────────────────────────────────────
display:
  - platform: st7701s
    id: main_display
    update_interval: never
    auto_clear_enabled: false
    spi_mode: MODE3          # ✅ confirmé (MODE0 ne fonctionnait pas)
    cs_pin: GPIO39
    # reset_pin retiré — GPIO4 utilisé par data_pins red
    dimensions:
      width: 480
      height: 480
    color_order: RGB          # ✅ confirmé (rouge = rouge)
    invert_colors: false
    pclk_frequency: 16MHz
    pclk_pin: GPIO21          # ✅ confirmé
    de_pin: GPIO18            # ✅ confirmé
    vsync_pin: GPIO17         # ✅ confirmé
    hsync_pin: GPIO16         # ✅ confirmé
    hsync_front_porch: 10
    hsync_pulse_width: 9
    hsync_back_porch: 50
    vsync_front_porch: 10
    vsync_pulse_width: 9
    vsync_back_porch: 20
    data_pins:               # ✅ confirmés par tests
      blue:
        - 11   # B1
        - 12   # B2
        - 13   # B3
        - 14   # B4
        - 0    # B5
      green:
        - 8    # G0
        - 20   # G1
        - 3    # G2
        - 46   # G3
        - 9    # G4
        - 10   # G5
      red:
        - 4    # R1
        - 5    # R2
        - 6    # R3
        - 7    # R4
        - 15   # R5

# ─────────────────────────────────────────────────────────────────────
# Polices de caractères
#   Roboto: via Google Fonts (téléchargé automatiquement à la compile)
#   MDI   : placer materialdesignicons-webfont.ttf dans /config/esphome/
#           https://github.com/Templarian/MaterialDesign-Webfont/raw/master/fonts/materialdesignicons-webfont.ttf
# ─────────────────────────────────────────────────────────────────────
font:
  - file: "gfonts://Roboto"
    id: font_s        # Textes secondaires
    size: 16
  - file: "gfonts://Roboto"
    id: font_m        # Labels
    size: 22
  - file: "gfonts://Roboto"
    id: font_l        # Valeurs
    size: 38
  - file: "gfonts://Roboto"
    id: font_xl       # Températures principales
    size: 58
  - file: "gfonts://Roboto"
    id: font_clock    # Horloge
    size: 46
    glyphs: "0123456789:"

  # Icônes météo MDI (taille grande — carte météo)
  - file: "materialdesignicons-webfont.ttf"
    id: mdi_large
    size: 88
    glyphs:
      - "\U000F0599"  # weather-sunny
      - "\U000F0594"  # weather-night
      - "\U000F0595"  # weather-partly-cloudy
      - "\U000F0590"  # weather-cloudy
      - "\U000F0591"  # weather-fog
      - "\U000F0597"  # weather-rainy
      - "\U000F0596"  # weather-pouring
      - "\U000F0F36"  # weather-snowy
      - "\U000F067F"  # weather-snowy-rainy
      - "\U000F0592"  # weather-hail
      - "\U000F0593"  # weather-lightning
      - "\U000F059F"  # weather-lightning-rainy
      - "\U000F059D"  # weather-windy
      - "\U000F059E"  # weather-windy-variant
      - "\U000F0F38"  # weather-dust / exceptionnel

  # Icônes MDI petites (étiquettes de cartes)
  - file: "materialdesignicons-webfont.ttf"
    id: mdi_small
    size: 22
    glyphs:
      - "\U000F050F"  # thermometer
      - "\U000F058E"  # water-percent (humidité)
      - "\U000F059D"  # weather-windy
      - "\U000F0590"  # weather-cloudy

# ─────────────────────────────────────────────────────────────────────
# Heure SNTP
# ─────────────────────────────────────────────────────────────────────
time:
  - platform: sntp
    id: sntp_time
    timezone: "America/Toronto"   # Montréal = America/Toronto
    servers:
      - 0.ca.pool.ntp.org
      - 1.pool.ntp.org
    on_time:
      # Mise à jour de l'horloge toutes les minutes
      - seconds: 0
        then:
          - lvgl.label.update:
              id: lbl_time
              text: !lambda |-
                return id(sntp_time).now().strftime("%H:%M");
      # Mise à jour de la date toutes les 30 s (rattrape le démarrage)
      - seconds: /30
        then:
          - lvgl.label.update:
              id: lbl_date
              text: !lambda |-
                static const char* jours[] =
                  {"Dim","Lun","Mar","Mer","Jeu","Ven","Sam"};
                static const char* mois[] =
                  {"Jan","Fev","Mar","Avr","Mai","Jun",
                   "Jul","Aou","Sep","Oct","Nov","Dec"};
                auto t = id(sntp_time).now();
                if (!t.is_valid()) return std::string("---");
                char buf[24];
                snprintf(buf, sizeof(buf), "%s %d %s",
                  jours[t.day_of_week], t.day_of_month, mois[t.month - 1]);
                return std::string(buf);

# ─────────────────────────────────────────────────────────────────────
# Capteurs Home Assistant
# ─────────────────────────────────────────────────────────────────────
sensor:
  # ── Température intérieure (capteur 433 MHz) ──────────────────────
  - platform: homeassistant
    id: temp_int
    entity_id: sensor.rtl433_2029_temperature
    unit_of_measurement: "°C"
    on_value:
      then:
        - lvgl.label.update:
            id: lbl_temp_int
            text:
              format: "%.1f°"
              args: [ x ]

  # ── Température extérieure (capteur 433 MHz) ──────────────────────
  - platform: homeassistant
    id: temp_ext
    entity_id: sensor.rtl433_79_temperature
    unit_of_measurement: "°C"
    on_value:
      then:
        - lvgl.label.update:
            id: lbl_temp_ext
            text:
              format: "%.1f°"
              args: [ x ]

  # ── Humidité intérieure (capteur 433 MHz) ────────────────────────
  - platform: homeassistant
    id: hum_int
    entity_id: sensor.rtl433_2029_humidity
    unit_of_measurement: "%"
    on_value:
      then:
        - lvgl.label.update:
            id: lbl_hum_int
            text:
              format: "%.0f%%"
              args: [ x ]

  # ── Humidité extérieure (capteur 433 MHz) ────────────────────────
  - platform: homeassistant
    id: hum_ext
    entity_id: sensor.rtl433_79_humidity
    unit_of_measurement: "%"
    on_value:
      then:
        - lvgl.label.update:
            id: lbl_hum_ext
            text:
              format: "%.0f%%"
              args: [ x ]

  # ── Attributs de weather.forecast_maison ─────────────────────────
  - platform: homeassistant
    id: weather_temp
    entity_id: weather.forecast_maison
    attribute: temperature
    on_value:
      then:
        - lvgl.label.update:
            id: lbl_weather_temp
            text:
              format: "%.0f°C"
              args: [ x ]

  - platform: homeassistant
    id: weather_humidity
    entity_id: weather.forecast_maison
    attribute: humidity
    on_value:
      then:
        - lvgl.label.update:
            id: lbl_weather_hum
            text:
              format: "%.0f%%"
              args: [ x ]

  - platform: homeassistant
    id: weather_wind
    entity_id: weather.forecast_maison
    attribute: wind_speed
    on_value:
      then:
        - lvgl.label.update:
            id: lbl_weather_wind
            text:
              format: "%.0f km/h"
              args: [ x ]

  - platform: homeassistant
    id: weather_pressure
    entity_id: weather.forecast_maison
    attribute: pressure
    on_value:
      then:
        - lvgl.label.update:
            id: lbl_weather_pressure
            text:
              format: "%.0f hPa"
              args: [ x ]

# ── État météo + icône mappée ─────────────────────────────────────────
text_sensor:
  - platform: homeassistant
    id: weather_condition
    entity_id: weather.forecast_maison
    on_value:
      then:
        - lambda: |-
            // ── Correspondance condition HA → icône MDI + libellé FR ──
            struct WeatherMap {
              const char* state;
              const char* icon;
              const char* label_fr;
            };
            static const WeatherMap table[] = {
              { "sunny",            "\U000F0599", "Ensoleille"       },
              { "clear-night",      "\U000F0594", "Nuit claire"      },
              { "partlycloudy",     "\U000F0595", "Partiell. nuageux" },
              { "cloudy",           "\U000F0590", "Nuageux"          },
              { "fog",              "\U000F0591", "Brouillard"       },
              { "rainy",            "\U000F0597", "Pluie"            },
              { "pouring",          "\U000F0596", "Forte pluie"      },
              { "snowy",            "\U000F0F36", "Neige"            },
              { "snowy-rainy",      "\U000F067F", "Pluie/Neige"      },
              { "hail",             "\U000F0592", "Grele"            },
              { "lightning",        "\U000F0593", "Orage"            },
              { "lightning-rainy",  "\U000F059F", "Orage et pluie"   },
              { "windy",            "\U000F059D", "Venteux"          },
              { "windy-variant",    "\U000F059E", "Tres venteux"     },
              { "exceptional",      "\U000F0F38", "Exceptionnel"     },
            };
            const char* icon    = "\U000F0599";  // défaut: soleil
            const char* label   = "Inconnu";
            for (auto& e : table) {
              if (x == e.state) { icon = e.icon; label = e.label_fr; break; }
            }
            lv_label_set_text(id(lbl_weather_icon), icon);
            lv_label_set_text(id(lbl_weather_cond), label);

# ─────────────────────────────────────────────────────────────────────
# Interface LVGL — Tableau de bord 480×480
# ─────────────────────────────────────────────────────────────────────
lvgl:
  displays:
    - main_display
  touchscreens:
    - touch_panel
  color_depth: 16
  bg_color: 0x0D1117    # fond quasi-noir

  # ── Styles réutilisables ─────────────────────────────────────────
  style_definitions:
    - id: style_card
      bg_color: 0x161B22
      bg_opa: COVER
      border_color: 0x30363D
      border_width: 1
      radius: 14
      shadow_width: 10
      shadow_color: 0x000000
      shadow_opa: 80%
      pad_all: 14

    - id: style_label_sec
      text_color: 0x8B949E
      text_font: font_s

    - id: style_value_int
      text_color: 0xFFD700
      text_font: font_xl

    - id: style_value_ext
      text_color: 0x58A6FF
      text_font: font_xl

  pages:
    - id: page_main
      bg_color: 0x0D1117

      widgets:

        # ════════════════════════════════════════
        # EN-TÊTE  (bande du haut 480×62)
        # ════════════════════════════════════════
        - obj:
            x: 0
            y: 0
            width: 480
            height: 62
            bg_color: 0x161B22
            border_width: 0
            radius: 0
            pad_all: 0
            widgets:
              - label:
                  id: lbl_title
                  text: "Maison"
                  align: LEFT_MID
                  x: 18
                  text_font: font_m
                  text_color: 0x58A6FF

              - label:
                  id: lbl_date
                  text: "---"
                  align: CENTER
                  text_font: font_s
                  text_color: 0x8B949E

              - label:
                  id: lbl_time
                  text: "--:--"
                  align: RIGHT_MID
                  x: -18
                  text_font: font_clock
                  text_color: 0xE6EDF3

        # ════════════════════════════════════════
        # CARTE — Température + Humidité Intérieure
        # Position: colonne gauche, ligne 1
        # ════════════════════════════════════════
        - obj:
            styles: style_card
            x: 10
            y: 70
            width: 224
            height: 170
            widgets:
              - label:
                  text: "Interieur"
                  align: TOP_LEFT
                  text_font: font_s
                  text_color: 0x8B949E

              - label:
                  id: lbl_temp_int
                  text: "--°"
                  align: TOP_LEFT
                  y: 22
                  text_font: font_l
                  text_color: 0xFFD700

              # Ligne humidité (icône + valeur)
              - label:
                  text: "\U000F058E"
                  align: TOP_LEFT
                  y: 78
                  text_font: mdi_small
                  text_color: 0x58A6FF
              - label:
                  id: lbl_hum_int
                  text: "--%"
                  align: TOP_LEFT
                  x: 28
                  y: 80
                  text_font: font_m
                  text_color: 0xE6EDF3

              - label:
                  text: "rtl433 #2029"
                  align: BOTTOM_LEFT
                  text_font: font_s
                  text_color: 0x484F58

        # ════════════════════════════════════════
        # CARTE — Température + Humidité Extérieure
        # Position: colonne droite, ligne 1
        # ════════════════════════════════════════
        - obj:
            styles: style_card
            x: 246
            y: 70
            width: 224
            height: 170
            widgets:
              - label:
                  text: "Exterieur"
                  align: TOP_LEFT
                  text_font: font_s
                  text_color: 0x8B949E

              - label:
                  id: lbl_temp_ext
                  text: "--°"
                  align: TOP_LEFT
                  y: 22
                  text_font: font_l
                  text_color: 0x58A6FF

              # Ligne humidité (icône + valeur)
              - label:
                  text: "\U000F058E"
                  align: TOP_LEFT
                  y: 78
                  text_font: mdi_small
                  text_color: 0x58A6FF
              - label:
                  id: lbl_hum_ext
                  text: "--%"
                  align: TOP_LEFT
                  x: 28
                  y: 80
                  text_font: font_m
                  text_color: 0xE6EDF3

              - label:
                  text: "rtl433 #79"
                  align: BOTTOM_LEFT
                  text_font: font_s
                  text_color: 0x484F58

        # ════════════════════════════════════════
        # CARTE — Météo (grande, pleine largeur)
        # Position: ligne 2, toute la largeur
        # ════════════════════════════════════════
        - obj:
            styles: style_card
            x: 10
            y: 250
            width: 460
            height: 220
            widgets:

              # Titre de la carte
              - label:
                  text: "Meteo — Prevision maison"
                  align: TOP_LEFT
                  text_font: font_s
                  text_color: 0x8B949E

              # Icône météo MDI (grande, côté gauche)
              - label:
                  id: lbl_weather_icon
                  text: "\U000F0599"
                  align: LEFT_MID
                  x: 4
                  y: 12
                  text_font: mdi_large
                  text_color: 0xFFD700

              # ── Bloc infos météo (à droite de l'icône) ──────────────
              # Condition en texte
              - label:
                  id: lbl_weather_cond
                  text: "Chargement..."
                  x: 114
                  y: 44
                  text_font: font_m
                  text_color: 0xE6EDF3

              # Température météo (grande)
              - label:
                  id: lbl_weather_temp
                  text: "--°C"
                  x: 114
                  y: 72
                  text_font: font_l
                  text_color: 0xFFD700

              # Séparateur visuel
              - line:
                  points:
                    - x: 106
                      y: 130
                    - x: 448
                      y: 130
                  line_color: 0x30363D
                  line_width: 1

              # Humidité
              - label:
                  text: "\U000F058E"
                  x: 108
                  y: 140
                  text_font: mdi_small
                  text_color: 0x58A6FF
              - label:
                  id: lbl_weather_hum
                  text: "--%"
                  x: 136
                  y: 142
                  text_font: font_s
                  text_color: 0x8B949E

              # Vent
              - label:
                  text: "\U000F059D"
                  x: 220
                  y: 140
                  text_font: mdi_small
                  text_color: 0x58A6FF
              - label:
                  id: lbl_weather_wind
                  text: "-- km/h"
                  x: 248
                  y: 142
                  text_font: font_s
                  text_color: 0x8B949E

              # Pression
              - label:
                  text: "\U000F0590"
                  x: 108
                  y: 168
                  text_font: mdi_small
                  text_color: 0x58A6FF
              - label:
                  id: lbl_weather_pressure
                  text: "-- hPa"
                  x: 136
                  y: 170
                  text_font: font_s
                  text_color: 0x8B949E

Nice I have a weather library that does that already Claude can integrate it easilly.

1 Like

You should switch the display driver to mipi_rgb, there is a predefined model for your board.

1 Like