Hi, thank you for the hint… Unfortunately esphome doesn’t support the display and also ArduinoGFX is not supported by esphome. It seems that you can add Arduino library’s but this is something which I have never did. So in the end I will give up, due my small amount of time. Hopefully the display IC get esphome support soon.
I am new to ESPHome, but can it be used for this display? Unfortunately, I haven’t managed to get anything shown on the display yet…
Hi
Yes you can use that display, the key is to set it to ili9342 and the resolution to 320 x 240, not 240 x 320
display:
- platform: ili9xxx
model: ili9342
spi_id: tft
cs_pin: GPIO15
dc_pin: GPIO2
rotation: 0
Have a look at https://github.com/jonnybergdahl/ESP32-Cheap-Yellow-Display/tree/main/Examples/ESPHome this helped me out
Cheers
Glad I found this! Two questions; one for @DerekSN : I have the same display but connected to an early ESP32 that has no param. Therefore the display buffer allocation always fails. Do you know if there’s a way to disable the buffer and write directly to the display?
And for @lukasz-tuz , you mentioned that LVGL requires a display driver – when used with the esphome display driver, at what level does it hook up? Any way I can get around not having enough ram?
EDIT: I see that in the Component, LVGL operates on a buffer, so I’m not getting out of that.
I know the display has examples using LVGL and zero psram, so it must at least be possible. The only question is whether I can do it in esphome (which is really key for me.)
I just discovered that the new LVGL Graphics — ESPHome component () has a buffer_size
option specifically for this kind of situation, when there is little or no PSRAM. That might be my way out.
I am pretty sure LVGL requires a buffer, so being able to set this size should help get this working for you.
Following the use of the new esphome-lvgl component, I no longer get out-of-memory errors. However, ili9341 still doesn’t seem to respond.
I noticed that your config specifies cs_pin
in addition to dc_pin
. Do you know if that’s a requirement? I have this device, and I cannot for the life of me figure out what the dc_pin is.
Maybe it’s not that, but it’s odd that there’s no error AND no response from the screen, even though the LVGL logs show updates every second.
UPDATE: I found the CS pin on an obscure site, (pin 15), but the screen is still blank
esphome:
platformio_options:
build_flags: "-DBOARD_HAS_PSRAM"
esp32:
board: esp32dev
framework:
# type: arduino
type: esp-idf
# Enable logging
logger:
level: VERBOSE
logs:
ili9xxx: VERBOSE
external_components:
- source: github://clydebarrow/esphome@lvgl
components: [ lvgl ]
debug:
update_interval: 5s
text_sensor:
- platform: debug
device:
name: "Device Info"
reset_reason:
name: "Reset Reason"
- platform: wifi_info
ip_address:
name: ESP IP Address
id: ip_address
on_value:
then:
- lvgl.label.update:
id: ip_address_label
text:
format: "%s"
args: [ 'id(ip_address).get_state().c_str()' ]
ssid:
name: ESP Connected SSID
bssid:
name: ESP Connected BSSID
mac_address:
name: ESP Mac Wifi Address
scan_results:
name: ESP Latest Scan Results
dns_address:
name: ESP DNS Address
spi:
- id: spi_bus0
clk_pin: 18
mosi_pin: 23
miso_pin: 19
display:
- platform: ili9xxx
model: ili9341
id: main_display
dc_pin: 2
spi_id: spi_bus0
data_rate: 20MHz
update_interval: never
auto_clear_enabled: false
invert_colors: true
dimensions:
height: 240
width: 320
transform:
swap_xy: true
mirror_y: true
mirror_x: true
lvgl:
log_level: TRACE
text_font: unscii_8
align: center
displays:
- display_id: main_display
buffer_size: 25%
widgets:
- obj:
bg_color: 0xFF0000
border_width: 8
pad_all: 8
height: size_content
width: size_content
widgets:
- label:
align: CENTER
text: 'IP Address'
- label:
id: ip_address_label
align: CENTER
text: 'n/a'
- label:
id: time_label
align: CENTER
text: 'n/a'
script:
- id: time_update
then:
- lvgl.label.update:
id: time_label
text:
format: "%02d : %02d"
args: [ 'id(time_comp).now().minute', 'id(time_comp).now().second' ]
time:
- platform: homeassistant
id: time_comp
on_time_sync:
- script.execute: time_update
on_time:
- minutes: '*'
seconds: '*'
then:
- script.execute: time_update
In my experience when the screen seems to be functioning but is blank, it’s normally the backlight, just make sure there’s no pin or config missing to turn on the backlight
I believe it’s labelled as TFT_RS on that board. You’ll also want to specify CS and RESET. You’ll need a schematic or sample code to figure out which pins they are. And you’ll need to turn on the backlight with the TFT_BL pin - a monochromatic light component will allow you to adjust the brightness.
Thanks for the tips.
Based on this wiring diagram for the TFT:
I figured the RS/DC is IO2 and CS is IO15.
There’s that pin labeled RESET
, but it seems to be hard-wired. Is that normal?
Regarding the BACKLIGHT, the screen seems to be lit up very bright (white). So at least I think it’s on by default.
There appears to be sample code here along with the wiring diagram I got here. (After translation, it says RESET is the LCD reset signal line. Because the GPIO on the start board is tight, it is connected to the RESET line of the system. Similarly, BL is the backlight control line of the LCD, which is also directly connected to 3.3V. – but I don’t know if that’s correct, or lost in translation. At least it would explain the backlight being always on.)
However, the sample code is very frustrating, because it uses macros like PIN_NUM_RST
, bit the headers that define those constants are not available – or at least I couldn’t figure out how to get them, even after having Google translate the page from Chinese.
Any suggestions?
For those interested in working with LVGL, I’ve successfully configured it using the following hardware setup:
Microcontroller: Lolin D32 PRO
Display: TFT 2.4 Touch Shield
TFT Driver: ILI9341
Touch Controller: XPT2046
Also notice the framework, not esp-idf but arduino did the trick for me.
esphome:
name: esp-display-lolin
friendly_name: ESP Display Lolin
platformio_options:
build_flags: "-DBOARD_HAS_PSRAM"
esp32:
board: lolin_d32_pro
framework:
type: arduino
external_components:
- source: github://clydebarrow/esphome@lvgl
components: [ lvgl ]
# Enable logging
logger:
# Enable Home Assistant API
api:
encryption:
key: !secret esphome_api
ota:
- platform: esphome
password: !secret esphome_ota
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
web_server:
local: true
captive_portal:
color:
- id: my_red
red: 100%
green: 0%
blue: 0%
- id: my_yellow
red: 100%
green: 100%
blue: 0%
- id: my_green
red: 0%
green: 100%
blue: 0%
- id: my_blue
red: 0%
green: 0%
blue: 100%
- id: my_gray
red: 50%
green: 50%
blue: 50%
- id: my_black
red: 0%
green: 0%
blue: 0%
- id: my_white
red: 100%
green: 100%
blue: 100%
font:
- file: "arial.ttf"
id: arial_48
size: 48
- file: "arial.ttf"
id: arial_36
size: 36
- file: "arial.ttf"
id: arial_24
size: 24
- file: "arial.ttf"
id: arial_12
size: 12
time:
- platform: homeassistant
id: esptime
sensor:
- platform: homeassistant
id: inside_temperature
entity_id: sensor.gw2000a_indoor_temperature
internal: true
- platform: homeassistant
id: outside_temperature
entity_id: sensor.gw2000a_temperature_1
internal: true
- platform: wifi_signal
name: "WiFi Signal Strength"
update_interval: 60s
spi:
clk_pin: 18
mosi_pin: 23
miso_pin: 19
touchscreen:
platform: xpt2046
id: touch_key1
cs_pin: 12
update_interval: 50ms
calibration:
x_min: 281
x_max: 3848
y_min: 347
y_max: 3878
transform:
mirror_x: false
mirror_y: false
swap_xy: false
lvgl:
displays:
- tft_ha_test
pages:
- id: main_page
widgets:
- label:
align: CENTER
text: 'Hello World!'
display:
- platform: ili9xxx
model: ili9341
cs_pin: 14
dc_pin: 27
reset_pin: 33
rotation: 90
auto_clear_enabled: false
invert_colors: false
show_test_card: false
id: tft_ha_test
I’m trying to get LVGL going on a Lanbon L8 but all I got was a blank screen UNTIL I removed the update_interval: never
line on the display. But I’m getting run-time errors:
[15:22:40][W][component:237]: Component display took a long time for an operation (72 ms).
[15:22:40][W][component:238]: Components should block for at most 30 ms.
[15:22:45][W][component:237]: Component display took a long time for an operation (72 ms).
[15:22:45][W][component:238]: Components should block for at most 30 ms.
Is the documentation wrong or am I doing something wrong?
Also, trying to test the touch screen by having a large checkable button in the middle of the screen. The label is there but not the button (it’s in the upper left) and it is TINY!
FYI, I’m familiar with LVGL using SquareLine Studio.
psram:
mode: octal
speed: 80MHz
spi:
clk_pin: GPIO19
mosi_pin: GPIO23
miso_pin: GPIO25
i2c:
sda: GPIO4
scl: GPIO0
font:
# gfonts://family[@weight]
- file: "gfonts://Roboto"
id: roboto_20
size: 20
display:
- id: langbon_L8
platform: st7789v
model: Custom
height: 320
width: 240
offset_height: 0
offset_width: 0
backlight_pin: GPIO5
cs_pin: GPIO22
dc_pin: GPIO21
reset_pin: GPIO18
auto_clear_enabled: false
touchscreen:
- platform: ft63x6
output:
- platform: ledc
pin: GPIO26
id: moodRed
- platform: ledc
pin: GPIO32
id: moodGreen
- platform: ledc
pin: GPIO33
id: moodBlue
- platform: gpio
pin: GPIO12
id: relay_1
- platform: gpio
pin: GPIO14
id: relay_2
- platform: gpio
pin: GPIO27
id: relay_3
light:
- platform: rgb
name: "Mood Light"
red: moodRed
green: moodGreen
blue: moodBlue
lvgl:
displays:
- langbon_L8
pages:
- id: main_page
widgets:
- button:
align: CENTER
height: 60
width: 200
checkable: true
bg_color: 0x0000FF
default:
bg_color: 0x00FF00
checked:
bg_color: 0xFF0000
- label:
text: "Click ME!"
align: CENTER
As per the docs, use the ili9xxx display component, not the deprecated st7789v component.
If you want the button to contain the label, it has to be a child of the button. See the example in the docs: LVGL Widgets — ESPHome
Switching to the ili9xxxx fixed the update issue and making the label a child of the button centered it on the button, but the button is still on the upper left and no sign that is is clickable.
display:
- id: langbon_L8
platform: ili9xxx
model: ST7789V
invert_colors: false
dimensions: 240x320
cs_pin: GPIO22
dc_pin: GPIO21
reset_pin: GPIO18
auto_clear_enabled: false
update_interval: never
...
lvgl:
pages:
- id: main_page
widgets:
- button:
x: 120
y: 120
height: 60
width: 150
checkable: true
default:
bg_color: 0x00FF00
checked:
bg_color: 0xFF0000
widgets:
- label:
text: "Click ME!"
align: CENTER
on_value:
then:
- logger.log:
format: "Button checked state: %d"
args: [ x ]
I can probably figure out the LGVL layout issues eventually (and how to manage the now-explicit backlight) but the lack of clicking needs help.
It is clickable (you will see it change when pressed) but the checkable
flag isn’t being set. Move the bg_color
setting out from default
to just under the button itself. Not sure why that affects it (could be a bug) but you never need to use the default
key anyway, since anything applied directly to the widget is the default.
Change
checkable: true
default:
bg_color: 0x00FF00
checked:
bg_color: 0xFF0000
to
checkable: true
bg_color: 0x00FF00
checked:
bg_color: 0xFF0000
just spent the weekend getting exactly this going!
here is my esphome config and it includes a display timeout and a clickable button that turns a homeassistant light entity on and off
spi:
clk_pin: GPIO19
mosi_pin: GPIO23
miso_pin: GPIO25
i2c:
sda: GPIO4
scl: GPIO0
display:
- platform: ili9xxx
model: ST7789V
cs_pin: GPIO22
dc_pin: GPIO21
reset_pin: GPIO18
invert_colors: false
auto_clear_enabled: false
update_interval: never
show_test_card: true
id: disp
rotation: 180
output:
- platform: ledc
pin: GPIO5
id: backlight_pwm
- platform: ledc
id: mood_red
pin: GPIO26
- platform: ledc
id: mood_green
pin: GPIO32
- platform: ledc
id: mood_blue
pin: GPIO33
light:
- platform: monochromatic
output: backlight_pwm
name: "Display Backlight"
id: backlight
restore_mode: ALWAYS_ON
- platform: rgb
name: "Moodlight"
red: mood_red
green: mood_green
blue: mood_blue
touchscreen:
platform: ft63x6
id: touch
display: disp
calibration:
x_min: 0
y_min: 0
x_max: 230
y_max: 312
on_touch:
- lambda: |-
ESP_LOGI("cal", "x=%d, y=%d, x_raw=%d, y_raw=%0d",
touch.x,
touch.y,
touch.x_raw,
touch.y_raw
);
on_release:
- if:
condition: lvgl.is_paused
then:
- logger.log: "LVGL resuming"
- lvgl.resume:
- lvgl.widget.redraw:
- light.turn_on: backlight
lvgl:
displays:
- disp
on_idle:
timeout: !lambda "return (id(display_timeout).state * 1000);"
then:
- logger.log: "LVGL is idle"
- light.turn_off: backlight
- lvgl.pause:
pages:
- id: main_page
widgets:
- button:
id: light_btn
align: CENTER
width: 140
height: 70
checkable: true
widgets:
- label:
align: CENTER
text: 'Lights'
on_click:
- homeassistant.action:
action: light.toggle
data:
entity_id: light.bedroom_lights
- logger.log:
format: "Button checked"
switch:
- platform: gpio
pin: GPIO12
name: relay1
- platform: gpio
pin: GPIO14
name: relay2
- platform: gpio
pin: GPIO27
name: relay3
binary_sensor:
- platform: homeassistant
id: bedroom_light
entity_id: light.bedroom_lights
publish_initial_state: true
on_state:
then:
lvgl.widget.update:
id: light_btn
state:
checked: !lambda return x;
- platform: lvgl
name: button2
widget: light_btn
publish_initial_state: true
number:
- platform: template
name: LVGL Screen timeout
optimistic: true
id: display_timeout
unit_of_measurement: "s"
initial_value: 45
restore_value: true
min_value: 10
max_value: 180
step: 5
mode: box
captive_portal:
Good luck here is a basic button matrix that seems to work a bit better than single buttons.
I will keep uploading my latest configs to: GitHub - jtbnz/esphome_lanbonL8: ESphome config for a Lanbon L8 LCD switch
pages:
- id: main_page
widgets:
- buttonmatrix:
x: 5
y: 40
width: 230
items:
pressed:
bg_color: 0xFFFF00
id: matrix_id
rows:
- buttons:
- id: light_btn
control:
checkable: true
text: ‘Lights’
on_click:
- homeassistant.action:
action: light.toggle
data:
entity_id: light.bedroom_lights
- logger.log:
format: “Button pressed”
- buttons:
- id: relay1_btn
control:
checkable: true
text: ‘Relay1’
on_click:
- switch.toggle: relay1
- logger.log:
format: “Relay Button pressed”
I’ve submitted a PR to document the configuration for fully integrated hardware platform.