Lesson04_CrowPanel_Touch_LVGL: Knob-Controlled LVGL Brightness Meter Interface¶
1. Course Introduction¶
This lesson extends the circular display and knob dimming covered in the previous two lessons into a complete LVGL brightness meter interface. ESPHome scales bj_light_21_1.png to 480 x 480 and converts it into an RGB565 background image; LVGL then draws the title, a 0%-100% arc, and the brightness percentage on top of that background. Each knob step adjusts the value by 5%, with the GPIO6 PWM backlight, arc position, and text changing in sync.
Through this lesson, learners will validate the complete chain of panel power, ST7701S RGB display, PSRAM image resources, LVGL widgets, knob input, and PWM backlight. Because this lesson's code does not configure a touch component, lesson acceptance is based on knob dimming and interface synchronization.
2. Learning Objectives¶
- Be able to place
bj_light_21_1.pngin a location parseable by ESPHome and complete the image conversion. - Be able to explain the LVGL stacking relationship among the background image, arc, knob, and percentage label.
- Be able to use the knob to synchronously control the PWM, arc, and brightness text.
- Be able to troubleshoot missing resources, encoder anomalies, or PWM desynchronization issues based on the interface, logs, and backlight changes.
3. What You Need to Prepare¶
- CrowPanel 2.1inch-HMI ESP32 Rotary Display with Lesson01 and Lesson02 already completed.
- A USB data cable that supports data transfer.
- ESPHome Device Builder 1.9.2.
- ESPHome 2026.7.4.
- Lesson materials
bj_light_21_1.png / bj_light_21_2.png. - Network connection required to compile Google Fonts and download the materials.
Code download link: Elecrow Official Lesson_Code
Material download link:
Adding Materials Guide:¶
Next, we will show you how to upload the materials you want so that they can be used on the ESPHome platform.
First, download the Samba Share tool. You need to use this tool so that we can conveniently upload the image materials we want to use.
First, install Samba.
After the download completes, on this tool's page, configure your account. Here, configure the account name and password used by your Home Assistant.
After the configuration is complete, remember to click Save in the bottom-right corner.
Then you can open a file-viewing interface in your computer's file system and enter \ + your Home Assistant IP address.
After entering, you will arrive at your current ESPHome file management interface.
First enter the config folder, then enter the esphome folder.
You can place the materials you need to use here. In this way, the material names referenced in your code must also match the names of the materials you placed. (same operation)
This way, when your code is compiled, it will be able to find the materials you placed and display them on the screen.
4. Software Operation Steps¶
Open ESPHome Device Builder 1.9.2 and confirm that its ESPHome Core version displays as 2026.7.4. If the versions are inconsistent, complete the upgrade or switch environments first to avoid component syntax differences. 
Create a new project, place 21-lvgl-interface.yaml into the ESPHome configuration directory, and open the corresponding configuration in the device list. Note, however, that device names on the same network must not be duplicated.
A. Click Create device to create a new project.
B. Select the esp32s3 main controller.
C. Name the project. Complete the new project task.
Copy the official code into the project (the code is provided above).
However, ensure that the project name in the code matches the name of the project you just created.
Modify the WiFi.
Click the three dots in the top-right corner, then click secret.
You can enter your own WiFi name and password. (Ensure that this WiFi is on the same local network as your Home Assistant system)
Click Install, select the USB installation method suitable for the current environment, choose the serial port corresponding to the CrowPanel 2.1inch-HMI ESP32 Rotary Display, and complete compilation and flashing. After flashing finishes, open the log window and confirm that the PCF8574, ST7701S display, image resource, Wi-Fi connection, and encoder initialize without repeated resets.
Wait for compilation.
After compilation completes, click flash to upload.
Select the connected serial port.
Click to connect to the corresponding serial port (confirm the hardware is already connected).
Wait for the download to complete.
5. Hardware Operation Steps¶
With the device powered off, check that the screen, knob housing, and USB interface show no obvious damage, then use a USB cable that supports data transfer to connect the CrowPanel 2.1inch-HMI ESP32 Rotary Display to the computer.
Wait for the LVGL page to be built and look straight at the center of the circular screen. The page should display the background image, the Brightness title, the brightness arc, and 50%. Rotate the knob clockwise and counterclockwise to confirm that the arc, percentage, and actual backlight change synchronously; the device should not freeze, restart, or stop refreshing for an extended period. This lesson's code does not configure touch functionality, so touch response is not treated as an acceptance item.
6. Key Code Explanation¶
6.1 Boot Initialization and Knob Protection¶
on_boot:
priority: 800
then:
- output.turn_on: lcd_power
- output.turn_on: display_reset
- delay: 100ms
- output.turn_off: display_reset
- delay: 100ms
- delay: 500ms
- light.turn_on:
id: display_backlight
brightness: 0.5
- lambda: |-
id(encoder_ready) = false;
id(brightness_value) = 50;
id(knob).publish_state(0);
- light.turn_on:
id: display_backlight
brightness: 0.5
- lambda: |-
char buf[10];
snprintf(buf, sizeof(buf), "%d%%", id(brightness_value));
lv_label_set_text(id(lbl_brightness), buf);
- delay: 200ms
- lambda: |-
id(encoder_ready) = true;
The startup sequence powers and resets the panel through the PCF8574, initializes the backlight and state to 50%, resets the encoder baseline, updates the percentage label, and only then enables encoder processing. The arc itself starts at 50 in its widget declaration, so the arc, label, and PWM begin in the same state.
6.2 480 x 480 Image Resource¶
ESPHome reads bj_light_21_1.png at compile time, resizes it to the panel resolution, and converts it to RGB565. The file must be available relative to the YAML configuration. A missing file or mismatched name stops compilation before flashing.
6.3 Display Buffer and Refresh¶
display:
- platform: st7701s
id: my_display
update_interval: 50ms
dimensions:
width: 480
height: 480
pclk_frequency: 18MHz
pclk_inverted: true
lvgl:
displays:
- my_display
buffer_size: 50%
The full display section preserves the 2.1-inch board's SPI control pins, RGB data map, porch timing, and ST7701S initialization sequence. LVGL uses half of a full-frame buffer, which relies on the 8 MB Octal PSRAM. The 50 ms display interval corresponds to a 20 Hz update schedule.
6.4 Background, Title, Arc, and Percentage¶
widgets:
- image:
align: CENTER
id: img_bg
src: img_bg_light
width: 480
height: 480
antialias: true
- label:
align: CENTER
id: lbl_title
y: -50
text_font: montserrat_25
text: "Brightness"
text_color: 0xFFFFFF
- arc:
id: arc_brightness
align: CENTER
width: 360
height: 360
start_angle: 135
end_angle: 45
min_value: 0
max_value: 100
value: 50
arc_color: 0x1A1A1A
arc_width: 12
indicator:
arc_color: 0x00D2FF
arc_width: 12
knob:
bg_color: 0xFFFFFF
width: 15
height: 15
radius: 7
- label:
align: CENTER
id: lbl_brightness
text_font: montserrat_50
text: "50%"
text_color: 0xFFFFFF
Widgets are drawn in definition order. The 480 x 480 background is placed first, then the title, the 360 x 360 arc, and the central percentage. The arc covers 270 degrees from 135 degrees to 45 degrees. arc_brightness and lbl_brightness are referenced by the encoder Lambda, so their IDs form part of the input-to-UI contract.
6.5 Encoder Input and Synchronized Outputs¶
static int acc = 0;
acc += delta;
if (abs(acc) >= 1) {
id(brightness_value) += (acc > 0) ? -5 : 5;
id(brightness_value) = clamp(id(brightness_value), 0, 100);
float level = id(brightness_value) / 100.0f;
id(bl_pwm).set_level(level);
lv_arc_set_value(id(arc_brightness), id(brightness_value));
char buf[10];
snprintf(buf, sizeof(buf), "%d%%", id(brightness_value));
lv_label_set_text(id(lbl_brightness), buf);
lv_refr_now(NULL);
acc = 0;
}
GPIO42 and GPIO4 provide the encoder phases. The callback accumulates movement until it reaches one effective step, changes brightness by 5%, clamps the value, writes GPIO6 PWM, moves the arc, updates the percentage label, and forces an LVGL refresh. All three outputs use the same integer, preventing visual and physical brightness from drifting apart.
7. Experimental Observations¶
After reset, the 480 x 480 background image, Brightness title, cyan arc, white knob, and 50% value should appear. Rotating the encoder must change the arc, percentage, and physical backlight together in 5% steps. The image should remain stable without missing resources, color corruption, repeated resets, or long refresh pauses. Lesson 04 does not configure touch, so touching the arc is not an acceptance item yet.
8. Function or Resource Creation Process¶
Place bj_light_21_1.png in the ESPHome configuration directory beside 21-lvgl-interface.yaml. ESPHome converts it to the compiled resource img_bg_light; LVGL then creates the runtime widget img_bg. These IDs serve different stages and should not be interchanged. For a custom background, use a 480 x 480 image, keep important content away from the circular edge, and re-run Validate to confirm memory use and readability.

























