That did not work, i added the firmware from ESPHome and called it firmware.ota.bin and it did not flash the new firmware i created
Okay so you shouldnât be renaming a file. When you compile through the command line one of the files produced is named firmware.ota.bin
. That is the one I flashed using the factory web interface, then it worked.
Either way, if you can figure out the pinout of those pins on the left side of your picture you should be able to flash via serial the normal way.
I received this version also and have it workingâsort of. For a start could not get the code to work for 240x240, had to reduce it to 235 x 235.
Flashed the CS-32E as a ESP32
My code for display
Display:
- platform: ili9xxx
id: lcd_display
model: st7789v
spi_id: spihwd
data_rate: 40MHz #oringal device uses 20mhz - 40 is default and works - does not work at 80mhz
#cs_pin: GPIO03 #CS pin is connected to gnd I believe
dc_pin: GPIO02
reset_pin: GPIO04
spi_mode: MODE3 #since no cs pin default is mode0
dimensions:
width: 235
height: 235
offset_height: 0
offset_width: 0
invert_colors: true
So i am using ESPHome through Home Assistant and am not sure what i need flash to the device. @Dingo Would you be willing to post the whole yaml you used for yours?
Intially I used Home Assistant - ESPhomebuilder, create new device. I will post the code i usedâŚI still have some issues with sizing but trying to fix these, but its a start
esphome:
name: energytv
friendly_name: EnergyTV
esp32:
board: esp32dev
framework:
type: arduino
# Enable logging
logger:
level: VERBOSE
logs:
#lvgl.component: VERBOSE
light.component: ERROR
light.output: ERROR
number.component: ERROR
ledc.output: ERROR
template.number: ERROR
baud_rate: 0 #no hardware serial connected to USB - unless using the internal programming header
# Enable Home Assistant API
api:
encryption:
key: "mine"
ota:
- platform: esphome
password: "mine"
wifi:
ssid: IOT
password: mine
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Geekmagic-Hilo Fallback Hotspot"
password: "mine"
captive_portal:
external_components:
- source: github://clydebarrow/esphome@lvgl
components: [ lvgl ]
# Define a PWM output on the ESP32
output:
- platform: ledc
pin: GPIO25
inverted: True
id: backlight_pwm
# Define a monochromatic, dimmable light for the backlight
light:
- platform: monochromatic
output: backlight_pwm
name: "Display Backlight"
id: back_light
restore_mode: ALWAYS_ON
esp32_touch:
# setup_mode: true
sensor:
- platform: homeassistant
entity_id: sensor.shellyem_98cdac1f0b5f_channel_1_voltage
id: voltage
internal: true
state_class: measurement
unit_of_measurement: Volts
- platform: homeassistant
entity_id: sensor.shellyem_98cdac1f0b5f_channel_1_power
id: power
internal: true
state_class: measurement
unit_of_measurement: Watts
- platform: homeassistant
entity_id: sensor.shellyem_98cdac1f0b5f_channel_2_power
id: solarpower
internal: true
state_class: measurement
unit_of_measurement: Watts
spi:
clk_pin: GPIO18
mosi_pin: GPIO23
interface: hardware
id: spihwd
color:
- id: my_red
red: 100%
green: 0%
blue: 0%
- id: my_orange
red: 100%
green: 50%
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_teal
red: 0%
green: 100%
blue: 100%
- id: my_gray
red: 70%
green: 70%
blue: 70%
- id: my_white
red: 100%
green: 100%
blue: 100%
- id: my_black
red: 0%
green: 0%
blue: 0%
font:
- file: "gfonts://Roboto"
id: font_48
size: 48
- file: "gfonts://Roboto"
id: font_36
size: 36
- file: "gfonts://Roboto"
id: font_24
size: 24
- file: "gfonts://Roboto"
id: font_12
size: 12
- file: "gfonts://Roboto"
id: font_20
size: 20
display:
- platform: ili9xxx
id: lcd_display
model: st7789v
spi_id: spihwd
data_rate: 40MHz #oringal device uses 20mhz - 40 is default and works - does not work at 80mhz
#cs_pin: GPIO03 #CS pin is connected to gnd I believe
dc_pin: GPIO02
reset_pin: GPIO04
spi_mode: MODE3 #since no cs pin default is mode0
dimensions:
width: 235
height: 235
offset_height: 0
offset_width: 0
invert_colors: true
#update_interval: never
#auto_clear_enabled: false
lambda: |-
it.rectangle(0, 0, it.get_width(), it.get_height(), id(my_blue));
it.rectangle(0, 20, it.get_width(), it.get_height(), id(my_blue)); // header bar
//it.print(5, 5, id(font_12), id(my_yellow), TextAlign::TOP_LEFT, "ESPHome");
it.strftime(5, 5, id(font_12), id(my_yellow), TextAlign::TOP_LEFT, "%H:%M:%S", id(time_comp).now());
it.print((it.get_width() / 2), (240 / 5.5) * 1 - 8, id(font_20), id(my_yellow), TextAlign::CENTER, "Voltage");
it.printf((it.get_width() / 2), (240 / 4) * 1 + 9, id(font_36), id(my_yellow), TextAlign::CENTER, "%.1fVac",id(voltage).state);
it.print((it.get_width() / 2), (240 / 4.5) * 2 - 8, id(font_20), id(my_green), TextAlign::CENTER, "Grid Power");
it.printf((it.get_width() / 2), (240 / 4) * 2 + 9, id(font_36), id(my_green), TextAlign::CENTER, "%.1fW",id(power).state);
it.print((it.get_width() / 2), (240 / 4.2) * 3 - 8, id(font_20), id(my_orange), TextAlign::CENTER, "Solar Power");
it.printf((it.get_width() / 2), (240 / 4) * 3 + 9, id(font_36), id(my_orange), TextAlign::CENTER, "%.1fW",id(solarpower).state);
time:
- platform: sntp
id: time_comp
That worked!!! It is giving me errors when it says mine??? im just kidding. Thanks again @Dingo
I was able to get everything working on a PRO variant (ESP32E) using LVGL and no external ESPHome components. Iâm using ESPHome 2025.3.2.
The full 240x240 resolution is also working.
This example boots up with the ESPHome logo and a spinner (taken from the ESPHome LVGL documentation) and then shows a clock with date and time (taken from ESPHome documentation).
Seems to work very well! Thanks for everyoneâs help.
esphome:
name: esphome-web-8af3ac
friendly_name: SmallTV Pro
min_version: 2024.11.0
name_add_mac_suffix: false
on_boot:
- delay: 5s
- lvgl.widget.hide: boot_screen
esp32:
board: esp32dev
framework:
type: arduino
# Enable logging
logger:
baud_rate: 0
# Enable Home Assistant API
api:
ota:
- platform: esphome
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Define a PWM output on the ESP32
output:
- platform: ledc
pin: GPIO25
inverted: True
id: backlight_pwm
# Define a monochromatic, dimmable light for the backlight
light:
- platform: monochromatic
output: backlight_pwm
name: "Display Backlight"
id: back_light
restore_mode: ALWAYS_ON
esp32_touch:
# setup_mode: true
binary_sensor:
- platform: esp32_touch
name: "Touch Button"
pin: GPIO32
threshold: 1250
spi:
clk_pin: GPIO18
mosi_pin: GPIO23
interface: hardware
id: spihwd
display:
- platform: ili9xxx
id: lcd_display
model: st7789v
spi_id: spihwd
data_rate: 40MHz
dc_pin: GPIO02
reset_pin: GPIO04
spi_mode: MODE3
dimensions:
width: 240
height: 240
offset_height: 0
offset_width: 0
invert_colors: true
auto_clear_enabled: false
update_interval: never
time:
- platform: sntp
id: time_comp
on_time_sync:
- script.execute: time_update
on_time:
- minutes: '*'
seconds: 0
then:
- script.execute: time_update
image:
- file: https://esphome.io/_static/favicon-512x512.png
id: boot_logo
resize: 200x200
type: RGB565
transparency: alpha_channel
lvgl:
buffer_size: 25%
top_layer:
widgets:
- label:
text: "\uF1EB"
id: lbl_hastatus
hidden: true
align: top_right
x: -2
y: 7
text_align: right
text_color: 0xFFFFFF
- obj:
id: boot_screen
x: 0
y: 0
width: 100%
height: 100%
bg_color: 0xffffff
bg_opa: COVER
radius: 0
pad_all: 0
border_width: 0
widgets:
- image:
align: CENTER
src: boot_logo
y: -40
- spinner:
align: CENTER
y: 75
height: 50
width: 50
spin_time: 1s
arc_length: 60deg
arc_width: 8
indicator:
arc_color: 0x18bcf2
arc_width: 8
on_press:
- lvgl.widget.hide: boot_screen
pages:
- id: clock_page
widgets:
- obj: # clock container
height: SIZE_CONTENT
width: 240
align: CENTER
pad_all: 0
border_width: 0
bg_color: 0xFFFFFF
widgets:
- meter: # clock face
height: 220
width: 220
align: CENTER
bg_opa: TRANSP
border_width: 0
text_color: 0x000000
scales:
- range_from: 0 # minutes scale
range_to: 60
angle_range: 360
rotation: 270
ticks:
width: 1
count: 61
length: 10
color: 0x000000
indicators:
- line:
id: minute_hand
width: 3
color: 0xa6a6a6
r_mod: -4
value: 0
- range_from: 1 # hours scale for labels
range_to: 12
angle_range: 330
rotation: 300
ticks:
width: 1
count: 12
length: 1
major:
stride: 1
width: 4
length: 10
color: 0xC0C0C0
label_gap: 12
- range_from: 0 # hi-res hours scale for hand
range_to: 720
angle_range: 360
rotation: 270
ticks:
count: 0
indicators:
- line:
id: hour_hand
width: 5
color: 0xa6a6a6
r_mod: -30
value: 0
- label:
align: CENTER
id: day_label
y: -30
- label:
align: CENTER
id: date_label
y: 30
script:
- id: time_update
then:
- lvgl.indicator.update:
id: minute_hand
value: !lambda |-
return id(time_comp).now().minute;
- lvgl.indicator.update:
id: hour_hand
value: !lambda |-
auto now = id(time_comp).now();
return std::fmod(now.hour, 12) * 60 + now.minute;
- lvgl.label.update:
id: date_label
text: !lambda |-
static const char * const mon_names[] = {"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
static char date_buf[8];
auto now = id(time_comp).now();
snprintf(date_buf, sizeof(date_buf), "%s %2d", mon_names[now.month-1], now.day_of_month);
return date_buf;
- lvgl.label.update:
id: day_label
text: !lambda |-
static const char * const day_names[] = {"SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"};
return day_names[id(time_comp).now().day_of_week - 1];
Thanks, this is awesome.
FYI on esphome version 2024.9.2 240x240 res. works just fine. Looks like problem lies in underlying libraries.
So I got a SmallTV-pro (ESP32), tried a few things, and most were quite hard for a beginner.
My findings so far:
- Using lambda to render the display means that the dimensions need to have a value of 235. But there is a bright noisy stripe in the remaining are. Using a higher value makes the display crash. (Which can be annoying because it just freezes after an update. Only after a power cycle itâs going to be all noisy and therefore obviously faulty.)
This works:
display:
- platform: ili9xxx
id: lcd_display
model: st7789v
spi_id: spihwd
data_rate: 40MHz
dc_pin: GPIO02
reset_pin: GPIO04
spi_mode: MODE3
dimensions:
width: 235
height: 235
offset_height: 0
offset_width: 0
invert_colors: true
#update_interval: never
#auto_clear_enabled: false
- LVGL can render the full resolution.
Working code:
display:
- platform: ili9xxx
id: lcd_display
model: st7789v
spi_id: spihwd
data_rate: 40MHz
dc_pin: GPIO02
reset_pin: GPIO04
spi_mode: MODE3
dimensions:
width: 240
height: 240
offset_height: 0
offset_width: 0
invert_colors: true
auto_clear_enabled: false
update_interval: never
- Neither (free) ChatGPT nor (free) Copilot produce working code. ChatGPT is a better though.
- Even ChatGPT is mostly useless when Home Assistant itself is concerned. It often relies on outdated mechanisms and wonât stop even if told so.
But Iâve managed to display the departure time of the next upcoming train for my commute. The goal is to have a full schedule for five or so connections.
I am a totally noob on esphome - has anybody of you a bin file for me, to update it via the build in webui of the geekmagic pro (esp32) variant, please? so I can add this device to my home asssitant instance via esphome
I would like to display information from the home assistant to this geekmagic pro clock
lovely, thanks for this fine example.
Tried first with the stv-ultra and texts, which was annoying due to lack of memory when changing things. When flashing again, had to go back first to the minimal firmware always.
Your lvgl approach looks much more promising
You need to install it as a new device in the ESPHome Device Builder (install the add-on in your Home Assistant). The platform is ESP32.
After it is created you choose manual download and the legacy method.
The file you receive (*.bin) can be inserted in the update section of the SmallTV configuration website.
Looks great! Glad it worked for you. Iâve added a couple more sensor screens and now use the touch button to change between pages. Seems to work very well.
Cool, could you share that button part?
I played around a bit for my needs - I added my PV + EV sensors, now trying to use some emojis which needs some fonts to be embedded first and maybe some colors.
esphome:
name: esphome-web-8af3ac
friendly_name: SmallTV Pro
min_version: 2024.11.0
name_add_mac_suffix: false
esp32:
board: esp32dev
framework:
type: arduino
# Enable logging
logger:
baud_rate: 0
# enable web server
web_server:
version: 3
# Enable Home Assistant API
api:
ota:
- platform: esphome
wifi:
ssid: !secret wifi-ssid
password: !secret wifi-password
# Define a PWM output on the ESP32
output:
- platform: ledc
pin: GPIO25
inverted: True
id: backlight_pwm
# Define a monochromatic, dimmable light for the backlight
light:
- platform: monochromatic
output: backlight_pwm
name: "Display Backlight"
id: back_light
restore_mode: ALWAYS_ON
esp32_touch:
# setup_mode: true
binary_sensor:
- platform: esp32_touch
name: "Touch Button"
pin: GPIO32
threshold: 1250
spi:
clk_pin: GPIO18
mosi_pin: GPIO23
interface: hardware
id: spihwd
display:
- platform: ili9xxx
id: lcd_display
model: st7789v
spi_id: spihwd
data_rate: 40MHz
dc_pin: GPIO02
reset_pin: GPIO04
spi_mode: MODE3
dimensions:
width: 240
height: 240
offset_height: 0
offset_width: 0
invert_colors: true
auto_clear_enabled: false
update_interval: never
lvgl:
buffer_size: 25%
widgets:
# DC
- label:
id: power_label
text: "Power: 0.00 Watt"
x: 20 # Adjust position
y: 20
width: 200
text_align: CENTER
# Forecast
- label:
id: forecast_label
text: "Forecast Today: 0.00 kW"
x: 20 # Adjust position
y: 40
width: 200
text_align: CENTER
# Home Battery
- label:
id: battery_label
text: "Home Battery: 0%"
x: 20
y: 80 # Position below power display
width: 200
text_align: CENTER
- bar:
id: battery_bar
x: 20
y: 100
width: 200
height: 20
min_value: 0
max_value: 100
value: 0
# Car 1 Battery (id_4_state_of_charge)
- label:
id: car1_label
text: "Car 1: 0%"
x: 10
y: 140
width: 100
text_align: RIGHT
- label:
id: car1_rangelabel
text: "Car 1:0km"
x: 100
y: 140
width: 100
text_align: RIGHT
- bar:
id: car1_bar
x: 10
y: 160
width: 200
height: 15
min_value: 0
max_value: 100
# Car 2 Battery (smart_batterie)
- label:
id: car2_label
text: "Car 2: 0%"
x: 10
y: 180
width: 100
text_align: RIGHT
- label:
id: car2_rangelabel
text: "Car 2: 0km"
x: 100
y: 180
width: 100
text_align: RIGHT
- bar:
id: car2_bar
x: 10
y: 200
width: 200
height: 15
min_value: 0
max_value: 100
sensor:
# DC Power
- platform: homeassistant # or your actual sensor platform
id: total_dc_power
unit_of_measurement: "Watt"
entity_id: sensor.total_dc_power # Replace with your HA entity
on_value:
- lvgl.label.update:
id: power_label
text: !lambda |-
return ("Sun Power: " + to_string(static_cast<int>(x)) + " Watt").c_str();
# Forecast
- platform: homeassistant # or your actual sensor platform
id: forecast_remaining
entity_id: sensor.solcast_pv_forecast_prognose_verbleibende_leistung_heute # Replace with your HA entity
on_value:
- lvgl.label.update:
id: forecast_label
text: !lambda |-
return ("Solcast remaining: " + to_string(static_cast<int>(x)) + " kWh").c_str();
# Home Battery
- platform: homeassistant
id: evcc_battery_soc
entity_id: sensor.evcc_battery_soc # Replace with actual HA entity
unit_of_measurement: "%"
on_value:
- lvgl.label.update:
id: battery_label
text: !lambda |-
return ("Home Battery: " + to_string(static_cast<int>(x)) + "%").c_str();
- lvgl.bar.update:
id: battery_bar
value: !lambda |-
return x;
# Car 1 Battery
- platform: homeassistant
id: car1_soc
entity_id: sensor.id_4_state_of_charge # Replace with actual entity
unit_of_measurement: "%"
on_value:
- lvgl.label.update:
id: car1_label
text: !lambda |-
return ("ID4: " + to_string(static_cast<int>(x)) + "%").c_str();
- lvgl.bar.update:
id: car1_bar
value: !lambda |-
return x;
# Car 1 Range
- platform: homeassistant
id: car1_range
entity_id: sensor.id_4_range # Replace with actual entity
unit_of_measurement: "km"
on_value:
- lvgl.label.update:
id: car1_rangelabel
text: !lambda |-
return (to_string(static_cast<int>(x)) + "km").c_str();
# Car 2 Battery
- platform: homeassistant
id: car2_soc
entity_id: sensor.smart_batterie # Replace with actual entity
unit_of_measurement: "%"
on_value:
- lvgl.label.update:
id: car2_label
text: !lambda |-
return ("Smart #1: " + to_string(static_cast<int>(x)) + "%").c_str();
- lvgl.bar.update:
id: car2_bar
value: !lambda |-
return x;
# Car 2 Range
- platform: homeassistant
id: car2_range
entity_id: sensor.smart_reichweite # Replace with actual entity
unit_of_measurement: "km"
on_value:
- lvgl.label.update:
id: car2_rangelabel
text: !lambda |-
return ( to_string(static_cast<int>(x)) + "km").c_str();
a online lvgl editor would come in handy, looking for one
Looks really good! EVâs and solar?? Jealous. We have EVâs just no solar (yet)âŚ
The touch button control was done by tieing a binary_sensor to the esp32_touch platform and using an on_press event.
This block added to my original post will get it working.
This will rotate forward through all pages and wrap around automatically to the first one. I am likely going to add a press-and-hold to go backwards.
binary_sensor:
- platform: esp32_touch
name: "Touch Button"
pin: GPIO32
threshold: 1250
on_press:
then:
- lvgl.page.next:
animation: FADE_IN
time: 300ms
I think there is a difference in the ESP module. Wheni tried to get your code working for the display, it didnt show errors but just showed a screen of white noise.
Thx AoSpades - you pointed me to the right direction I have flashed the device and added it to ha successfully
now starts the hard stuff, right? how to customize the screen I would like to show PV information - is it possible to show mqtt device information?
Are you able to share a photo of the module side of your board? There appear to be some modified and/or clones of the original geekmagic devices that might be different enough to not work with this config.