ESP32 freezing every night

Try this code

# ─────────────── Default values ───────────────
substitutions:
  friendly_name: "UNSET_FRIENDLY_NAME"
  device_id:    "UNSET_DEVICE_ID"
  description:  "UNSET DESCRIPTION"
  area:         "UNSET AREA"
  is_esp_32:    "true"
  logger:       "INFO"

  inside_temp_sensor_id:  sensor.climate_temperature_2
  inside_temp_name:       "OFFICE"
  outside_temp_sensor_id: sensor.climate_temperature
  outside_temp_name:      "OUTSIDE"

# ─────────────── Wi‑Fi: keep the link alive & reboot if lost ───────────────
wifi:                        # <<<  NEW
  ssid:      !secret wifi_ssid
  password:  !secret wifi_pass
  power_save_mode: none      # stay awake → quicker reconnect
  reboot_timeout: 5min       # full restart only if Wi‑Fi gone 5 min
  # optional – comment if you don’t care
  # manual_ip:               # avoids DHCP dance right when router reboots
  #   static_ip:  192.168.1.120
  #   gateway:    192.168.1.1
  #   subnet:     255.255.255.0
  on_disconnect:             # blink RGB while offline  <<<  NEW
    then:
      - light.turn_on:
          id: rgb_led
          red: 100%
  on_connect:
    then:
      - light.turn_off: rgb_led

# ─────────────── Native API: don’t reboot just because HA is down ──────────
api:                         # <<<  NEW
  reboot_timeout: 0s         # Wi‑Fi watchdog already covers us
  encryption:
    key: !secret api_key

ota:
  password: !secret ota_pass

# ─────────────── Logging ───────────────
logger:
  level: INFO

# ─────────────── Pins, buses, framework (unchanged) ───────────────
i2c:
  - id: bus_a
    sda: GPIO1
    scl: GPIO2
    scan: false

spi:
  clk_pin:  GPIO7
  miso_pin: GPIO5
  mosi_pin: GPIO6

one_wire:
  - pin: GPIO10
    platform: gpio

esp32:
  board: esp32-c6-devkitc-1
  variant: esp32c6
  flash_size: 4MB
  framework:
    type: esp-idf
    version: 5.3.1
    platform_version: 6.9.0
    sdkconfig_options:
      CONFIG_ESPTOOLPY_FLASHSIZE_DETECT: y
      CONFIG_ESPTOOLPY_FLASHSIZE_4MB:  y
      CONFIG_OPENTHREAD_ENABLED:       n
      CONFIG_USE_MINIMAL_MDNS:         y
      # Memory optimisation
      COMPILER_OPTIMIZATION_SIZE:              y
      COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE:y
      CONFIG_HEAP_POISONING_DISABLED:          y

esphome:
  friendly_name: $friendly_name
  name:          $device_id
  name_add_mac_suffix: false
  comment: "${description}"
  area:   $area
  includes:
    - ./common/yaml/functions.h
  project:
    name: "Waveshare.ESP32-C6-LCD-1-47in"
    version: "v"
  platformio_options:
    board_build.flash_mode: dio
    build_flags:
      - "-DI2C_NUM_1=I2C_NUM_0"
      - "-Wl,-Map,output.map"
    board_build.arduino.memory_type: qio_opi
    platform_packages:
      - platformio/toolchain-xtensa-esp-elf @ 14.2.0+20241119

# (lights, sensors, fonts, colours … unchanged – trimmed for brevity)

# ─────────────── Display with watchdog feed ───────────────
display:
  - platform: st7789v
    cs_pin: GPIO14
    dc_pin:
      number: GPIO15
      ignore_strapping_warning: true
    reset_pin: GPIO21
    model: Waveshare 1.47in 172X320
    id: tft_ha
    rotation: 0
    pages:
      - id: page1
        lambda: |-
          App.feed_wdt();            // <<<  NEW – yield to RTOS first
          // id(tft_ha).update();    // (uncomment if you ever cache tiles)

          /*  … your original drawing code here – untouched …  */

          // inside the heavy for‑loop that draws the gradient,
          // add an extra feed every ~32 pixels so a huge bar
          // can’t starve networking for >100 ms
          for (int i = rect_start_x; i <= rect_end_x; i++) {
            DRAW_TEMP_COL(i);
            if ((i & 31) == 0) App.feed_wdt();   // <<< NEW
          }

          /*  … rest of the lambda unchanged …  */

# ─────────────────────────────────────────────────────────────

yields often enough to keep the watchdog happy and gives the Wi‑Fi stack clear rules for surviving your 02 : 29 router reboot.

Tweak Purpose
wifi.power_save_mode: none Keeps the radio awake so reconnect is immediate.
wifi.reboot_timeout: 5min Hard‑reset if the stack wedges after a long outage.
api.reboot_timeout: 0s Don’t reset just because Home Assistant is offline.
App.feed_wdt() at top of lambda Gives control back to the RTOS before the heavy drawing work.
Extra feed_wdt every 32 pixels Stops the gradient loop from blocking the TCP/IP task during outages.
LED feedback on on_disconnect / on_connect Visual clue that the node is offline while the router reboots.

Thank you. I will try that and report back.