Show each printer on the fleet page as a status gauge.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Joshua King
2026-10-20 15:13:24 -04:00
co-authored by Cursor
parent 4626019a3e
commit 360e86e46a
6 changed files with 537 additions and 698 deletions
+45 -39
View File
@@ -245,48 +245,56 @@ def snapshot_lines(printer, expressions, trays):
return lines
def overview_layout(count):
row_h = (436 - 46) // count
return row_h, row_h >= 52
def overview_slots(count):
"""Place one steam gauge per printer. Full-size arcs match the printer pages."""
columns = 4 if count > 4 else max(count, 1)
rows = (count + columns - 1) // columns
top, bottom = 8, 400
arc = min(154, (800 // columns) - 20, (bottom - top) // rows - 36)
col_w = 800 // columns
row_h = (bottom - top) // rows
slots = []
for index in range(count):
row, col = divmod(index, columns)
in_row = min(columns, count - row * columns)
x0 = (800 - in_row * col_w) // 2
gauge_w = arc + 16
slots.append((x0 + col * col_w + (col_w - gauge_w) // 2,
top + row * row_h, arc))
return slots
def overview_row(printer, y, row_h, two_line):
def overview_gauge(printer, x, y, arc):
pid = printer['id']
name_w, status_x, status_w = (430, 448, 312) if two_line else (240, 258, 150)
meta_x, meta_w, meta_y = (448, 312, 28) if two_line else (414, 346, 8)
children = [
{'obj': {'id': f'{pid}_overview_accent', 'x': 0, 'y': 8, 'width': 4,
'height': max(row_h - 16, 8), 'bg_color': MUTED, 'bg_opa': 'COVER',
'border_width': 0, 'radius': 2, 'pad_all': 0, 'scrollable': False,
'gesture_bubble': True}},
label(printer['name'], 12, 2 if two_line else 6, name_w, 18 if two_line else 16),
label('SYNCING', status_x, 6 if two_line else 8, status_w, 16 if two_line else 14,
id=f'{pid}_overview_status', text_align='RIGHT', text_color=MUTED),
scale = arc / 154
value_font = 32 if arc >= 140 else 18
detail_font = 14 if arc >= 140 else 12
name_font = 14 if arc >= 140 else 12
open_page = [{'lvgl.page.show': f'{pid}_page'}]
inner = max(8, int(round(13 * scale)))
return [
{'arc': {'id': f'{pid}_overview_arc', 'x': x + int(round(8 * scale)), 'y': y,
'width': arc, 'height': arc, 'min_value': 0, 'max_value': 100, 'value': 0,
'start_angle': 135, 'end_angle': 45, 'arc_width': inner, 'arc_color': TRACK,
'indicator': {'arc_color': GREEN, 'arc_width': inner}, 'adjustable': False,
'gesture_bubble': True, 'clickable': True, 'on_click': open_page}},
label('--', x + int(round(14 * scale)), y + int(round(47 * scale)), int(round(142 * scale)),
value_font, id=f'{pid}_overview_value', text_align='CENTER',
clickable=True, on_click=open_page),
label('SYNCING', x + int(round(14 * scale)), y + int(round(86 * scale)),
int(round(142 * scale)), detail_font, id=f'{pid}_overview_detail',
text_align='CENTER', text_color=MUTED, clickable=True, on_click=open_page),
label(printer['name'], x, y + int(round(137 * scale)), arc + 16, name_font,
text_align='CENTER', text_color=GREEN, clickable=True, on_click=open_page),
]
if two_line:
children.append(label('Waiting for Home Assistant', 12, 28, 430, 12,
id=f'{pid}_overview_task', text_color=MUTED))
children += [
label('--', meta_x, meta_y, meta_w, 12 if two_line else 14,
id=f'{pid}_overview_meta', text_align='RIGHT', text_color=MUTED),
{'bar': {'id': f'{pid}_overview_progress', 'x': 12, 'y': row_h - 7, 'width': 748, 'height': 4,
'min_value': 0, 'max_value': 100, 'value': 0, 'bg_color': TRACK,
'indicator': {'bg_color': GREEN}, 'gesture_bubble': True}},
]
return {'obj': {'id': f'{pid}_overview_row', 'x': 8, 'y': y, 'width': 784, 'height': row_h,
'bg_color': BG, 'bg_opa': 'COVER', 'border_width': 0, 'pad_all': 0,
'radius': 0, 'scrollable': False, 'clickable': True, 'gesture_bubble': True,
'on_click': [{'lvgl.page.show': f'{pid}_page'}], 'widgets': children}}
def overview_page(printers):
row_h, two_line = overview_layout(len(printers))
widgets = [
label('FLEET', 16, 8, 180, 26, text_color=GREEN),
label('SYNCING', 210, 16, 574, 14, id='fleet_summary', text_align='RIGHT', text_color=MUTED),
]
widgets += [overview_row(printer, 46 + index * row_h, row_h, two_line)
for index, printer in enumerate(printers)]
widgets = []
for printer, (x, y, arc) in zip(printers, overview_slots(len(printers))):
widgets += overview_gauge(printer, x, y, arc)
widgets.append(label('SYNCING', 90, 404, 620, 14, id='fleet_summary',
text_align='CENTER', text_color=MUTED))
for direction, x, text in (('previous', 16, '<'), ('next', 720, '>')):
widgets.append({'button': {'x': x, 'y': 446, 'width': 64, 'height': 30,
'bg_color': TRACK, 'radius': 8, 'border_width': 0,
@@ -308,16 +316,14 @@ def overview_page(printers):
def fleet_refresh_lines(snapshots):
_, two_line = overview_layout(len(snapshots))
lines = ['bambu_display::FleetCounts counts;']
for pid, snapshot in snapshots:
task = f'id({pid}_overview_task)' if two_line else 'nullptr'
lines.append('{')
lines.extend(snapshot)
lines.append('bambu_display::tally(counts, data);')
lines.append('bambu_display::render_overview(data, {' + ', '.join([
f'id({pid}_overview_status)', task, f'id({pid}_overview_meta)',
f'id({pid}_overview_progress)', f'id({pid}_overview_accent)']) + '});')
f'id({pid}_overview_arc)', f'id({pid}_overview_value)',
f'id({pid}_overview_detail)']) + '});')
lines.append('}')
lines.append('bambu_display::render_fleet_summary(id(fleet_summary), counts);')
return lines