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

I have the jsonl and yaml posted here…

https://community.home-assistant.io/t/yet-another-smart-camper-project/779825/11

As I update the thermostat, I’ll update that post.

Currently, in auto mode, you can’t use the arc knobs to control heat and cool setpoints. This is because you can’t have a “transparent” clickable arc in front of another one. I have a thought on how to implement this differently - I’ll try it out later and if it’s successful, I will update.

Finally, I’d really like to simulate HA’s climate control where the arc becomes highlighted at the portion between the setpoint and current temp - when heating/cooling. I have some thoughts here, but it may prove too cumbersome to implement.

1 Like

Thanks for this i will have a look as my son has a campervan aswell.

If feeding it from 5V or 12V, that topic has a link to a 3D printable screw/mounting backplate stl file - for a clean surface mount install. I “implanted” a tiny 12v to 5v regulator in the display housing and just fed two wires out of the back.

Could please someone help me understand the general concept of this ESPhome/LVGL approach.
Correct me or amend:

  • First you flash your device with ESPhome. After this it is basically an empty ESP32 device visible in HA
  • Then you use one of the ESPhome-YAML files provided here or at other locations making use of the LVGL library and basically hand-code every display element with its behavior. (I’ve seen some YAML files making use of SVG graphics, which supposedly requires an install of an SVG library manually to ESPhome, but otherwise the main LVGL library is now directly available with any new version of ESPhome, no install necessary)
  • You integrate or copy one of these YAMLs in your ESPhome-YAML (either replace completely or keep some parts of your initial new YAML). Compile in ESPhome and OTA-update to the display.
  • Now you have your Smart Display but with the display elements and logics of what someone else has come up with for their needs
  • You basically re-do all the display-element and behavior coding by copy-pasting and adapting the YAML script to you liking in ESPhome

Is this how it works? Well, OpenHASP kind of repelled me for its use and dependency on multiple other HA parts, but the easiness of installing and tinkering/adapting to your layout is compelling…

Is there any recommended source/documentation of available LVGL/screen elements and the YAML code to paint and the logic required to drive them? Or do you guys copy-paste from the existing scripts here and use the LVGL manual only?

Such an exciting and lean approach, but I feel a bit lost.

Tom

I was hoping I had a solution for this - I tried making both arcs unclickable and floating an invisible object over (or under) each arc’s knob. With a little trigonometry, I was able to get these invisible knobs to “follow” the setpoint knobs. I hoped that if I enabled an arc’s click while I was holding down on the invisible knob, the arc would pick that up as a click. Alas, that did not work. The best I could come up with is to show/hide a setpoint knob when I clicked on the invisible knob (where the knob would be).

Video for reference…
Dual Mode Climate Control

Yes everything you say is true. Using ESPHome is much more flexible then OpenHASP but does require bit of coding. The ESPHome site has very good documentation on how everything works.

Get a screen, and download one of my basic examples. This will get you a working screen! then you can modify it. If you just want to add a few button you can do this with one line of code using my library.

2 Likes

Can the Battery port on the back be used to power the display?

All sorted. And working on 5v power supply.

So did you try the battery connector? Did it work? thanks!

Waiting for some MX 1.25 connectors from China.

Will let you know but i think its for a backup battery.

Hello,

is someone succeed with cover control please?

i follow the doc but nothing happen when i press up or down, here is my code :

the page on the screen :

    - id: cover_page
      widgets:
          - label:
              x: 100
              y: 50
              width: 100
              text: "Porche"
              text_align: CENTER
          - button:
              x: 100
              y: 110
              width: 100
              height: 100
              widgets:
                - label:
                    id: volet_up_porche
                    align: CENTER
                    text: "\U000F005D"
                    text_font: roboto_icons_51
              on_press:
                then:
                  - homeassistant.action:
                      action: cover.open
                      data:
                        entity_id: cover.volet_porche
          - button:
              x: 100
              y: 220
              width: 100
              height: 100
              widgets:
                - label:
                    id: volet_stop_porche
                    align: CENTER
                    text: STOP
                    text_font: roboto_icons_30
              on_press:
                then:
                  - homeassistant.action:
                      action: cover.stop
                      data:
                        entity_id: cover.volet_porche
          - button:
              x: 100
              y: 330
              width: 100
              height: 100
              widgets:
                - label:
                    id: volet_down_porche
                    align: CENTER
                    text: "\U000F0045"
                    text_font: roboto_icons_51
              on_press:
                then:
                  - homeassistant.action:
                      action: cover.close
                      data:
                        entity_id: cover.volet_porche

the sensor :

  - platform: homeassistant
    id: volet_porche_pos
    entity_id: cover.volet_porche
    attribute: current_position
    on_value:
      - if:
          condition:
            lambda: |-
              return x == 100;
          then:
            - lvgl.widget.update:
                id: volet_up_porche
                text_opa: 60%
          else:
            - lvgl.widget.update:
                id: volet_up_porche
                text_opa: 100%
      - if:
          condition:
            lambda: |-
              return x == 0;
          then:
            - lvgl.widget.update:
                id: volet_down_porche
                text_opa: 60%
          else:
            - lvgl.widget.update:
                id: volet_down_porche
                text_opa: 100%    

the text_sensor :

  - platform: homeassistant
    id: volet_porche_state
    entity_id: cover.volet_porche
    on_value:
      - if:
          condition:
            lambda: |-
              return ((0 == x.compare(std::string{"opening"})) or (0 == x.compare(std::string{"closing"})));
          then:
            - lvgl.label.update:
                id: volet_stop_porche
                text: "STOP"
          else:
            - lvgl.label.update:
                id: volet_stop_porche
                text:
                  format: "%.0f%%"
                  args: [ 'id(volet_porche_pos).get_state()' ]

doesnt understand why it doesnt work, i check code several times and entity.

thanks if someone see something or can provide his code?

perhaps api doesnt have to be with an encryption key?

EDIT : i try without encryption key, no difference, doesnt work.

Cover control actions

Available actions: cover.open_cover, cover.close_cover, cover.stop_cover, cover.toggle, cover.open_cover_tilt, cover.close_cover_tilt, cover.stop_cover_tilt, cover.toggle_tilt so you first need to update buttons

1 Like

Thanks a lot, you’re the boss! the docs and exemple in LVGL Esphome are outdated…i havent realize that all command have change…like cover.stop is cover.stop_cover now :smile:

thanks again @radugeo, lost a lot of time yesterday :smile:

Hey everyone,

Huge thanks again for all the effort on this project! The modular display setup looks really promising.

I’ve been trying out the guition-esp32-s3-4848s040-display modular.yaml example, and I’ve run into a bit of a roadblock. I keep getting an error saying it can’t find the lvgl.style.update action.

I was wondering if anyone else who’s tried this specific modular.yaml configuration has encountered the same issue? And if so, were you able to find a way around it? Any help or insights would be super appreciated!

Yeah sorry about that. I added support for theming the UI. You can now update the theme at runtime. In my demo I have a button that can switch from day to night theme. I was hoping this feature would be in an official release by now but it’s not. You need to compile with the DEV version of ESPHome.

If you have not run DEV before this is the command to load it.

pip install git+https://github.com/esphome/esphome.git@dev
1 Like

Hey

Just wanted to say a massive THANK YOU for the quick response and the explanation! and with the latest update on Git, it’s now working perfectly!

No problem they should have ESPHome 2025.4.0 out in a week or so and then you won’t need DEV.

1 Like

Now working with 2025.4.0b2

pip3 install esphome==2025.4.0b2

I just wanted to say a massive thank you to everyone, especially @clydebarrow and @andrew_NH, for making things so straightforward for non-devs like me. I’ve swapped out all my light switches for the 4-inch guition and had a play over the last couple of weeks. I’ve set up a sort of stream that activates when someone rings the doorbell, and I was wondering if there’s a better way to do this. Here’s what I’ve got so far:

# -------------------------------------------
# Doorbell
# -------------------------------------------
http_request:

online_image:
  - url: "http://192.168.1.10:8123/static/icons/favicon-192x192.png"
    id: my_online_image
    format: JPEG
    transparency: alpha_channel
    type: RGB565
    resize: 480x400
    on_download_finished:
      - lvgl.image.update:
          id: my_image_widget
          src: my_online_image

binary_sensor:
  - platform: homeassistant
    id: doorbell_pressed
    name: "Doorbell Pressed"
    entity_id: binary_sensor.video_doorbell_visitor
    on_state:
      then:
        - if:
            condition:
              - switch.is_on: doorbell_alerts
              - binary_sensor.is_on: presence_sensor
              - binary_sensor.is_on: doorbell_pressed
            then:
              - logger.log: "Doorbell pressed"
              - online_image.set_url:
                    id: my_online_image
                    url: !lambda return id(my_image_url).state;
              - lvgl.page.show: doorbell_page
              - lvgl.label.update:
                  id: doorbell_label
                  text: "Someone's at the front door"
              - light.turn_on:
                  id: backlight
                  brightness: 100%
              - repeat:
                  count: 20
                  then:
                    - online_image.set_url:
                          id: my_online_image
                          url: !lambda return id(my_image_url).state;
                    - delay: 3s
              - lvgl.label.update:
                  id: doorbell_label
                  text: "Doorbell"

text_sensor:
  - id: my_image_url
    platform: homeassistant
    entity_id: camera.video_doorbell_snapshots_fluent
    attribute: entity_picture
    filters:
      - prepend: http://192.168.1.10:8123

lvgl:
  pages:
    - id: doorbell_page
      <<: !include
        file: automations/on_swipe_right_page.yaml
        vars:
          page: menu_page
      <<: !include
        file: automations/on_swipe_left_page.yaml
        vars:
          page: main_page
      widgets:
        - obj:
            x: 0
            y: 30
            on_click:
              then:
                - online_image.set_url:
                    id: my_online_image
                    url: !lambda return id(my_image_url).state;
            scrollable: false
            align: TOP_LEFT          
            bg_color: 0x000000
            bg_opa: 30%
            pad_top: 0
            pad_bottom: 5
            pad_left: 10
            pad_right: 10
            styles: default_item
            width: 480
            height: 450
            widgets:
              - label:
                  # y: 10
                  id: doorbell_label
                  align: TOP_MID
                  text: "Doorbell"
                  text_font: regular_30
              - image:
                  id: my_image_widget
                  src: my_online_image
                  align: BOTTOM_MID
                  clip_corner: true
1 Like

Thanks for that.

I tried to use your repository but unfortunately keep running into issues. The latest shown below. Any thoughts on this?
Thanks again for your help!

INFO ESPHome 2025.4.0b3
INFO Reading configuration /config/guiton.yaml...
INFO Detected timezone 'Etc/UTC'
Failed config

display.st7701s: [source /config/modules/hardware/guition-esp32-s3-4848s040.yaml:99]
  
  This feature is only available with frameworks ['esp-idf'].
  platform: st7701s
  id: my_display
  update_interval: never
  auto_clear_enabled: False
  spi_mode: MODE3
  data_rate: 2MHz
  color_order: RGB
  invert_colors: False
  dimensions: 
    width: 480
    height: 480
  cs_pin: 39