GUITION 4" 480x480 ESP32-S3-4848S040 Smart Display with LVGL

Like it says, you need to use esp-idf:

esp32:
  board: esp32-s3-devkitc-1
  framework:
    type: esp-idf

Thank you for your quick response. However, exactly that code (that you shared) is a few lines above the error in the guition-esp32-s3-4848s040.yaml.

So that is also what is puzzling me…

I can’t think of a better way. That code is really cool! What type of doorbell cam is it?

Here are so quick debug steps to get your screen working

  1. load the latest ESPHome (you are using the beta)
pip3 install esphome==2025.4.0
  1. Download my latest git repot
  1. build the demo for your screen.
esphome run guition-esp32-s3-4848s040-display_modular.yaml

It’s a Reolink doorbell, but I don’t see why it wouldn’t work with other cameras as long as the online image format is supported.



module diagram

1 Like

Just fine, canvas.draw_polygon was added on 2025.04.0, thanks @clydebarrow

What are these hardware modifications for?

Connecting the power supply directly, an IR remote control with a remote LED, connecting an external sensor via a connector

Does anyone know what the P1 connector is ?
Is it a uart ?
Is it accessible with ephome ?
thanks !

P1 is a serial port connected to pins 43 (uart0 TX) and 44 (uart0 RX) according to the docs I have.

I ordered the device and received it without the grey ā€˜back pack’ which enables easier powering and relays. Does anybody know where you can order it?
I reached out to the seller but he doesn’t seem to understand me (or doesn’t want to…)

if I understood correctly https://aliexpress.ru/item/1005006335587633.html

You do need to be careful and make sure you read the listing fully. For example, this one:
https://www.aliexpress.com/item/1005008506761923.html - Looks OK aside from the lack of relays and mains powered PSU.

https://www.aliexpress.com/item/1005006302251538.html is a similar description and price, but has the option of one or three relays (and includes the PSU).

If your seller won’t accept a return, I’d suggest using it as a test & development board and purchase another one (with relays). Always handy having a spare to check firmware & scripts on the bench.

I may have an extra (in the US) that I am not using. Have to look around. Let me know if helpful.

I have used Andrews code as a base the screen is working fine. I am trying to build a screen with 2 temp sliders and 3 buttons to toggle switches below that. so to start I have one slider configured and my background picture. The problem I seemed to be having was that when I compiled changes and uploaded using the usb cable nothing would change(that is a couple hours I will never get back). So I went back to a version that showed the slider and uploaded via WiFi this would reflect changes but I am back to my original problem my background image does not show up. I have had the image show up in a few of my many iterations so I know the reference is ok. If someone can spot the issue I would be grateful

lvgl:
  theme: !include { file: modules/base/theme.yaml }
  page_wrap: true # Keep this

  # Boot screen
  top_layer: !include
    file: modules/screens/boot_screen.yaml
    vars:
      height: $screen_height
      width: $screen_width

  # Main Page
  pages:
    - id: main_page
      
      widgets:
        
        - image:
            id: background_image
            src: lake1
            align: CENTER # Center the image within its bounds (the full screen)
            scrollable: false # Image itself is not scrollable

        
        - obj:
            id: controls_container # New container to hold and layout controls
            width: $screen_width # Make container same size as screen to overlay image
            height: $screen_height # Make container same size as screen to overlay image
            scrollable: false # This container is not scrollable (helps prevent scrolling)
            layout:
              type: flex
              flex_flow: COLUMN # <-- Use COLUMN for vertical stacking of children
              flex_align_main: START # Align items from the start (top) of the column
              flex_align_cross: CENTER # Center items horizontally within the column
            pad_all: 8 # Add padding to this container to push controls inwards from edges
            widgets:
              # Widgets inside this container will stack vertically
              - label: # First item in the column (will be above the slider)
                  id: target_temp_label_bedroom
                  text: "Bedroom Target: -- °C"
                  text_font: roboto36 # Use the desired font
                  text_color: black # Set text color
                  height: SIZE_CONTENT # Explicitly set height to content size
                  pad_bottom: 10 # Add padding below the label to push the slider down

              - slider: # Second item in the column (will be below the label)
                  id: target_temp_slider_bedroom
                  width: 95% # Percentage width relative to controls_container width
                  height: 50 # Fixed height in pixels
                  min_value: 15
                  max_value: 25
                  value: !lambda |-
                   return id(thermostat_target_temp_bedroom).state; // Initial value from sensor
                  on_change:
                    - then:
                        - homeassistant.action:
                            action: climate.set_temperature
                            data:
                              entity_id: climate.bedroomtt
                              temperature: !lambda |-
                                return x; // Use the slider's new value (x)

      # Event trigger attached to the page definition
      # Keep 'on_load' since it compiled for you previously.
      # Ensure correct indentation under - id: main_page
      on_load:
        then:
          - delay: 2s # Keep or remove as needed
          - lambda: |-
              // Correct lambda syntax to set the slider's value programmatically
              // Use the ID directly, not .obj
              if (!isnan(id(thermostat_target_temp_bedroom).state)) {
                lv_slider_set_value(id(target_temp_slider_bedroom), id(thermostat_target_temp_bedroom).state, LV_ANIM_OFF);
              }
              // Add logic for any other sliders here if you add them back

bg_opa: TRANSP was what I was missing. so that is solved, onward to adding other stuff

Next issue. I would like the buttons to be transparent or mostly transparent when they are off, I cannot get this to work using bg_opa or opa

pages:
    - id: main_page
      widgets:
        # Layer 1: Background Image - MUST be first
        - image:
            id: background_image
            src: lake1 # Use the ID directly, no quotes
            width: $screen_width
            height: $screen_height
            align: CENTER
            scrollable: false
            # Removed opacity: true as it's not standard

        # Layer 2: Controls Container that overlays the image - MUST be second
        - obj:
            id: controls_container
            width: $screen_width
            height: $screen_height
            scrollable: false # Prevent this container from scrolling
            # Make container background transparent so image shows through
            
            bg_opa: TRANSP # TRANSP = 0% opacity
            layout:
              type: flex
              flex_flow: COLUMN # Stack children vertically
              flex_align_main: START # Align children to the START (top)
              flex_align_cross: CENTER # Center children horizontally
            pad_all: 15 # Padding inside the container
            widgets:
              # Widgets inside this container stack vertically from the top
              - label:
                  id: target_temp_label_bedroom
                  text: "Bedroom Target: -- °C"
                  text_font: roboto36
                  text_color: white # Changed to white for better visibility on image
                  height: SIZE_CONTENT
                  pad_bottom: 10 # Adjusted padding
                  align: CENTER

              - slider:
                  id: target_temp_slider_bedroom
                  width: 85% # Relative to controls_container width
                  height: 50
                  min_value: 15
                  max_value: 25
                  value: !lambda |-
                   return id(thermostat_target_temp_bedroom).state;
                  on_change:
                    - then:
                        - homeassistant.action:
                            action: climate.set_temperature
                            data:
                              entity_id: climate.bedroomtt
                              temperature: !lambda |-
                                return x;
              - label:
                 id: target_temp_label_living_room
                 text: "Living Room Target: -- °C"
                 text_font: roboto36
                 text_color: white
              - slider:
                 id: target_temp_slider_livingroom
                 width: 85%  # Changed from lv_pct(95)
                 height: 50
                 min_value: 15
                 max_value: 25
                 value: !lambda |-
                  return id(thermostat_target_temp_livingroom).state;
                 on_change:
                   - then:
                       - homeassistant.action:
                           action: climate.set_temperature
                           data:
                             entity_id: climate.lr_talltimbers
                             temperature: !lambda |-
                               return x;                
              # Button 2 - Standard light button with state updates
              - button: !include
                  file: modules/buttons/switch_button.yaml
                  vars:
                    uid: button_2
                    height: $button_height_double
                    text: Button 2
                    opa: TRANSP
                    icon: $lightbulb
                    entity_id: "switch.craig_s_bedroom_lamp"

For anyone trying to do this in the future you need to edit the modules/base/theme.yaml file

---
    obj:
      border_width: 0
      pad_all: 0
      scrollable: false
#      outline_width: 1
#      outline_color: red
    label:
      border_width: 0
      scrollable: false
#      outline_width: 1
#      outline_color: red
    image:
      border_width: 0
      scrollable: false
#      outline_width: 1
#      outline_color: red
    button:
      text_font: $text_font
      checkable: false
      scroll_on_focus: true
      radius: 25px
      width: $button_width
      height: $button_height_single
      pad_all: 10px
      shadow_width: 0 # This is required even though the default is supposed to be 0
      bg_color: $button_off_color
      text_color: $label_off_color
      bg_opa: 25% # to make buttons transparent

Hi all,

Im having issues appending the celsius sign to my text sensor for temperature. its not adding the celsius., just showing the text for the temperature and box - suggesting the icon cant be rendered? Any ideas where i’m going wrong here?!

TEXT SENSOR

sensor:
  - platform: homeassistant
    entity_id: ${entity_id}
    id: text_sensor_${uid}
    on_value:
      - lvgl.label.update:
          id: text_lable_${uid}
          text:
            format: "%.1f \U000F050F"
            args: [ 'x' ]  

LABLE

    widgets:
      - label:
          text_font: roboto24
          text: "--.-°C"
          id: text_lable_${uid}
          align: CENTER
          #text_align: right
          text_color: 0xFFFFFF
          on_press:
            then:
              - lvgl.page.show: main_page 

Many thanks!

ah it was a font issues - please ignore :slight_smile:

tip is to make sure you have the same fonts assined in the sensor and label code.