Add a second ESPHome fleet display that shares the existing printer pages.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Joshua King
2026-10-20 11:24:47 -04:00
co-authored by Cursor
parent 5e50c9a296
commit 0ec94a909e
5 changed files with 156 additions and 124 deletions
+17 -10
View File
@@ -84,17 +84,22 @@ printer rotation are outside its current scope.
## Install
1. Keep `esphome/bambu-printer-display.yaml` and the entire `bambu-display/` folder
together in the ESPHome configuration directory. The generated package is checked
in, so the ESPHome dashboard can compile it without running the generator first.
1. Keep both device files and the entire `bambu-display/` folder together in the
ESPHome configuration directory. `bambu-printer-display.yaml` is the first board
and `bambu-printer-display-2.yaml` is the second. They share `board.yaml` and the
generated fleet package, which is checked in, so the ESPHome dashboard can compile
either file without running the generator first.
2. Supply the existing `api_encryption_key`, `wifi_iot_ssid` and `wifi_password`
entries in that directory's `secrets.yaml`.
3. Use ESPHome **2026.9.0 or newer**. Compile and install
`bambu-printer-display.yaml` over the board's USB-to-UART bridge for the first
flash; subsequent installs can use encrypted OTA.
4. Add **Bambu Printer Display** through Home Assistant's ESPHome integration using
the same API encryption key. The display only subscribes to entities, so it does
not require permission to perform Home Assistant actions.
3. Use ESPHome **2026.9.0 or newer**. Compile and install the matching device file
over that board's USB-to-UART bridge for the first flash; subsequent installs can
use encrypted OTA. Flash `bambu-printer-display.yaml` to the first panel and
`bambu-printer-display-2.yaml` to the second. Each file has its own ESPHome name,
so both panels can be online together.
4. Add **Bambu Printer Display** or **Bambu Printer Display 2** through Home
Assistant's ESPHome integration using the same API encryption key. Each display
only subscribes to entities, so it does not require permission to perform Home
Assistant actions.
5. Confirm all pages receive data and verify touch direction and color order on the
physical panel. Entity IDs match the repository's `ha-entities.txt` snapshot;
renamed or disabled entities in live HA must be corrected/enabled there.
@@ -103,7 +108,7 @@ The USB D+/D− GPIO19/20 pins are used by the board's touch bus. Logging theref
uses UART0. ESPHome may still warn about these two pins; they are intentional for
this board. If GT911 is not found at `0x5D`, inspect the I²C scan and use its reported
address (some hardware revisions select `0x14`). Backlight is GPIO2; RGB data pins
and timings are explicit in the main YAML rather than borrowed from a 5″ board.
and timings are explicit in `board.yaml` rather than borrowed from a 5″ board.
The display and LVGL both use **big-endian RGB565**. With `mipi_rgb`'s named
`red`/`green`/`blue` pin groups, its generated bus pin map already exchanges the
@@ -121,7 +126,9 @@ CLI checks from the repository root:
```sh
esphome config esphome/bambu-printer-display.yaml
esphome config esphome/bambu-printer-display-2.yaml
esphome compile esphome/bambu-printer-display.yaml
esphome compile esphome/bambu-printer-display-2.yaml
```
## Change or expand the fleet
+114
View File
@@ -0,0 +1,114 @@
# Shared Sunton ESP32-8048S043C board for every fleet display.
# Device name and friendly name come from the top-level YAML substitutions.
esphome:
name: ${device_name}
friendly_name: ${friendly_name}
min_version: 2026.9.0
includes:
- bambu-display/dashboard.h
esp32:
board: esp32-s3-devkitc-1
flash_size: 16MB
flash_mode: dio
cpu_frequency: 240MHz
framework:
type: esp-idf
sdkconfig_options:
CONFIG_ESP32S3_DATA_CACHE_64KB: "y"
CONFIG_ESP32S3_DATA_CACHE_LINE_64B: "y"
CONFIG_SPIRAM_FETCH_INSTRUCTIONS: "y"
CONFIG_SPIRAM_RODATA: "y"
psram:
mode: octal
speed: 80MHz
logger:
hardware_uart: UART0 # GPIO19/20 are the touch bus, not native USB.
api:
id: ha_api
encryption:
key: !secret api_encryption_key
ota:
- platform: esphome
encryption:
key: !secret api_encryption_key
wifi:
ssid: !secret wifi_iot_ssid
password: !secret wifi_password
i2c:
id: touch_bus
sda: GPIO19
scl: GPIO20
scan: true
display:
- platform: mipi_rgb
id: panel_display
model: RPI
dimensions: 800x480
color_order: RGB
# Named RGB data_pins are byte-swapped by mipi_rgb's pin mapping.
# Send big-endian RGB565 pixels to match that wiring transformation.
byte_order: big_endian
de_pin: GPIO40
hsync_pin: GPIO39
vsync_pin: GPIO41
pclk_pin: GPIO42
pclk_inverted: true
pclk_frequency: 16MHz
hsync_front_porch: 8
hsync_pulse_width: 4
hsync_back_porch: 8
vsync_front_porch: 8
vsync_pulse_width: 4
vsync_back_porch: 8
data_pins:
red: [GPIO45, GPIO48, GPIO47, GPIO21, GPIO14]
green: [GPIO5, GPIO6, GPIO7, GPIO15, GPIO16, GPIO4]
blue: [GPIO8, GPIO3, GPIO46, GPIO9, GPIO1]
auto_clear_enabled: false
update_interval: never
touchscreen:
- platform: gt911
id: panel_touch
display: panel_display
i2c_id: touch_bus
address: 0x5D
# Polling avoids the GT911 INT pin's boot/address-selection behaviour.
update_interval: 20ms
output:
- platform: ledc
id: backlight_output
pin: GPIO2
light:
- platform: monochromatic
id: panel_backlight
name: Backlight
output: backlight_output
restore_mode: ALWAYS_ON
default_transition_length: 0s
time:
- platform: homeassistant
id: ha_time
timezone: America/New_York
lvgl:
id: dashboard
displays: [panel_display]
touchscreens: [panel_touch]
buffer_size: 12%
color_depth: 16
byte_order: big_endian # Must match mipi_rgb's named RGB pin mapping above.
bg_color: 0x000000
text_color: 0xEEEEEE
default_font: montserrat_18
+13 -1
View File
@@ -123,7 +123,7 @@ class FleetTests(unittest.TestCase):
pass
for tag in ('!secret', '!include'):
Loader.add_constructor(tag, lambda loader, node: loader.construct_scalar(node))
config = yaml.load((HERE.parent / 'bambu-printer-display.yaml').read_text(), Loader=Loader)
config = yaml.load((HERE / 'board.yaml').read_text(), Loader=Loader)
display = config['display'][0]
pins = display['data_pins']
natural = pins['blue'] + pins['green'] + pins['red']
@@ -135,6 +135,18 @@ class FleetTests(unittest.TestCase):
for i, pin in enumerate(driver))
self.assertEqual(panel_word, color, f'RGB565 color {color:#06x} is wired incorrectly')
def test_both_boards_share_one_hardware_package(self):
class Loader(yaml.SafeLoader):
pass
Loader.add_constructor('!include', lambda loader, node: loader.construct_scalar(node))
names = set()
for filename in ('bambu-printer-display.yaml', 'bambu-printer-display-2.yaml'):
config = yaml.load((HERE.parent / filename).read_text(), Loader=Loader)
names.add(config['substitutions']['device_name'])
self.assertEqual(config['packages']['board'], 'bambu-display/board.yaml')
self.assertEqual(config['packages']['fleet'], 'bambu-display/generated.yaml')
self.assertEqual(len(names), 2)
def test_diagnostic_color_page_is_skipped_during_normal_navigation(self):
package = generate(self.printers)
page = next(page for page in package['lvgl']['pages'] if page['id'] == 'color_test_page')
+10
View File
@@ -0,0 +1,10 @@
# Second Sunton ESP32-8048S043C fleet display. Same pages and hardware as
# bambu-printer-display.yaml, with its own ESPHome name so both boards can
# join Home Assistant. Edit bambu-display/printers.yaml, then run generate.py.
substitutions:
device_name: bambu-printer-display-2
friendly_name: Bambu Printer Display 2
packages:
board: !include bambu-display/board.yaml
fleet: !include bambu-display/generated.yaml
+2 -113
View File
@@ -1,121 +1,10 @@
# Sunton ESP32-8048S043C: 4.3" 800x480 RGB LCD + GT911 capacitive touch.
# Edit bambu-display/printers.yaml, then run its generate.py to change the fleet.
# The second board is bambu-printer-display-2.yaml; both include bambu-display/board.yaml.
substitutions:
device_name: bambu-printer-display
friendly_name: Bambu Printer Display
esphome:
name: ${device_name}
friendly_name: ${friendly_name}
min_version: 2026.9.0
includes:
- bambu-display/dashboard.h
esp32:
board: esp32-s3-devkitc-1
flash_size: 16MB
flash_mode: dio
cpu_frequency: 240MHz
framework:
type: esp-idf
sdkconfig_options:
CONFIG_ESP32S3_DATA_CACHE_64KB: "y"
CONFIG_ESP32S3_DATA_CACHE_LINE_64B: "y"
CONFIG_SPIRAM_FETCH_INSTRUCTIONS: "y"
CONFIG_SPIRAM_RODATA: "y"
psram:
mode: octal
speed: 80MHz
logger:
hardware_uart: UART0 # GPIO19/20 are the touch bus, not native USB.
api:
id: ha_api
encryption:
key: !secret api_encryption_key
ota:
- platform: esphome
encryption:
key: !secret api_encryption_key
wifi:
ssid: !secret wifi_iot_ssid
password: !secret wifi_password
i2c:
id: touch_bus
sda: GPIO19
scl: GPIO20
scan: true
display:
- platform: mipi_rgb
id: panel_display
model: RPI
dimensions: 800x480
color_order: RGB
# Named RGB data_pins are byte-swapped by mipi_rgb's pin mapping.
# Send big-endian RGB565 pixels to match that wiring transformation.
byte_order: big_endian
de_pin: GPIO40
hsync_pin: GPIO39
vsync_pin: GPIO41
pclk_pin: GPIO42
pclk_inverted: true
pclk_frequency: 16MHz
hsync_front_porch: 8
hsync_pulse_width: 4
hsync_back_porch: 8
vsync_front_porch: 8
vsync_pulse_width: 4
vsync_back_porch: 8
data_pins:
red: [GPIO45, GPIO48, GPIO47, GPIO21, GPIO14]
green: [GPIO5, GPIO6, GPIO7, GPIO15, GPIO16, GPIO4]
blue: [GPIO8, GPIO3, GPIO46, GPIO9, GPIO1]
auto_clear_enabled: false
update_interval: never
touchscreen:
- platform: gt911
id: panel_touch
display: panel_display
i2c_id: touch_bus
address: 0x5D
# Polling avoids the GT911 INT pin's boot/address-selection behaviour.
update_interval: 20ms
output:
- platform: ledc
id: backlight_output
pin: GPIO2
light:
- platform: monochromatic
id: panel_backlight
name: Backlight
output: backlight_output
restore_mode: ALWAYS_ON
default_transition_length: 0s
time:
- platform: homeassistant
id: ha_time
timezone: America/New_York
packages:
board: !include bambu-display/board.yaml
fleet: !include bambu-display/generated.yaml
lvgl:
id: dashboard
displays: [panel_display]
touchscreens: [panel_touch]
buffer_size: 12%
color_depth: 16
byte_order: big_endian # Must match mipi_rgb's named RGB pin mapping above.
bg_color: 0x000000
text_color: 0xEEEEEE
default_font: montserrat_18