This board has no existing HA Community topic, so this write-up covers the hardware, the ESPHome drivers used, the LVGL quirks this panel needed, and the SY6970 PMU integration
Screen spec
| Component | Part | Notes |
|---|---|---|
| MCU | ESP32-S3R8 | Native WiFi, octal PSRAM, 16MB flash, ESP-IDF framework |
| Display panel | AXS15231B, QSPI | 3.4" bar panel, native geometry 180 (W) x 640 (H), driven at 90 degrees rotation for a 640x180 logical landscape bar |
| Touch controller | CST3530, capacitive | I2C, shares the bus with the PMU |
| PMU | SY6970 | I2C address 0x6A, Li-ion battery charger with onboard STAT LED |
| Backlight | LEDC PWM | GPIO1, monochromatic light entity |
The QSPI bus uses GPIO17 for clock and GPIO13/18/21/14 for data; the display’s chip-select is GPIO12 and reset is GPIO16. Pin assignments come from LilyGO’s own example firmware for this board.
Drivers used
Everything here is a stock ESPHome component; no custom C++ driver was needed for the display, touch, or PMU.
| Peripheral | ESPHome component | Config |
|---|---|---|
| Display | mipi_spi |
model: AXS15231, native dims 180x640, rotation: 90 |
| Touch | touchscreen: axs15231 |
I2C, shares touchscreen_bus with the PMU |
| PMU | sy6970 |
I2C address 0x6a, on touchscreen_bus |
| Backlight | output: ledc + light: monochromatic |
GPIO1 |
The AXS15231B has no hardware axis-swap bit, so ESPHome applies the 90-degree rotation as a software LVGL-level rotation rather than a native panel rotation. That single fact drives the touch quirk in the next section.
Modifications made (LVGL quirks)
Touch calibration must target the panel’s native, unrotated axes
ESPHome’s LVGL component rotates incoming touch coordinates itself when rotation: 90 is set: for a native width W, it computes new_x = old_y and new_y = W - old_x - 1. That means the touchscreen component’s own calibration.x_min/x_max/y_min/y_max has to describe the display’s native, unrotated geometry (180 wide x 640 tall) - not the logical 640x180 canvas the LVGL pages are laid out on.
The first attempt calibrated against the logical 640x180 canvas instead, and it showed up on hardware as touch feeling squeezed to one side, with only one button tile responding and the Y reading staying at 0 until the far edge of the screen was touched. Raw touch-coordinate logging plus reading the LVGL rotation source pinned this down. The fix:
touchscreen:
- platform: axs15231
transform:
mirror_x: false
mirror_y: true
swap_xy: true
calibration:
x_min: 0
x_max: 180
y_min: 0
y_max: 640
swap_xy is needed because the sensor’s raw X/Y come out swapped relative to which native axis each should scale against; mirror_x/mirror_y were confirmed by on-hardware button testing until tiles landed on the correct side.
Narrow tiles need a taller label clamp
This panel’s grid is 4 columns x 1 row across a 640px-wide bar, so each tile is only about 160px wide. The date/time tile’s label config (labelLines) was left at 1 when this device profile was first written, while every other device profile in the catalog uses 2 (or 3 for double-height tiles). At 160px, a date string with a month name wraps to a second line, and with labelLines: 1 the label’s clamp height was computed for one line only, so the wrapped month got clipped instead of shown. Setting labelLines: 2 for this device gave the clamp enough height for both lines.
PMU updates
What was added
- A
sy6970PMU config on the shared touch I2C bus: 1000mA input current limit, 4200mV charge voltage, 500mA charge current, 128mA precharge current, charging disabled by default. - Diagnostic sensors: binary
vbus_connected,charging,charge_done; textbus_status,charge_status. - A template switch to enable/disable charging, exposed to Home Assistant, defaulting to off.
The original motivation was simple: stop the flashing green STAT LED since I don’t use a battery
The I2C watchdog problem
The SY6970 has a built-in I2C communication watchdog (register REG07, bits 5:4, WATCHDOG[1:0]; power-on default is 01 = 40 seconds). If the host never resets it, the chip silently reverts several registers back to power-on defaults, including the charge-enable bit (REG03 CHG_CONFIG) and the STAT LED disable bit (REG07 STAT_DIS). ESPHome’s sy6970 component never touches this register, so charging and the LED would both quietly re-enable roughly 40 seconds after every boot or after any toggle from Home Assistant - matching exactly what was observed on hardware.
The fix
The stock component never services this watchdog, so the fix belongs in the component. I raised it upstream:
- ESPHome: esphome/esphome#19424 adds an
i2c_watchdog_timeoutoption (DISABLED,40S,80S,160S, default40S) and resets the watchdog automatically on every successful update, so the chip’s safety net stays enabled. A config error is raised ifupdate_intervalis not shorter than the timeout.reset_i2c_watchdog()is also available from lambdas. - Docs: esphome/esphome.io#7412
Credits
This device profile is built entirely on top of EspControl by Jonathan Tenniswood - the firmware, LVGL control-panel UI, and web configurator that make this screen usable at all. Docs: jtenniswood.github.io/espcontrol.
Pin assignments for the display, touch, and PMU come from LilyGO’s own example firmware: Xinyuan-LilyGO/T-Display-S3-Long (examples/*/pins_config.h).
A basic, EspControl-independent ESPHome config (LVGL hello-world example) was also contributed back to that same LilyGO repo, on the T-Display-S3-Long-cst3530 branch: examples/ESPHome_LVGL_HelloWorld. It’s a good starting point for anyone who wants bare ESPHome + LVGL on this board without pulling in the full EspControl package.
The display and touch drivers are the stock ESPHome mipi_spi (AXS15231 model) and axs15231 touchscreen components; PMU support uses ESPHome’s native sy6970 component. No custom ESPHome components were written for this board.
This work was originally submitted upstream as a PR to EspControl; the maintainer closed it since they don’t have this exact panel to test for regressions on. The device profile lives on this fork branch for anyone else picking up this board: willumpie82/espcontrol, add-lilygo-t-display-s3-long.
