Add the Elecrow CrowPanel 7.0" as a third board, and take the packages and the add-on from Gitea (0.2.93)
CI / checks (push) Successful in 12m50s
CI / firmware (add-on) (push) Successful in 18m19s
CI / firmware (min_version) (push) Successful in 17m55s

A board file for the Elecrow CrowPanel 7.0" (DIS08070H, ESP32-S3-WROOM-1-N4R8): 800x480 through mipi_rgb, GT911 on the
ESP32-S3's USB pins (elecrow_usb_phy.h frees them, behind a flag only this board sets), the Guition's vertical sizes
across a wider page, no rotation. Its 4 MB of flash take the CYD's budget: a partition table of the component's
(smart_display: partitions: 4mb_wide_slots, 1,984 KB slots), the icon fonts at 2 bits a pixel and the TLS client only
bring the firmware to 1,865,440 bytes, 91.8 % of a slot, with camera images kept. docs/ELECROW.md has the numbers and
the trade.

The add-on reads a large board's name from the type sensor's value, the editor offers the board under New screen and
draws the wide preview, tools/check.sh builds it with the budget, render_topbar and capture_ui take the panel's size.
Firmware 0.2.79; the CYD image is unchanged (1,633,760 bytes).

This fork builds from gittea.trippedonmy.name/Xandrossian/homeassistant_espscreen: the packages, the fonts, the
component and the add-on repository point there instead of GitHub.
This commit is contained in:
Xandrossian
2026-09-20 23:18:01 -07:00
parent efbab04b39
commit 9857cc3bda
64 changed files with 1664 additions and 145 deletions
+18 -12
View File
@@ -20,14 +20,16 @@ from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
WORK = ROOT / '.esphome' / 'render-topbar'
PROFILES = {'guition': 'guition-4848s040.yaml', 'cyd': 'home-like-2432s028.yaml'}
PROFILES = {'guition': 'guition-4848s040.yaml', 'cyd': 'home-like-2432s028.yaml', 'elecrow': 'elecrow-crowpanel7.yaml'}
sys.path.insert(0, str(ROOT / 'tools'))
import profiles # noqa: E402
FONTS = ('headline', 'time_label', 'sublabel_big', 'label', 'materialdesign_icons', 'materialdesign_icons_mini')
# Hardware headers the host cannot compile; the top bar needs none of them.
SKIP = {'guition_diagnostics.h', '__pycache__'}
# Header band per board: page width and height above the tiles.
BANDS = {'guition': (480, 72), 'cyd': (320, 40)}
# Header band per board: page width and height above the tiles. The Elecrow's bar is the Guition's across 800 px
# (the same fonts and insets), so it renders with the Guition's fonts.
BANDS = {'guition': (480, 72), 'cyd': (320, 40), 'elecrow': (800, 72)}
LARGE = ('guition', 'elecrow')
# (slug, title, items) with items as C++ expressions of the render lambda's helpers.
SCENARIOS = (
@@ -56,8 +58,8 @@ def font_blocks(board):
def band(board, y):
width, height = BANDS[board]
margin, top = (16, 22) if board == 'guition' else (11, 14)
tile_y, tile_w, tile_h, col2, radius = (72, 218, 108, 246, 22) if board == 'guition' else (40, 147, 52, 164, 18)
margin, top = (16, 22) if board in LARGE else (11, 14)
tile_y, tile_w, tile_h, col2, radius = {'guition': (72, 218, 108, 246, 22), 'elecrow': (72, 378, 108, 406, 22), 'cyd': (40, 147, 52, 164, 18)}[board]
return f''' - obj:
id: {board}_page
x: 0
@@ -85,7 +87,7 @@ def band(board, y):
text: ""
text_font: time_label_{board}
- obj:
x: {margin if board == 'guition' else 9}
x: {margin if board in LARGE else 9}
y: {tile_y}
width: {tile_w}
height: {tile_h}
@@ -128,6 +130,7 @@ struct Board {{ const char *name; lv_obj_t *page, *room, *time; const lv_font_t
std::vector<Board> boards = {{
{{"guition", id(guition_page), id(guition_room), id(guition_time), id(sublabel_big_guition)->get_lv_font(), id(materialdesign_icons_mini_guition)->get_lv_font()}},
{{"cyd", id(cyd_page), id(cyd_room), id(cyd_time), id(sublabel_big_cyd)->get_lv_font(), id(materialdesign_icons_mini_cyd)->get_lv_font()}},
{{"elecrow", id(elecrow_page), id(elecrow_room), id(elecrow_time), id(sublabel_big_guition)->get_lv_font(), id(materialdesign_icons_mini_guition)->get_lv_font()}},
}};
for (auto &scenario : scenarios) {{
for (auto &board : boards) {{
@@ -200,8 +203,8 @@ display:
- platform: sdl
id: sdl_display
dimensions:
width: 480
height: 480
width: 800
height: 540
auto_clear_enabled: false
update_interval: never
@@ -227,7 +230,7 @@ lvgl:
points:
- 0, 0
- 1, 1
{band('guition', 0)}{band('cyd', 220)}
{band('guition', 0)}{band('cyd', 220)}{band('elecrow', 340).replace('headline_elecrow', 'headline_guition').replace('time_label_elecrow', 'time_label_guition')}
script:
- id: action_seed
then:
@@ -254,15 +257,18 @@ def crop_scale(image, width, height, scale):
return bytes(out)
def sheet(out):
"""Header bands of every scenario: Guition 2x above CYD 3x, 12 px white between."""
"""Header bands of every scenario: Guition 2x above CYD 3x above the Elecrow 1x, 12 px white between."""
width, gap = 960, 12
rows = []
for slug, _, _ in SCENARIOS:
for board, scale in (('guition', 2), ('cyd', 3)):
for board, scale in (('guition', 2), ('cyd', 3), ('elecrow', 1)):
image = read_ppm(out / f'{slug}-{board}.ppm')
band_w, band_h = BANDS[board]
png(out / f'{slug}-{board}.png', image[0], image[1], image[2])
rows.append((crop_scale(image, band_w, band_h, scale), band_h * scale))
band = crop_scale(image, band_w, band_h, scale)
# A band narrower than the sheet (the Elecrow's 800) gets white at its right.
pad = bytes([255]) * (width - band_w * scale) * 3
rows.append((b''.join(band[y * band_w * scale * 3:(y + 1) * band_w * scale * 3] + pad for y in range(band_h * scale)), band_h * scale))
rows.append((bytes([255]) * width * 3 * gap * 2, gap * 2))
height = sum(h for _, h in rows)
png(out / 'sheet.png', width, height, b''.join(data for data, _ in rows))