ESP32-S3-N16R8 + SH1106 Black Screen when using LVGL

Hello,
I am new to displays on the ESP32. I have made a few simple projects using esp32-c3 and a pn532 RFID reader, and thought I was ready to tackle a display. After getting everything wired up and “Hello World!” displaying on the screen using lambda I was ecstatic, then I tried to get LVGL to work and hit a brick wall. Much searching and trials later I still cannot get it to work. so I am hoping that someone can tell me where I am messing up.

here is my setup:
esphome on a docker updated to the latest image.
ESP: ESP32-S3-N16R8
Display: SH1106 with a EC11 encoder (I2C Bus A)
Load Cell: 5K connected through a hx711
RFID/NFC reader: pn532 (I2C Bus B)

Code that works using lambda

esphome:
  name: drybox-rfid-screen
  friendly_name: DryBox RFID Screen
  platformio_options:
    board_build.arduino.memory_type: qio_opi
    board_build.flash_mode: qio
    build_flags:
      - "-DCONFIG_SPIRAM_CACHE_WORKAROUND"
      - "-mfix-esp32-psram-cache-issue"

esp32:
  board: esp32-s3-devkitc-1
  variant: esp32s3
  flash_size: 16MB
  framework:
    type: esp-idf
    sdkconfig_options:
      CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240: "y"
      CONFIG_ESP32S3_DATA_CACHE_64KB: "y"
      CONFIG_ESP32S3_DATA_CACHE_LINE_64B: "y"
      CONFIG_SPIRAM_FETCH_INSTRUCTIONS: y
      CONFIG_SPIRAM_RODATA: y 

psram:
  mode: octal
  speed: 80MHz    

globals:
  - id: source
    type: std::string
  - id: url
    type: std::string
  - id: info
    type: std::string
  - id: conversion_number
    type: float
    restore_value: no
    initial_value: '0.0'




# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: Retracted 

ota:
  - platform: esphome
    password: Retracted 

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

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Drybox-Rfid-Screen"
    password: Retracted 

captive_portal:


font:
    # gfonts://family[@weight]
  - file: "gfonts://Roboto"
    id: roboto_20
    size: 20

i2c:
  - id: bus_a
    sda: GPIO16
    scl: GPIO15
    scan: true
  - id: bus_b
    sda: GPIO08
    scl: GPIO09
    scan: true

switch:
- platform: template
  name: "${friendly_name} Buzzer Enabled"
  id: buzzer_enabled
  icon: mdi:volume-high
  optimistic: true
  restore_mode: RESTORE_DEFAULT_ON
  entity_category: config
- platform: template
  name: "${friendly_name} LED enabled"
  id: led_enabled
  icon: mdi:alarm-light-outline
  optimistic: true
  restore_mode: RESTORE_DEFAULT_ON
  entity_category: config


display:
  - platform: ssd1306_i2c
    id: my_display
    i2c_id: bus_a
    model: "SH1106 128x64"
    address: 0x3C
    lambda: |-
      // Print the string "Hello World!" at [0,10]
      it.print(0, 10, id(roboto_20), "Hello World!");


pn532_i2c:
  id: pn532_board
  i2c_id: bus_b
  update_interval: 1s

  on_tag:
    then:
      - if:
          condition:
            switch.is_on: led_enabled
          then:
          - light.turn_on:
              id: activity_led
              brightness: 100%
              red: 0%
              green: 100%
              blue: 0%
              flash_length: 500ms

      - delay: 0.15s #to fix slow component

      
      - lambda: |-
          id(source)="";
          id(url)="";
          id(info)="";
          if (tag.has_ndef_message()) 
          {
            auto message = tag.get_ndef_message();
            auto records = message->get_records();
            for (auto &record : records) 
            {
              std::string payload = record->get_payload();
              std::string type = record->get_type();
              size_t box = payload.find("Box");
              size_t spool = payload.find("Spool");
              

              if (type == "U" and box != std::string::npos ) 
              {
                ESP_LOGD("tagreader", "Found Box tag NDEF");
                id(source)="Box";
                id(url)=payload;
              }
              else if (type == "U" and spool != std::string::npos ) 
              {
                ESP_LOGD("tagreader", "Found Box tag NDEF");
                id(source)="Spool";
                id(url)=payload;
              }
              else if (type == "T" ) 
              {
                ESP_LOGD("tagreader", "Found music info tag NDEF");
                id(info)=payload;
              } 
              else if ( id(source)=="" ) 
              {
                id(source)="uid";
              }
            }
          }
          else 
          {
            id(source)="uid";
          }

      - if:
          condition:
            lambda: 'return ( id(source)=="uid" );'
          then:
            - homeassistant.tag_scanned: !lambda |-
                ESP_LOGD("tagreader", "No HA NDEF, using UID");
                return x;
          else:
          - if:
              condition:
                lambda: 'return ( id(source)=="hass" );'
              then:
              - homeassistant.tag_scanned: !lambda 'return id(info);'
              else:
              - homeassistant.event:
                  event: esphome.filament_tag
                  data:
                    reader: !lambda |-
                      return App.get_name().c_str();
                    source: !lambda |-
                      return id(source);
                    url: !lambda |-
                      return id(url);
                    info: !lambda |-
                      return id(info);

      - if:
          condition:
            switch.is_on: buzzer_enabled
          then:
#          - rtttl.play: "success:d=24,o=5,b=100:c,g,b"



light:
  - platform: esp32_rmt_led_strip
    rgb_order: GRB
    rmt_symbols: 48
    pin: GPIO48
    num_leds: 1
    chipset: ws2812
    id: activity_led    
    name: "${friendly_name} LED"
    restore_mode: ALWAYS_OFF

sensor:
  - platform: hx711
    name: "HX711 Value"
    dout_pin: GPIO11
    clk_pin: GPIO10
    gain: 128
    update_interval: 1s

  - platform: rotary_encoder
    name: "Rotary Encoder"
    id: rotaryencoder
    pin_a: GPIO05
    pin_b: GPIO06

binary_sensor:
  - platform: gpio
    name: "Back Button"
    id: back_button
    pin:
      number: GPIO4
      inverted: false
      mode:
        input: true
        pullup: true
  - platform: gpio
    name: "Encoder Push"
    id: encoder_push
    pin:
      number: GPIO7
      inverted: false
      mode:
        input: true
        pullup: true
  - platform: gpio
    name: "Confirm Button"
    id: confirm_button
    pin:
      number: GPIO17
      inverted: false
      mode:
        input: true
        pullup: true

here is the log for the above code:

INFO ESPHome 2026.2.4
INFO Reading configuration /config/drybox-rfid-screen.yaml...
INFO Starting log output from drybox-rfid-screen.local using esphome API
INFO Successfully resolved drybox-rfid-screen.local in 0.179s
INFO Successfully connected to drybox-rfid-screen @ 192.168.120.167 in 0.011s
INFO Successful handshake with drybox-rfid-screen @ 192.168.120.167 in 0.059s
[19:05:41.253][I][app:215]: ESPHome version 2026.2.4 compiled on 2026-03-20 18:23:11 -0500
[19:05:41.253][I][app:222]: ESP32 Chip: ESP32-S3 rev0.2, 2 core(s)
[19:05:41.253][C][logger:237]: Logger:
[19:05:41.253][C][logger:237]:   Max Level: DEBUG
[19:05:41.253][C][logger:237]:   Initial Level: DEBUG
[19:05:41.253][C][logger:244]:   Log Baud Rate: 115200
[19:05:41.253][C][logger:244]:   Hardware UART: USB_SERIAL_JTAG
[19:05:41.254][C][logger:254]:   Task Log Buffer Size: 768 bytes
[19:05:41.254][C][i2c.idf:093]: I2C Bus:
[19:05:41.254][C][i2c.idf:094]:   SDA Pin: GPIO16
[19:05:41.254][C][i2c.idf:094]:   SCL Pin: GPIO15
[19:05:41.254][C][i2c.idf:094]:   Frequency: 50000 Hz
[19:05:41.254][C][i2c.idf:104]:   Recovery: bus successfully recovered
[19:05:41.254][C][i2c.idf:114]: Results from bus scan:
[19:05:41.254][C][i2c.idf:120]: Found device at address 0x3C
[19:05:41.255][C][i2c.idf:093]: I2C Bus:
[19:05:41.255][C][i2c.idf:094]:   SDA Pin: GPIO8
[19:05:41.255][C][i2c.idf:094]:   SCL Pin: GPIO9
[19:05:41.255][C][i2c.idf:094]:   Frequency: 50000 Hz
[19:05:41.258][C][i2c.idf:104]:   Recovery: bus successfully recovered
[19:05:41.258][C][i2c.idf:114]: Results from bus scan:
[19:05:41.258][C][i2c.idf:120]: Found device at address 0x24
[19:05:41.273][C][esp32_rmt_led_strip:271]: ESP32 RMT LED Strip:
[19:05:41.273][C][esp32_rmt_led_strip:271]:   Pin: 48
[19:05:41.274][C][esp32_rmt_led_strip:275]:   RMT Symbols: 48
[19:05:41.274][C][esp32_rmt_led_strip:300]:   RGB Order: GRB
[19:05:41.274][C][esp32_rmt_led_strip:300]:   Max refresh rate: 0
[19:05:41.274][C][esp32_rmt_led_strip:300]:   Number of LEDs: 1
[19:05:41.284][C][gpio.binary_sensor:016]: GPIO Binary Sensor 'Back Button'
[19:05:41.285][C][gpio.binary_sensor:152]:   Pin: GPIO4
[19:05:41.285][C][gpio.binary_sensor:069]:   Mode: interrupt
[19:05:41.294][C][gpio.binary_sensor:071]:   Interrupt Type: ANY_EDGE
[19:05:41.295][C][gpio.binary_sensor:016]: GPIO Binary Sensor 'Encoder Push'
[19:05:41.295][C][gpio.binary_sensor:152]:   Pin: GPIO7
[19:05:41.295][C][gpio.binary_sensor:069]:   Mode: interrupt
[19:05:41.295][C][gpio.binary_sensor:071]:   Interrupt Type: ANY_EDGE
[19:05:41.295][C][gpio.binary_sensor:016]: GPIO Binary Sensor 'Confirm Button'
[19:05:41.303][C][gpio.binary_sensor:152]:   Pin: GPIO17
[19:05:41.303][C][gpio.binary_sensor:069]:   Mode: interrupt
[19:05:41.303][C][gpio.binary_sensor:071]:   Interrupt Type: ANY_EDGE
[19:05:41.324][C][light:091]: Light '${friendly_name} LED'
[19:05:41.324][C][light:094]:   Default Transition Length: 1.0s
[19:05:41.324][C][light:094]:   Gamma Correct: 2.80
[19:05:41.324][C][template.switch:092]: Template Switch '${friendly_name} Buzzer Enabled'
[19:05:41.324][C][template.switch:092]:   Restore Mode: restore defaults to ON
[19:05:41.336][C][template.switch:157]:   Icon: 'mdi:volume-high'
[19:05:41.337][C][template.switch:055]:   Optimistic: YES
[19:05:41.337][C][template.switch:092]: Template Switch '${friendly_name} LED enabled'
[19:05:41.337][C][template.switch:092]:   Restore Mode: restore defaults to ON
[19:05:41.349][C][template.switch:157]:   Icon: 'mdi:alarm-light-outline'
[19:05:41.349][C][template.switch:055]:   Optimistic: YES
[19:05:41.349][C][psram:016]: PSRAM:
[19:05:41.349][C][psram:019]:   Available: YES
[19:05:41.349][C][psram:021]:   Size: 8192 KB
[19:05:41.349][C][pn532:430]: PN532:
[19:05:41.354][C][pn532:488]:   Update Interval: 1.0s
[19:05:41.354][C][pn532_i2c:125]:   Address: 0x24
[19:05:41.364][C][hx711:017]: HX711 'HX711 Value'
[19:05:41.364][C][hx711:017]:   State Class: 'measurement'
[19:05:41.364][C][hx711:017]:   Unit of Measurement: ''
[19:05:41.364][C][hx711:017]:   Accuracy Decimals: 0
[19:05:41.371][C][hx711:157]:   Icon: 'mdi:scale'
[19:05:41.372][C][hx711:152]:   DOUT Pin: GPIO11
[19:05:41.372][C][hx711:152]:   SCK Pin: GPIO10
[19:05:41.372][C][hx711:488]:   Update Interval: 1.0s
[19:05:41.372][C][rotary_encoder:017]: Rotary Encoder 'Rotary Encoder'
[19:05:41.372][C][rotary_encoder:017]:   State Class: ''
[19:05:41.372][C][rotary_encoder:017]:   Unit of Measurement: 'steps'
[19:05:41.372][C][rotary_encoder:017]:   Accuracy Decimals: 0
[19:05:41.372][C][rotary_encoder:157]:   Icon: 'mdi:rotate-right'
[19:05:41.379][C][rotary_encoder:152]:   Pin A: GPIO5
[19:05:41.380][C][rotary_encoder:152]:   Pin B: GPIO6
[19:05:41.380][C][rotary_encoder:178]:   Restore Mode: Restore (Defaults to zero)
[19:05:41.421][C][rotary_encoder:182]:   Resolution: 1 Pulse Per Cycle
[19:05:41.421][C][ssd1306_i2c:022]: I2C SSD1306
[19:05:41.421][C][ssd1306_i2c:022]:   Rotations: 0 °
[19:05:41.421][C][ssd1306_i2c:022]:   Dimensions: 128px x 64px
[19:05:41.422][C][ssd1306_i2c:023]:   Model: SH1106 128x64
[19:05:41.422][C][ssd1306_i2c:023]:   External VCC: NO
[19:05:41.422][C][ssd1306_i2c:023]:   Flip X: YES
[19:05:41.422][C][ssd1306_i2c:023]:   Flip Y: YES
[19:05:41.422][C][ssd1306_i2c:023]:   Offset X: 0
[19:05:41.422][C][ssd1306_i2c:023]:   Offset Y: 0
[19:05:41.422][C][ssd1306_i2c:023]:   Inverted Color: NO
[19:05:41.424][C][ssd1306_i2c:033]:   Address: 0x3C
[19:05:41.424][C][ssd1306_i2c:488]:   Update Interval: 1.0s
[19:05:41.442][C][captive_portal:134]: Captive Portal:
[19:05:41.447][C][wifi:1450]: WiFi:
[19:05:41.447][C][wifi:1450]:   Local MAC: E0:72:A1:FC:E3:30
[19:05:41.447][C][wifi:1450]:   Connected: YES
[19:05:41.447][C][wifi:1202]:   IP Address: 192.168.120.167
[19:05:41.447][C][wifi:1213]:   SSID: [redacted]
[19:05:41.447][C][wifi:1213]:   BSSID: [redacted]
[19:05:41.447][C][wifi:1213]:   Hostname: 'drybox-rfid-screen'
[19:05:41.447][C][wifi:1213]:   Signal strength: -48 dB ▂▄▆█
[19:05:41.447][C][wifi:1213]:   Channel: 6
[19:05:41.447][C][wifi:1213]:   Subnet: 255.255.255.0
[19:05:41.447][C][wifi:1213]:   Gateway: 192.168.120.1
[19:05:41.447][C][wifi:1213]:   DNS1: 192.168.120.1
[19:05:41.447][C][wifi:1213]:   DNS2: 0.0.0.0
[19:05:41.687][C][esphome.ota:075]: Over-The-Air updates:
[19:05:41.687][C][esphome.ota:075]:   Address: drybox-rfid-screen.local:3232
[19:05:41.687][C][esphome.ota:075]:   Version: 2
[19:05:41.693][C][esphome.ota:082]:   Password configured
[19:05:41.695][C][safe_mode:022]: Safe Mode:
[19:05:41.695][C][safe_mode:022]:   Successful after: 60s
[19:05:41.695][C][safe_mode:022]:   Invoke after: 10 attempts
[19:05:41.695][C][safe_mode:022]:   Duration: 300s
[19:05:41.699][C][safe_mode:039]:   Bootloader rollback: support unknown
[19:05:41.699][D][hx711:029]: 'HX711 Value': Got value 115774
[19:05:41.699][D][sensor:118]: 'HX711 Value' >> 115774 
[19:05:41.705][C][web_server.ota:238]: Web Server OTA
[19:05:41.719][C][api:237]: Server:
[19:05:41.719][C][api:237]:   Address: drybox-rfid-screen.local:6053
[19:05:41.719][C][api:237]:   Listen backlog: 4
[19:05:41.719][C][api:237]:   Max connections: 8
[19:05:41.719][C][api:244]:   Noise encryption: YES
[19:05:41.722][C][mdns:177]: mDNS:
[19:05:41.722][C][mdns:177]:   Hostname: drybox-rfid-screen

Code that shows Black Screen:

esphome:
  name: drybox-rfid-screen
  friendly_name: DryBox RFID Screen
  platformio_options:
    board_build.arduino.memory_type: qio_opi
    board_build.flash_mode: qio
    build_flags:
      - "-DCONFIG_SPIRAM_CACHE_WORKAROUND"
      - "-mfix-esp32-psram-cache-issue"

esp32:
  board: esp32-s3-devkitc-1
  variant: esp32s3
  flash_size: 16MB
  framework:
    type: esp-idf
    sdkconfig_options:
      CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240: "y"
      CONFIG_ESP32S3_DATA_CACHE_64KB: "y"
      CONFIG_ESP32S3_DATA_CACHE_LINE_64B: "y"
      CONFIG_SPIRAM_FETCH_INSTRUCTIONS: y
      CONFIG_SPIRAM_RODATA: y 

psram:
  mode: octal
  speed: 80MHz    

globals:
  - id: source
    type: std::string
  - id: url
    type: std::string
  - id: info
    type: std::string
  - id: conversion_number
    type: float
    restore_value: no
    initial_value: '0.0'




# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: Retracted 

ota:
  - platform: esphome
    password: Retracted 

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

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Drybox-Rfid-Screen"
    password: Retracted 

captive_portal:


font:
    # gfonts://family[@weight]
  - file: "gfonts://Roboto"
    id: roboto_20
    size: 20

i2c:
  - id: bus_a
    sda: GPIO16
    scl: GPIO15
    scan: true
  - id: bus_b
    sda: GPIO08
    scl: GPIO09
    scan: true

switch:
- platform: template
  name: "${friendly_name} Buzzer Enabled"
  id: buzzer_enabled
  icon: mdi:volume-high
  optimistic: true
  restore_mode: RESTORE_DEFAULT_ON
  entity_category: config
- platform: template
  name: "${friendly_name} LED enabled"
  id: led_enabled
  icon: mdi:alarm-light-outline
  optimistic: true
  restore_mode: RESTORE_DEFAULT_ON
  entity_category: config


lvgl:
  log_level: "DEBUG"
# Example configuration entry
  displays:
    - my_display
  pages:
    - id: main_page
      widgets:
        - label:
            id: display_label
            align: CENTER
            text: "Waiting for Updates..."
            text_font: montserrat_10 
            long_mode: WRAP 

display:
  - platform: ssd1306_i2c
    id: my_display
    i2c_id: bus_a
    model: "SH1106 128x64"
    address: 0x3C
    auto_clear_enabled: false
    update_interval: never


pn532_i2c:
  id: pn532_board
  i2c_id: bus_b
  update_interval: 1s

  on_tag:
    then:
      - if:
          condition:
            switch.is_on: led_enabled
          then:
          - light.turn_on:
              id: activity_led
              brightness: 100%
              red: 0%
              green: 100%
              blue: 0%
              flash_length: 500ms

      - delay: 0.15s #to fix slow component

      
      - lambda: |-
          id(source)="";
          id(url)="";
          id(info)="";
          if (tag.has_ndef_message()) 
          {
            auto message = tag.get_ndef_message();
            auto records = message->get_records();
            for (auto &record : records) 
            {
              std::string payload = record->get_payload();
              std::string type = record->get_type();
              size_t box = payload.find("Box");
              size_t spool = payload.find("Spool");
              

              if (type == "U" and box != std::string::npos ) 
              {
                ESP_LOGD("tagreader", "Found Box tag NDEF");
                id(source)="Box";
                id(url)=payload;
              }
              else if (type == "U" and spool != std::string::npos ) 
              {
                ESP_LOGD("tagreader", "Found Box tag NDEF");
                id(source)="Spool";
                id(url)=payload;
              }
              else if (type == "T" ) 
              {
                ESP_LOGD("tagreader", "Found music info tag NDEF");
                id(info)=payload;
              } 
              else if ( id(source)=="" ) 
              {
                id(source)="uid";
              }
            }
          }
          else 
          {
            id(source)="uid";
          }

      - if:
          condition:
            lambda: 'return ( id(source)=="uid" );'
          then:
            - homeassistant.tag_scanned: !lambda |-
                ESP_LOGD("tagreader", "No HA NDEF, using UID");
                return x;
          else:
          - if:
              condition:
                lambda: 'return ( id(source)=="hass" );'
              then:
              - homeassistant.tag_scanned: !lambda 'return id(info);'
              else:
              - homeassistant.event:
                  event: esphome.filament_tag
                  data:
                    reader: !lambda |-
                      return App.get_name().c_str();
                    source: !lambda |-
                      return id(source);
                    url: !lambda |-
                      return id(url);
                    info: !lambda |-
                      return id(info);

      - if:
          condition:
            switch.is_on: buzzer_enabled
          then:
#          - rtttl.play: "success:d=24,o=5,b=100:c,g,b"



light:
  - platform: esp32_rmt_led_strip
    rgb_order: GRB
    rmt_symbols: 48
    pin: GPIO48
    num_leds: 1
    chipset: ws2812
    id: activity_led    
    name: "${friendly_name} LED"
    restore_mode: ALWAYS_OFF

sensor:
  - platform: hx711
    name: "HX711 Value"
    dout_pin: GPIO11
    clk_pin: GPIO10
    gain: 128
    update_interval: 1s

  - platform: rotary_encoder
    name: "Rotary Encoder"
    id: rotaryencoder
    pin_a: GPIO05
    pin_b: GPIO06

binary_sensor:
  - platform: gpio
    name: "Back Button"
    id: back_button
    pin:
      number: GPIO4
      inverted: false
      mode:
        input: true
        pullup: true
  - platform: gpio
    name: "Encoder Push"
    id: encoder_push
    pin:
      number: GPIO7
      inverted: false
      mode:
        input: true
        pullup: true
  - platform: gpio
    name: "Confirm Button"
    id: confirm_button
    pin:
      number: GPIO17
      inverted: false
      mode:
        input: true
        pullup: true

Log for the code that gives a black screen

INFO Successfully connected to drybox-rfid-screen @ 192.168.120.167 in 5.118s
INFO Successful handshake with drybox-rfid-screen @ 192.168.120.167 in 0.074s
[19:28:21.502][I][app:215]: ESPHome version 2026.2.4 compiled on 2026-03-20 19:07:28 -0500
[19:28:21.502][I][app:222]: ESP32 Chip: ESP32-S3 rev0.2, 2 core(s)
[19:28:21.502][C][logger:237]: Logger:
[19:28:21.502][C][logger:237]:   Max Level: DEBUG
[19:28:21.502][C][logger:237]:   Initial Level: DEBUG
[19:28:21.513][C][logger:244]:   Log Baud Rate: 115200
[19:28:21.513][C][logger:244]:   Hardware UART: USB_SERIAL_JTAG
[19:28:21.513][C][logger:254]:   Task Log Buffer Size: 768 bytes
[19:28:21.529][C][i2c.idf:093]: I2C Bus:
[19:28:21.536][C][i2c.idf:094]:   SDA Pin: GPIO16
[19:28:21.536][C][i2c.idf:094]:   SCL Pin: GPIO15
[19:28:21.536][C][i2c.idf:094]:   Frequency: 50000 Hz
[19:28:21.537][C][i2c.idf:104]:   Recovery: bus successfully recovered
[19:28:21.537][C][i2c.idf:114]: Results from bus scan:
[19:28:21.545][C][i2c.idf:120]: Found device at address 0x3C
[19:28:21.545][C][i2c.idf:093]: I2C Bus:
[19:28:21.545][C][i2c.idf:094]:   SDA Pin: GPIO8
[19:28:21.545][C][i2c.idf:094]:   SCL Pin: GPIO9
[19:28:21.545][C][i2c.idf:094]:   Frequency: 50000 Hz
[19:28:21.545][C][i2c.idf:104]:   Recovery: bus successfully recovered
[19:28:21.545][C][i2c.idf:114]: Results from bus scan:
[19:28:21.545][C][i2c.idf:120]: Found device at address 0x24
[19:28:21.552][C][esp32_rmt_led_strip:271]: ESP32 RMT LED Strip:
[19:28:21.552][C][esp32_rmt_led_strip:271]:   Pin: 48
[19:28:21.552][C][esp32_rmt_led_strip:275]:   RMT Symbols: 48
[19:28:21.552][C][esp32_rmt_led_strip:300]:   RGB Order: GRB
[19:28:21.552][C][esp32_rmt_led_strip:300]:   Max refresh rate: 0
[19:28:21.552][C][esp32_rmt_led_strip:300]:   Number of LEDs: 1
[19:28:21.567][C][gpio.binary_sensor:016]: GPIO Binary Sensor 'Back Button'
[19:28:21.568][C][gpio.binary_sensor:152]:   Pin: GPIO4
[19:28:21.568][C][gpio.binary_sensor:069]:   Mode: interrupt
[19:28:21.571][C][gpio.binary_sensor:071]:   Interrupt Type: ANY_EDGE
[19:28:21.571][C][gpio.binary_sensor:016]: GPIO Binary Sensor 'Encoder Push'
[19:28:21.572][C][gpio.binary_sensor:152]:   Pin: GPIO7
[19:28:21.580][C][gpio.binary_sensor:069]:   Mode: interrupt
[19:28:21.580][C][gpio.binary_sensor:071]:   Interrupt Type: ANY_EDGE
[19:28:21.581][C][gpio.binary_sensor:016]: GPIO Binary Sensor 'Confirm Button'
[19:28:21.584][C][gpio.binary_sensor:152]:   Pin: GPIO17
[19:28:21.585][C][gpio.binary_sensor:069]:   Mode: interrupt
[19:28:21.585][C][gpio.binary_sensor:071]:   Interrupt Type: ANY_EDGE
[19:28:21.608][C][light:091]: Light '${friendly_name} LED'
[19:28:21.608][C][light:094]:   Default Transition Length: 1.0s
[19:28:21.608][C][light:094]:   Gamma Correct: 2.80
[19:28:21.608][C][template.switch:092]: Template Switch '${friendly_name} Buzzer Enabled'
[19:28:21.608][C][template.switch:092]:   Restore Mode: restore defaults to ON
[19:28:21.616][C][template.switch:157]:   Icon: 'mdi:volume-high'
[19:28:21.616][C][template.switch:055]:   Optimistic: YES
[19:28:21.630][C][template.switch:092]: Template Switch '${friendly_name} LED enabled'
[19:28:21.630][C][template.switch:092]:   Restore Mode: restore defaults to ON
[19:28:21.630][C][template.switch:157]:   Icon: 'mdi:alarm-light-outline'
[19:28:21.630][C][template.switch:055]:   Optimistic: YES
[19:28:21.630][C][psram:016]: PSRAM:
[19:28:21.635][C][psram:019]:   Available: YES
[19:28:21.635][C][psram:021]:   Size: 8192 KB
[19:28:21.635][C][pn532:430]: PN532:
[19:28:21.638][C][pn532:488]:   Update Interval: 1.0s
[19:28:21.638][C][pn532_i2c:125]:   Address: 0x24
[19:28:21.642][C][hx711:017]: HX711 'HX711 Value'
[19:28:21.642][C][hx711:017]:   State Class: 'measurement'
[19:28:21.642][C][hx711:017]:   Unit of Measurement: ''
[19:28:21.642][C][hx711:017]:   Accuracy Decimals: 0
[19:28:21.644][C][hx711:157]:   Icon: 'mdi:scale'
[19:28:21.645][C][hx711:152]:   DOUT Pin: GPIO11
[19:28:21.645][C][hx711:152]:   SCK Pin: GPIO10
[19:28:21.667][C][hx711:488]:   Update Interval: 1.0s
[19:28:21.667][C][rotary_encoder:017]: Rotary Encoder 'Rotary Encoder'
[19:28:21.667][C][rotary_encoder:017]:   State Class: ''
[19:28:21.667][C][rotary_encoder:017]:   Unit of Measurement: 'steps'
[19:28:21.667][C][rotary_encoder:017]:   Accuracy Decimals: 0
[19:28:21.667][C][rotary_encoder:157]:   Icon: 'mdi:rotate-right'
[19:28:21.667][C][rotary_encoder:152]:   Pin A: GPIO5
[19:28:21.667][C][rotary_encoder:152]:   Pin B: GPIO6
[19:28:21.667][C][rotary_encoder:178]:   Restore Mode: Restore (Defaults to zero)
[19:28:21.701][C][rotary_encoder:182]:   Resolution: 1 Pulse Per Cycle
[19:28:21.701][C][ssd1306_i2c:022]: I2C SSD1306
[19:28:21.701][C][ssd1306_i2c:022]:   Rotations: 0 °
[19:28:21.701][C][ssd1306_i2c:022]:   Dimensions: 128px x 64px
[19:28:21.701][C][ssd1306_i2c:023]:   Model: SH1106 128x64
[19:28:21.701][C][ssd1306_i2c:023]:   External VCC: NO
[19:28:21.701][C][ssd1306_i2c:023]:   Flip X: YES
[19:28:21.701][C][ssd1306_i2c:023]:   Flip Y: YES
[19:28:21.701][C][ssd1306_i2c:023]:   Offset X: 0
[19:28:21.701][C][ssd1306_i2c:023]:   Offset Y: 0
[19:28:21.701][C][ssd1306_i2c:023]:   Inverted Color: NO
[19:28:21.704][C][ssd1306_i2c:033]:   Address: 0x3C
[19:28:21.704][C][ssd1306_i2c:484]:   Update Interval: never
[19:28:21.709][C][lvgl:103]: LVGL:
[19:28:21.709][C][lvgl:103]:   Display width/height: 128 x 64
[19:28:21.709][C][lvgl:103]:   Buffer size: 100%
[19:28:21.709][C][lvgl:103]:   Rotation: 0
[19:28:21.709][C][lvgl:103]:   Draw rounding: 2
[19:28:21.727][C][captive_portal:134]: Captive Portal:
[19:28:21.738][C][wifi:1450]: WiFi:
[19:28:21.738][C][wifi:1450]:   Local MAC: E0:72:A1:FC:E3:30
[19:28:21.738][C][wifi:1450]:   Connected: YES
[19:28:21.738][C][wifi:1202]:   IP Address: 192.168.120.167
[19:28:21.742][C][wifi:1213]:   SSID: [redacted]
[19:28:21.742][C][wifi:1213]:   BSSID: [redacted]
[19:28:21.742][C][wifi:1213]:   Hostname: 'drybox-rfid-screen'
[19:28:21.742][C][wifi:1213]:   Signal strength: -53 dB ▂▄▆█
[19:28:21.742][C][wifi:1213]:   Channel: 6
[19:28:21.742][C][wifi:1213]:   Subnet: 255.255.255.0
[19:28:21.742][C][wifi:1213]:   Gateway: 192.168.120.1
[19:28:21.742][C][wifi:1213]:   DNS1: 192.168.120.1
[19:28:21.742][C][wifi:1213]:   DNS2: 0.0.0.0
[19:28:21.747][C][esphome.ota:075]: Over-The-Air updates:
[19:28:21.747][C][esphome.ota:075]:   Address: drybox-rfid-screen.local:3232
[19:28:21.747][C][esphome.ota:075]:   Version: 2
[19:28:21.747][C][esphome.ota:082]:   Password configured
[19:28:21.754][C][safe_mode:022]: Safe Mode:
[19:28:21.754][C][safe_mode:022]:   Successful after: 60s
[19:28:21.754][C][safe_mode:022]:   Invoke after: 10 attempts
[19:28:21.754][C][safe_mode:022]:   Duration: 300s
[19:28:21.773][C][safe_mode:039]:   Bootloader rollback: supported
[19:28:21.773][C][web_server.ota:238]: Web Server OTA
[19:28:21.779][C][api:237]: Server:
[19:28:21.779][C][api:237]:   Address: drybox-rfid-screen.local:6053
[19:28:21.779][C][api:237]:   Listen backlog: 4
[19:28:21.779][C][api:237]:   Max connections: 8
[19:28:21.779][C][api:244]:   Noise encryption: YES
[19:28:21.785][C][mdns:177]: mDNS:
[19:28:21.785][C][mdns:177]:   Hostname: drybox-rfid-screen
[19:28:22.470][D][hx711:029]: 'HX711 Value': Got value 115735
[19:28:23.354][D][sensor:118]: 'HX711 Value' >> 115735 
[19:28:23.474][D][hx711:029]: 'HX711 Value': Got value 115770
[19:28:24.354][D][sensor:118]: 'HX711 Value' >> 115770 

Hopefully someone can see what I am doing wrong.

Afaik oled display needs update interval. Try:
update_interval: 500ms

Also, empty lvgl: config should give “hello world” page.

Try reading the notes associated with the latest 2026.3 ESPHome changes before you apply them and make the appropriate code changes as there has been some LVGL work included.

Clean your ESPHome cache as well, just to be sure, and be aware the first compile after you do that may take a few minutes longer as it loads the very latest updates before unpacking and compiling.

ok, I missed the section that stated “but note that some displays such as OLED and e-paper will need the update interval set to a suitable interval, or make use of the on_draw_end trigger to manually update the display.”, I must have skipped over that section without it clicking that I am using an OLED display at least 50 times.

I have tried both 500ms, 100ms and on_draw_end, there was a change, I have a solid white screen now instead of a solid black one, with it flashing every now and then.

not sure what you mean, how is lvgl: empty? there is code below it, and it looks like the samples I have found when searching.

here is the new code

lvgl:
  displays:
    - my_display
  pages:
    - id: main_page
      widgets:
        - label:
            id: display_label
            align: CENTER
            text: "Hello World"
            text_font: montserrat_10 
            long_mode: WRAP
  on_draw_end:
    component.update: my_display 


display:
  - platform: ssd1306_i2c
    id: my_display
    i2c_id: bus_a
    model: "SH1106 128x64"
    address: 0x3C
    auto_clear_enabled: false
#    update_interval: 500ms    
#    update_interval: 100ms

I did update to 2026.3 last night after posting the original message, to see if it made any difference. I did clean the cache and sis a build from scratch, same issue. the only thing that showed any reaction was changing the update interval as mentioned above.

thank you both for your help.

While I was browsing another post I found the solution to the white screen.

and

but I would not have gotten here with out the help from Karosm and IOT7712

thanks again.
The Doc

From docs:
" To get started, it is sufficient to add a display and an empty LVGL configuration. If neither pages nor widgets is specified, then a default “hello world” page will be shown."

1 Like