Has anyone managed to get one of these working with ESPHome? I bought one but I am struggling to get it to work. I can load the code but unable to get the display to work.
Your display GC9A01 and touch CST816D are both supported, so should be doable.
Also, have a look here:
If someone has gotten this to work please post your code. I can get it to compile and upload but it would never fully boot if I remember correctly.
Hey, I got it to work finally. See the code below. still needs a bit of work but right now this is a basic clock that is displaying the correct time pulled from HA.
esphome:
name: elecrowrotary128-inch
platformio_options:
build_flags: "-DBOARD_HAS_PSRAM"
board_build.esp-idf.memory_type: qio_opi
board_build.flash_mode: dio
friendly_name: Rotary1.28-inch
on_boot:
priority: 800
then:
- logger.log: "Backlight ON"
- output.turn_on: gpio_3_backlight_pwm
- delay: 200ms
- output.turn_off: power_light
- output.turn_on: out1
- output.turn_on: out2
esp32:
board: esp32-s3-devkitc-1
framework:
type: esp-idf
version: recommended
# Enable logging
logger:
level: VERY_VERBOSE
# Enable Home Assistant API
api:
encryption:
key: !secret encryption_key
ota:
- platform: esphome
password: !secret ota_key
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "${friendly_name} Hotspot"
password: "6T3RFWEF71"
psram:
mode: octal
speed: 80MHz
time:
- platform: homeassistant
timezone: "Australia/Melbourne"
id: esptime
on_time_sync:
- script.execute: time_update
on_time:
- minutes: '*'
seconds: 0
then:
- script.execute: time_update
output:
- platform: ledc
pin: GPIO46
id: gpio_3_backlight_pwm
- platform: gpio
id: power_light
pin: GPIO40
# inverted: true
- platform: gpio
id: out4
pin: GPIO4
- platform: gpio
id: out12
pin: GPIO12
- platform: gpio
id: out1
pin: GPIO1
- platform: gpio
id: out2
pin: GPIO2
light:
- platform: monochromatic
name: "Backlight"
output: gpio_3_backlight_pwm
id: back_light
restore_mode: ALWAYS_ON
sensor:
- platform: rotary_encoder
id: knob
name: "Encoder"
pin_a:
number: 45
mode:
input: true
pullup: true
pin_b:
number: 42
mode:
input: true
pullup: true
resolution: 1
min_value: -100000
max_value: 100000
binary_sensor:
- platform: touchscreen
id: change_page # Name is not needed, ID is sufficient
# This zone now covers the entire 240x240 screen
x_min: 0
y_min: 0
x_max: 240
y_max: 240
on_press:
- script.execute: screentime
- platform: gpio
pin: 41
id: rotary_button
script:
- id: screentime
mode: restart
then:
- light.turn_on: back_light
- delay: 1 min
- light.turn_off: back_light
- id: dim_screen
then:
- light.turn_on:
id: back_light
brightness: 30%
- logger.log: "script: dim to 30%"
- id: bright_screen
then:
- light.turn_on:
id: back_light
brightness: 100%
- logger.log: "script: brightness to full"
- id: time_update
then:
- lvgl.indicator.update:
id: minute_hand
value: !lambda |-
return id(esptime).now().minute;
- lvgl.indicator.update:
id: hour_hand
value: !lambda |-
auto now = id(esptime).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(esptime).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(esptime).now().day_of_week - 1];
i2c:
- id: i2c_touch
setup_priority: 400
sda: 6
scl: 7
scan: true
frequency: 400kHz
touchscreen:
platform: cst816
id: touch
address: 0x15
interrupt_pin: 5
reset_pin: 13
i2c_id: i2c_touch
transform:
mirror_x: false
mirror_y: true
swap_xy: true
spi:
id: spi_bus
mosi_pin: 11
clk_pin: 10
font:
- file: "gfonts://Roboto"
id: roboto16
size: 16
display:
- platform: ili9xxx
id: round_display
model: GC9A01A
cs_pin: GPIO9
dc_pin: GPIO3
reset_pin: GPIO14
invert_colors: true
show_test_card: true
rotation: 0
#external_components:
# - source:
# type: local
# path: components
# components: [gc9a01a_display]
lvgl:
displays:
- round_display
default_font: roboto16
disp_bg_color: black
touchscreens:
touchscreen_id: touch
style_definitions:
- id: date_style
text_font: unscii_8
align: center
text_color: 0x000000
bg_opa: cover
radius: 4
pad_all: 2
pages:
- id: clock_page
widgets:
- obj: # clock container
height: 240
width: 240
align: CENTER
pad_all: 0
border_width: 0
bg_color: 0x000000 # black
widgets:
- meter: # clock face
height: 240
width: 240
align: CENTER
bg_opa: TRANSP
border_width: 0
text_color: 0xFFFFFF # white
scales:
- range_from: 0 # minutes scale
range_to: 60
angle_range: 360
rotation: 270
ticks:
width: 1
count: 61
length: 10
color: 0xFFFFFF # white
indicators:
- line:
id: minute_hand
width: 3
color: 0xFF0000 # Red
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 # silver
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: 0xFF0000 # Red
r_mod: -30
value: 0
- label:
styles: date_style
id: day_label
y: -30
- label:
id: date_label
styles: date_style
y: 30
captive_portal:
Iβll post back here as I get more of the functions to work.
Note for me the thing that got it working was holding down the boot button on the back while powering on. Before that I was having issues with boot loops.
Where you able to upload using web.esphome.io interface? There instruction show using Arduino and Iβve not been able to connect using the ESP home web tool.
Hi, curious if you got any further. Thinking about getting one of these as welβ¦
Hi,
there are some esphome example configs in the official elecrow GitHub repo:
I played a while with the device. I think I got everything working.
- Display (SPI / ili9xxx / GC9A01A)
- Touchscreen (I2C / cst816)
- Touchscreen Backlight
- Rotary Encoder
- Button Press
- Ambient Light LEDs / Status Indicator LEDs
- Power Indicator LED
- I2C Port
- UART Port
Works fine with ESPHome + Home Assistant
Wow thats a good list of functions, do you mind sharing your config for all of us?
looks like you managed to get a lot further along than I did.
Sure. Here are the relevant parts:
esphome:
name: knob
friendly_name: Knob
platformio_options:
build_flags: '-DBOARD_HAS_PSRAM'
board_build.esp-idf.memory_type: qio_opi
board_build.flash_mode: dio
on_boot:
then:
- output.turn_off: gpio40_power_indicator_led
- output.turn_on: gpio3_backlight_pwm
- output.turn_on: gpio1_screen
- light.turn_on:
id: back_light
brightness: 1
esp32:
board: esp32-s3-devkitc-1
framework:
type: esp-idf
psram:
mode: octal
speed: 80MHz
psram:
mode: octal
speed: 80MHz
logger:
level: DEBUG
#baud_rate: 0
api:
ota:
- platform: esphome
wifi:
ssid:
password:
spi:
mosi_pin: GPIO11
clk_pin: GPIO10
interface: hardware
i2c:
- id: i2c_touchscreen
sda: GPIO6
scl: GPIO7
scan: false
- id: i2c_sensor
sda: GPIO38
scl: GPIO39
scan: false
output:
- platform: ledc
pin: GPIO46
id: gpio3_backlight_pwm
- platform: gpio
inverted: true
id: gpio40_power_indicator_led
pin: GPIO40
- platform: gpio
id: gpio1_screen
pin: GPIO1
light:
- platform: monochromatic
name: Backlight
id: back_light
output:
restore_mode: ALWAYS_ON
- platform: esp32_rmt_led_strip
name: Status Indicator LED
id: status_indicator_led
rgb_order: GRB
pin: GPIO48
num_leds: 5
chipset: ws2811
binary_sensor:
- platform: gpio
name: Button Press
id: btn_01
pin:
number: GPIO41
inverted: true
mode:
input: true
pullup: true
filters:
- delayed_on: 15ms
- delayed_off: 15ms
sensor:
- platform: rotary_encoder
id: knob
name: 'Rotary Encoder'
pin_a:
number: GPIO45
mode:
input: true
pullup: true
pin_b:
number: GPIO42
mode:
input: true
pullup: true
resolution: 1
filters:
- debounce: 20ms
touchscreen:
id: touchscreen_id
platform: cst816
i2c_id: i2c_touchscreen
address: 21
interrupt_pin: GPIO5
reset_pin: GPIO13
skip_probe: true
display:
id: display_id
platform: mipi_spi
model: GC9A01A
cs_pin: GPIO9
dc_pin: GPIO3
reset_pin: GPIO14
data_rate: 80MHz
invert_colors: true
show_test_card: false
rotation: 0
update_interval: never
auto_clear_enabled: false
lvgl:
displays:
- display_id
touchscreens:
- touchscreen_id
encoders:
sensor: knob
enter_button: btn_01
Any suggestions on how to mount this thing to a wall? There isnβt any mounting hardware. I donβt have a 3-D printer to create something either. I kind of wanted to use this as a display for when our front door is open notifying people to close it (as well as a few other things.)
In my model, you can remove the backplate (or use longer screws?) to mount it onto something
Ive got mine working as well now with my nest.
substitutions:
# ββ Update these to match your setup ββββββββββββββββββββββββββββββββββββββ
climate_entity: climate.nest # Your HA climate entity
device_name: knob
friendly_name: Knob
esphome:
name: ${device_name}
friendly_name: ${friendly_name}
platformio_options:
build_flags: β-DBOARD_HAS_PSRAMβ
board_build.esp-idf.memory_type: qio_opi
board_build.flash_mode: dio
on_boot:
then:
- output.turn_off: gpio40_power_indicator_led
- output.turn_on: gpio3_backlight_pwm
- output.turn_on: gpio1_screen
- light.turn_on:
id: back_light
brightness: 1
esp32:
board: esp32-s3-devkitc-1
framework:
type: esp-idf
psram:
mode: octal
speed: 80MHz
logger:
level: DEBUG
api:
ota:
- platform: esphome
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
ap:
ssid: β${friendly_name} Fallbackβ
password: !secret ap_password
captive_portal:
spi:
mosi_pin: GPIO11
clk_pin: GPIO10
interface: hardware
i2c:
-
id: i2c_touchscreen
sda: GPIO6
scl: GPIO7
scan: false -
id: i2c_sensor
sda: GPIO38
scl: GPIO39
scan: false
ββ Fonts ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
font:
-
file: βgfonts://Robotoβ
id: font_huge
size: 80
bpp: 4
glyphs: "0123456789.-Β° " -
file: βgfonts://Robotoβ
id: font_large
size: 48
bpp: 4
glyphs: "0123456789.-Β°% " -
file: βgfonts://Robotoβ
id: font_medium
size: 20
bpp: 4
glyphs: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.-Β°%β " -
file: βgfonts://Robotoβ
id: font_small
size: 20
bpp: 4
glyphs: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.-Β°% "
globals: -
id: encoder_ready
type: bool
restore_value: no
initial_value: βtrueβ -
id: heating_on
type: bool
restore_value: no
initial_value: βfalseβ -
id: target_temp
type: float
restore_value: no
initial_value: β20.0β -
id: pending_temp_send
type: bool
restore_value: no
initial_value: βfalseβ -
id: display_dimmed
type: bool
restore_value: no
initial_value: βfalseβ
ββ Dim Screen Script ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
script:
- id: dim_timer
mode: restart
then:- delay: 15s
- light.turn_on:
id: back_light
brightness: 5% - lambda: βid(display_dimmed) = true;β
output:
-
platform: ledc
pin: GPIO46
id: gpio3_backlight_pwm -
platform: gpio
inverted: true
id: gpio40_power_indicator_led
pin: GPIO40 -
platform: gpio
id: gpio1_screen
pin: GPIO1
light:
-
platform: monochromatic
name: Backlight
id: back_light
output: gpio3_backlight_pwm
restore_mode: ALWAYS_ON -
platform: esp32_rmt_led_strip
name: Status Indicator LED
id: status_indicator_led
rgb_order: GRB
pin: GPIO48
num_leds: 5
chipset: ws2811
binary_sensor:
- platform: gpio
name: Button Press
id: btn_01
pin:
number: GPIO41
inverted: true
mode:
input: true
pullup: true
filters:- delayed_on: 15ms
- delayed_off: 15ms
ββ dimming of screen restore on touch (not click!!)ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
on_press:
then:
- if:
condition:
lambda: 'return id(display_dimmed);'
then:
- light.turn_on:
id: back_light
brightness: 100%
- lambda: 'id(display_dimmed) = false;'
- script.execute: dim_timer
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
else:
- lambda: |-
id(heating_on) = !id(heating_on);
- if:
condition:
lambda: 'return id(heating_on);'
then:
- homeassistant.service:
service: climate.set_hvac_mode
data:
entity_id: ${climate_entity}
hvac_mode: "heat"
- lvgl.label.update:
id: lv_heat_label
text: "ON"
text_align: CENTER
- lvgl.widget.update:
id: lv_button_2
bg_color: 0xEF4444
- lvgl.arc.update:
id: lv_arc_1
value: !lambda 'return (int) id(target_temp);'
- lvgl.widget.update:
id: lv_arc_1
state:
disabled: false
else:
- homeassistant.service:
service: climate.set_hvac_mode
data:
entity_id: ${climate_entity}
hvac_mode: "off"
- lvgl.label.update:
id: lv_heat_label
text: "OFF"
text_align: CENTER
- lvgl.widget.update:
id: lv_button_2
bg_color: 0x4F46E5
- lvgl.arc.update:
id: lv_arc_1
value: 0
- lvgl.widget.update:
id: lv_arc_1
state:
disabled: true
sensor:
-
platform: rotary_encoder
id: knob
name: βRotary Encoderβ
pin_a:
number: GPIO45
mode:
input: true
pullup: true
pin_b:
number: GPIO42
mode:
input: true
pullup: true
resolution: 1
filters:- debounce: 20ms
on_clockwise:
then:- lambda: |-
float new_temp = id(target_temp) + 0.5f;
if (new_temp > 30.0f) new_temp = 30.0f;
id(target_temp) = new_temp;
id(pending_temp_send) = true; - lvgl.arc.update:
id: lv_arc_1
value: !lambda βreturn (int) id(target_temp);β
indicator:
arc_color: !lambda |-
float t = (id(target_temp) - 15.0f) / 15.0f;
if (t < 0.0f) t = 0.0f;
if (t > 1.0f) t = 1.0f;
int r = (int)(0x3B + t * (0xEF - 0x3B));
int g = (int)(0x82 + t * (0x44 - 0x82));
int b = (int)(0xF6 + t * (0x44 - 0xF6));
return lv_color_make(r, g, b);
on_anticlockwise:
then: - lambda: |-
float new_temp = id(target_temp) - 0.5f;
if (new_temp < 15.0f) new_temp = 15.0f;
id(target_temp) = new_temp;
id(pending_temp_send) = true; - lvgl.arc.update:
id: lv_arc_1
value: !lambda βreturn (int) id(target_temp);β
indicator:
arc_color: !lambda |-
float t = (id(target_temp) - 15.0f) / 15.0f;
if (t < 0.0f) t = 0.0f;
if (t > 1.0f) t = 1.0f;
int r = (int)(0x3B + t * (0xEF - 0x3B));
int g = (int)(0x82 + t * (0x44 - 0x82));
int b = (int)(0xF6 + t * (0x44 - 0xF6));
return lv_color_make(r, g, b);
- lambda: |-
Current room temperature
- debounce: 20ms
-
platform: homeassistant
id: current_temperature
entity_id: ${climate_entity}
attribute: current_temperature
internal: true
on_value:
then:
- lvgl.label.update:
id: lbl_current_temp
text: !lambda |-
char buf[8];
snprintf(buf, sizeof(buf), β%.1fΒ°Cβ, x);
return std::string(buf); -
platform: homeassistant
id: nest_temperature
entity_id: ${climate_entity}
attribute: temperature
on_value:
then:
- lambda: |-
id(target_temp) = x;
- lvgl.arc.update:
id: lv_arc_1
value: !lambda βreturn (int) id(target_temp);β
indicator:
arc_color: !lambda |-
float t = (id(target_temp) - 15.0f) / 15.0f;
if (t < 0.0f) t = 0.0f;
if (t > 1.0f) t = 1.0f;
int r = (int)(0x3B + t * (0xEF - 0x3B));
int g = (int)(0x82 + t * (0x44 - 0x82));
int b = (int)(0xF6 + t * (0x44 - 0xF6));
return lv_color_make(r, g, b);
text_sensor:
- platform: homeassistant
id: nest_hvac_mode
entity_id: ${climate_entity}
on_value:
then:
- lambda: |-
id(heating_on) = (x == βheatβ);
- if:
condition:
lambda: βreturn id(heating_on);β
then:
- lvgl.label.update:
id: lv_heat_label
text: βONβ
- lvgl.widget.update:
id: lv_button_2
bg_color: 0xEF4444
- lvgl.widget.update:
id: lv_arc_1
state:
disabled: false
- lvgl.arc.update:
id: lv_arc_1
value: !lambda βreturn (int) id(target_temp);β
else:
- lvgl.label.update:
id: lv_heat_label
text: βOFFβ
- lvgl.widget.update:
id: lv_button_2
bg_color: 0x4F46E5
- lvgl.widget.update:
id: lv_arc_1
state:
disabled: true
- lvgl.arc.update:
id: lv_arc_1
value: 0
interval:
- interval: 1500ms
then:- if:
condition:
lambda: βreturn id(pending_temp_send);β
then:
- lambda: |-
id(pending_temp_send) = false;
ESP_LOGI(βknobβ, βSending debounced temp: %.1fβ, id(target_temp));
- homeassistant.service:
service: climate.set_temperature
data:
entity_id: ${climate_entity}
temperature: !lambda βreturn id(target_temp);β
- if:
touchscreen:
id: touchscreen_id
platform: cst816
i2c_id: i2c_touchscreen
address: 21
interrupt_pin: GPIO5
reset_pin: GPIO13
skip_probe: true
on_touch:
then:
- if:
condition:
lambda: βreturn id(display_dimmed);β
then:
- light.turn_on:
id: back_light
brightness: 100%
- lambda: βid(display_dimmed) = false;β
- script.execute: dim_timer
else:
- script.execute: dim_timer
display:
id: display_id
platform: mipi_spi
model: GC9A01A
cs_pin: GPIO9
dc_pin: GPIO3
reset_pin: GPIO14
data_rate: 80MHz
invert_colors: true
show_test_card: false
rotation: 0
update_interval: never
auto_clear_enabled: false
lvgl:
pages:
- id: canvas_1
bg_color: 0x111827
pad_all: 0
widgets:
- arc:
id: lv_arc_1
x: 0
y: 0
width: 230
height: 230
value: 20
min_value: 15
max_value: 30
adjustable: true
start_angle: 135
end_angle: 45
arc_color: 0x404040
arc_width: 15
arc_opa: 100%
arc_rounded: false
indicator:
arc_color: 0x818CF8
arc_width: 15
arc_opa: 100%
arc_rounded: false
knob:
bg_color: 0xFFFFFF
radius: 9999
border_width: 2
border_color: 0x818CF8
bg_opa: 0%
- button:
id: lv_button_2
x: 25
y: 25
width: 180
height: 180
text_align: CENTER
bg_color: 0x4F46E5
checkable: false
radius: 65535
widgets:
- label:
id: lv_heat_label
text: "OFF"
text_color: 0xFFFFFF
text_font: font_medium
align: CENTER
x: 0
y: 0
- label:
id: lv_label_3
x: 70
y: 40
width: 100
height: 30
text: "HEATING"
text_font: font_medium
text_color: 0xffffff
text_align: CENTER
pad_top: 6
- label:
id: lbl_current_temp
x: 0
y: 65
text_font: font_medium
text_color: 0xFFFFFF
text: "20Β°C"
align: CENTER
Thank you!!! I also got everything to work EXCEPT the display. Tried so many different variants and tested sooo many Gemini suggestions. Then I found this and copy/pasted your display related sections and BOOM! You rock - thanks for posting!