Color overview gauges by active filament and show finish times.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Joshua King
2026-10-20 19:22:04 -04:00
co-authored by Cursor
parent 360e86e46a
commit c5b7408b18
7 changed files with 380 additions and 235 deletions
+4 -6
View File
@@ -17,12 +17,10 @@ Home Assistant must be running and its printer integrations must have current pr
The configured swipe order is: The configured swipe order is:
1. Fleet — one steam gauge per printer, matching the progress arcs on the 1. Print Status Overview — one steam gauge per printer. Each ring uses the
printer pages. The needle is print progress, and the arc color follows color of that printer's active filament. The center shows the percent
status: green while printing, amber while paused, red for an error. The complete in white, with the printer name and estimated finish time underneath.
center is the percent complete and the caption is the status. A line under The local time is in the top-right corner. Tap a gauge to open that printer.
the gauges counts printers that need attention, are printing, paused, idle,
offline or still syncing. Tap a gauge to open that printer.
2. PrintsCharming — P1S, Office, both four-slot AMS units. 2. PrintsCharming — P1S, Office, both four-slot AMS units.
3. Polly-Pocket — A1 mini, Office, external spool. 3. Polly-Pocket — A1 mini, Office, external spool.
4. Ds-Turd-Flinger — A1, Upstairs, four-slot AMS. 4. Ds-Turd-Flinger — A1, Upstairs, four-slot AMS.
+16 -7
View File
@@ -226,6 +226,15 @@ struct Snapshot {
return progress_text + " " + finish_time + " " + time_line; return progress_text + " " + finish_time + " " + time_line;
return progress_text + " " + time_line; return progress_text + " " + time_line;
} }
// Active tray is the spool the printer loaded most recently. Without one, keep green.
uint32_t active_filament_color() const {
for (const auto &tray : trays)
if (is_on(tray.active)) {
const uint32_t color = filament_color(tray.color);
if (color != TRACK) return color;
}
return GREEN;
}
uint32_t status_color() const { uint32_t status_color() const {
if (!live()) return MUTED; if (!live()) return MUTED;
const auto state = lower(status); const auto state = lower(status);
@@ -290,7 +299,7 @@ struct Widgets {
lv_obj_t *elapsed = nullptr; lv_obj_t *elapsed = nullptr;
}; };
struct OverviewWidgets { struct OverviewWidgets {
lv_obj_t *arc, *value, *detail; lv_obj_t *arc, *value, *finish;
}; };
inline void set_text(lv_obj_t *label, const std::string &text) { inline void set_text(lv_obj_t *label, const std::string &text) {
@@ -361,15 +370,15 @@ inline void render(const Snapshot &data, const Widgets &widgets) {
inline void render_overview(const Snapshot &data, const OverviewWidgets &widgets) { inline void render_overview(const Snapshot &data, const OverviewWidgets &widgets) {
const bool live = data.live(); const bool live = data.live();
const uint32_t color = data.status_color(); const uint32_t filament = data.active_filament_color();
const float shown = live && std::isfinite(data.progress) const float shown = live && std::isfinite(data.progress)
? std::clamp(data.progress, 0.0f, 100.0f) : NAN; ? std::clamp(data.progress, 0.0f, 100.0f) : NAN;
lv_arc_set_value(widgets.arc, live ? gauge_value(data.progress, 100) : 0); lv_obj_set_style_arc_color(widgets.arc, lv_color_hex(filament), LV_PART_MAIN);
lv_obj_set_style_arc_color(widgets.arc, lv_color_hex(color), LV_PART_INDICATOR); lv_obj_set_style_arc_color(widgets.arc, lv_color_hex(filament), LV_PART_INDICATOR);
lv_arc_set_value(widgets.arc, 100);
set_text(widgets.value, number(shown)); set_text(widgets.value, number(shown));
lv_obj_set_style_text_color(widgets.value, lv_color_hex(live ? color : MUTED), 0); lv_obj_set_style_text_color(widgets.value, lv_color_hex(0xFFFFFF), 0);
set_text(widgets.detail, data.status_text()); set_text(widgets.finish, live && !data.finish_time.empty() ? data.finish_time : "--");
lv_obj_set_style_text_color(widgets.detail, lv_color_hex(color), 0);
} }
inline void render_fleet_summary(lv_obj_t *label, const FleetCounts &counts) { inline void render_fleet_summary(lv_obj_t *label, const FleetCounts &counts) {
+36 -25
View File
@@ -246,13 +246,13 @@ def snapshot_lines(printer, expressions, trays):
def overview_slots(count): def overview_slots(count):
"""Place one steam gauge per printer. Full-size arcs match the printer pages.""" """Place one steam gauge per printer under the page title."""
columns = 4 if count > 4 else max(count, 1) columns = 4 if count > 4 else max(count, 1)
rows = (count + columns - 1) // columns rows = (count + columns - 1) // columns
top, bottom = 8, 400 top, bottom = 46, 432
arc = min(154, (800 // columns) - 20, (bottom - top) // rows - 36)
col_w = 800 // columns
row_h = (bottom - top) // rows row_h = (bottom - top) // rows
arc = min(154, (800 // columns) - 24, row_h - 48)
col_w = 800 // columns
slots = [] slots = []
for index in range(count): for index in range(count):
row, col = divmod(index, columns) row, col = divmod(index, columns)
@@ -267,34 +267,36 @@ def overview_slots(count):
def overview_gauge(printer, x, y, arc): def overview_gauge(printer, x, y, arc):
pid = printer['id'] pid = printer['id']
scale = arc / 154 scale = arc / 154
value_font = 32 if arc >= 140 else 18 value_font = 32 if arc >= 130 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'}] open_page = [{'lvgl.page.show': f'{pid}_page'}]
inner = max(8, int(round(13 * scale))) inner = max(10, int(round(13 * scale)))
inner_x = x + int(round(8 * scale))
number_y = y + int(round(arc * 0.30))
return [ return [
{'arc': {'id': f'{pid}_overview_arc', 'x': x + int(round(8 * scale)), 'y': y, {'arc': {'id': f'{pid}_overview_arc', 'x': inner_x, 'y': y,
'width': arc, 'height': arc, 'min_value': 0, 'max_value': 100, 'value': 0, 'width': arc, 'height': arc, 'min_value': 0, 'max_value': 100, 'value': 100,
'start_angle': 135, 'end_angle': 45, 'arc_width': inner, 'arc_color': TRACK, 'start_angle': 135, 'end_angle': 45, 'arc_width': inner, 'arc_color': GREEN,
'indicator': {'arc_color': GREEN, 'arc_width': inner}, 'adjustable': False, 'indicator': {'arc_color': GREEN, 'arc_width': inner}, 'adjustable': False,
'gesture_bubble': True, 'clickable': True, 'on_click': open_page}}, 'gesture_bubble': True, 'clickable': True, 'on_click': open_page}},
label('--', x + int(round(14 * scale)), y + int(round(47 * scale)), int(round(142 * scale)), label('--', inner_x, number_y, arc, value_font, id=f'{pid}_overview_value',
value_font, id=f'{pid}_overview_value', text_align='CENTER', text_align='CENTER', text_color=0xFFFFFF, clickable=True, on_click=open_page),
label('%', inner_x, number_y + (34 if value_font >= 28 else 20), arc, 16,
id=f'{pid}_overview_percent', text_align='CENTER', text_color=0xFFFFFF,
clickable=True, on_click=open_page), clickable=True, on_click=open_page),
label('SYNCING', x + int(round(14 * scale)), y + int(round(86 * scale)), label(printer['name'], x, y + arc + 2, arc + 16, 14, text_align='CENTER',
int(round(142 * scale)), detail_font, id=f'{pid}_overview_detail', text_color=TEXT_COLOR, clickable=True, on_click=open_page),
text_align='CENTER', text_color=MUTED, clickable=True, on_click=open_page), label('--', x, y + arc + 22, arc + 16, 14, id=f'{pid}_overview_finish',
label(printer['name'], x, y + int(round(137 * scale)), arc + 16, name_font, text_align='CENTER', text_color=TEXT_COLOR, clickable=True, on_click=open_page),
text_align='CENTER', text_color=GREEN, clickable=True, on_click=open_page),
] ]
def overview_page(printers): def overview_page(printers):
widgets = [] widgets = [
label('Print Status Overview', 16, 10, 520, 22, text_color=GREEN),
label('--:--', 548, 12, 236, 18, id='fleet_clock', text_align='RIGHT', text_color=TEXT_COLOR),
]
for printer, (x, y, arc) in zip(printers, overview_slots(len(printers))): for printer, (x, y, arc) in zip(printers, overview_slots(len(printers))):
widgets += overview_gauge(printer, x, y, arc) 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, '>')): for direction, x, text in (('previous', 16, '<'), ('next', 720, '>')):
widgets.append({'button': {'x': x, 'y': 446, 'width': 64, 'height': 30, widgets.append({'button': {'x': x, 'y': 446, 'width': 64, 'height': 30,
'bg_color': TRACK, 'radius': 8, 'border_width': 0, 'bg_color': TRACK, 'radius': 8, 'border_width': 0,
@@ -316,16 +318,25 @@ def overview_page(printers):
def fleet_refresh_lines(snapshots): def fleet_refresh_lines(snapshots):
lines = ['bambu_display::FleetCounts counts;'] lines = []
for pid, snapshot in snapshots: for pid, snapshot in snapshots:
lines.append('{') lines.append('{')
lines.extend(snapshot) lines.extend(snapshot)
lines.append('bambu_display::tally(counts, data);')
lines.append('bambu_display::render_overview(data, {' + ', '.join([ lines.append('bambu_display::render_overview(data, {' + ', '.join([
f'id({pid}_overview_arc)', f'id({pid}_overview_value)', f'id({pid}_overview_arc)', f'id({pid}_overview_value)',
f'id({pid}_overview_detail)']) + '});') f'id({pid}_overview_finish)']) + '});')
lines.append('}') lines.append('}')
lines.append('bambu_display::render_fleet_summary(id(fleet_summary), counts);') lines += [
'{',
'const auto clock = id(ha_time).now();',
'std::string clock_text = "--:--";',
'if (clock.is_valid()) {',
' clock_text = clock.strftime("%I:%M %p");',
' if (!clock_text.empty() && clock_text[0] == \'0\') clock_text.erase(0, 1);',
'}',
'bambu_display::set_text(id(fleet_clock), clock_text);',
'}',
]
return lines return lines
+305 -190
View File
@@ -1490,7 +1490,6 @@ script:
- id: fleet_refresh - id: fleet_refresh
then: then:
- lambda: !lambda |- - lambda: !lambda |-
bambu_display::FleetCounts counts;
{ {
bambu_display::Snapshot data; bambu_display::Snapshot data;
data.connected = id(ha_api).is_connected_with_state_subscription(); data.connected = id(ha_api).is_connected_with_state_subscription();
@@ -1532,8 +1531,7 @@ script:
data.trays.push_back({"B2", id(prints_charming_tray_5_type).state, id(prints_charming_tray_5_color).state, id(prints_charming_tray_5_active).state}); data.trays.push_back({"B2", id(prints_charming_tray_5_type).state, id(prints_charming_tray_5_color).state, id(prints_charming_tray_5_active).state});
data.trays.push_back({"B3", id(prints_charming_tray_6_type).state, id(prints_charming_tray_6_color).state, id(prints_charming_tray_6_active).state}); data.trays.push_back({"B3", id(prints_charming_tray_6_type).state, id(prints_charming_tray_6_color).state, id(prints_charming_tray_6_active).state});
data.trays.push_back({"B4", id(prints_charming_tray_7_type).state, id(prints_charming_tray_7_color).state, id(prints_charming_tray_7_active).state}); data.trays.push_back({"B4", id(prints_charming_tray_7_type).state, id(prints_charming_tray_7_color).state, id(prints_charming_tray_7_active).state});
bambu_display::tally(counts, data); bambu_display::render_overview(data, {id(prints_charming_overview_arc), id(prints_charming_overview_value), id(prints_charming_overview_finish)});
bambu_display::render_overview(data, {id(prints_charming_overview_arc), id(prints_charming_overview_value), id(prints_charming_overview_detail)});
} }
{ {
bambu_display::Snapshot data; bambu_display::Snapshot data;
@@ -1567,8 +1565,7 @@ script:
if (clock.is_valid() && seconds_left >= 0) if (clock.is_valid() && seconds_left >= 0)
data.finish_time = esphome::ESPTime::from_epoch_local(clock.timestamp + seconds_left).strftime("%H:%M"); data.finish_time = esphome::ESPTime::from_epoch_local(clock.timestamp + seconds_left).strftime("%H:%M");
data.trays.push_back({"EXT", id(polly_pocket_tray_0_type).state, id(polly_pocket_tray_0_color).state, id(polly_pocket_tray_0_active).state}); data.trays.push_back({"EXT", id(polly_pocket_tray_0_type).state, id(polly_pocket_tray_0_color).state, id(polly_pocket_tray_0_active).state});
bambu_display::tally(counts, data); bambu_display::render_overview(data, {id(polly_pocket_overview_arc), id(polly_pocket_overview_value), id(polly_pocket_overview_finish)});
bambu_display::render_overview(data, {id(polly_pocket_overview_arc), id(polly_pocket_overview_value), id(polly_pocket_overview_detail)});
} }
{ {
bambu_display::Snapshot data; bambu_display::Snapshot data;
@@ -1605,8 +1602,7 @@ script:
data.trays.push_back({"A2", id(ds_turd_flinger_tray_1_type).state, id(ds_turd_flinger_tray_1_color).state, id(ds_turd_flinger_tray_1_active).state}); data.trays.push_back({"A2", id(ds_turd_flinger_tray_1_type).state, id(ds_turd_flinger_tray_1_color).state, id(ds_turd_flinger_tray_1_active).state});
data.trays.push_back({"A3", id(ds_turd_flinger_tray_2_type).state, id(ds_turd_flinger_tray_2_color).state, id(ds_turd_flinger_tray_2_active).state}); data.trays.push_back({"A3", id(ds_turd_flinger_tray_2_type).state, id(ds_turd_flinger_tray_2_color).state, id(ds_turd_flinger_tray_2_active).state});
data.trays.push_back({"A4", id(ds_turd_flinger_tray_3_type).state, id(ds_turd_flinger_tray_3_color).state, id(ds_turd_flinger_tray_3_active).state}); data.trays.push_back({"A4", id(ds_turd_flinger_tray_3_type).state, id(ds_turd_flinger_tray_3_color).state, id(ds_turd_flinger_tray_3_active).state});
bambu_display::tally(counts, data); bambu_display::render_overview(data, {id(ds_turd_flinger_overview_arc), id(ds_turd_flinger_overview_value), id(ds_turd_flinger_overview_finish)});
bambu_display::render_overview(data, {id(ds_turd_flinger_overview_arc), id(ds_turd_flinger_overview_value), id(ds_turd_flinger_overview_detail)});
} }
{ {
bambu_display::Snapshot data; bambu_display::Snapshot data;
@@ -1643,8 +1639,7 @@ script:
data.trays.push_back({"A2", id(jordyns_layer_slayer_tray_1_type).state, id(jordyns_layer_slayer_tray_1_color).state, id(jordyns_layer_slayer_tray_1_active).state}); data.trays.push_back({"A2", id(jordyns_layer_slayer_tray_1_type).state, id(jordyns_layer_slayer_tray_1_color).state, id(jordyns_layer_slayer_tray_1_active).state});
data.trays.push_back({"A3", id(jordyns_layer_slayer_tray_2_type).state, id(jordyns_layer_slayer_tray_2_color).state, id(jordyns_layer_slayer_tray_2_active).state}); data.trays.push_back({"A3", id(jordyns_layer_slayer_tray_2_type).state, id(jordyns_layer_slayer_tray_2_color).state, id(jordyns_layer_slayer_tray_2_active).state});
data.trays.push_back({"A4", id(jordyns_layer_slayer_tray_3_type).state, id(jordyns_layer_slayer_tray_3_color).state, id(jordyns_layer_slayer_tray_3_active).state}); data.trays.push_back({"A4", id(jordyns_layer_slayer_tray_3_type).state, id(jordyns_layer_slayer_tray_3_color).state, id(jordyns_layer_slayer_tray_3_active).state});
bambu_display::tally(counts, data); bambu_display::render_overview(data, {id(jordyns_layer_slayer_overview_arc), id(jordyns_layer_slayer_overview_value), id(jordyns_layer_slayer_overview_finish)});
bambu_display::render_overview(data, {id(jordyns_layer_slayer_overview_arc), id(jordyns_layer_slayer_overview_value), id(jordyns_layer_slayer_overview_detail)});
} }
{ {
bambu_display::Snapshot data; bambu_display::Snapshot data;
@@ -1691,8 +1686,7 @@ script:
data.trays.push_back({"B2", id(constipation_orion_tray_5_type).state, id(constipation_orion_tray_5_color).state, id(constipation_orion_tray_5_active).state}); data.trays.push_back({"B2", id(constipation_orion_tray_5_type).state, id(constipation_orion_tray_5_color).state, id(constipation_orion_tray_5_active).state});
data.trays.push_back({"B3", id(constipation_orion_tray_6_type).state, id(constipation_orion_tray_6_color).state, id(constipation_orion_tray_6_active).state}); data.trays.push_back({"B3", id(constipation_orion_tray_6_type).state, id(constipation_orion_tray_6_color).state, id(constipation_orion_tray_6_active).state});
data.trays.push_back({"B4", id(constipation_orion_tray_7_type).state, id(constipation_orion_tray_7_color).state, id(constipation_orion_tray_7_active).state}); data.trays.push_back({"B4", id(constipation_orion_tray_7_type).state, id(constipation_orion_tray_7_color).state, id(constipation_orion_tray_7_active).state});
bambu_display::tally(counts, data); bambu_display::render_overview(data, {id(constipation_orion_overview_arc), id(constipation_orion_overview_value), id(constipation_orion_overview_finish)});
bambu_display::render_overview(data, {id(constipation_orion_overview_arc), id(constipation_orion_overview_value), id(constipation_orion_overview_detail)});
} }
{ {
bambu_display::Snapshot data; bambu_display::Snapshot data;
@@ -1722,8 +1716,7 @@ script:
const auto clock = id(ha_time).now(); const auto clock = id(ha_time).now();
if (clock.is_valid() && seconds_left >= 0) if (clock.is_valid() && seconds_left >= 0)
data.finish_time = esphome::ESPTime::from_epoch_local(clock.timestamp + seconds_left).strftime("%H:%M"); data.finish_time = esphome::ESPTime::from_epoch_local(clock.timestamp + seconds_left).strftime("%H:%M");
bambu_display::tally(counts, data); bambu_display::render_overview(data, {id(centauri_carbon_overview_arc), id(centauri_carbon_overview_value), id(centauri_carbon_overview_finish)});
bambu_display::render_overview(data, {id(centauri_carbon_overview_arc), id(centauri_carbon_overview_value), id(centauri_carbon_overview_detail)});
} }
{ {
bambu_display::Snapshot data; bambu_display::Snapshot data;
@@ -1749,10 +1742,17 @@ script:
const auto clock = id(ha_time).now(); const auto clock = id(ha_time).now();
if (clock.is_valid() && seconds_left >= 0) if (clock.is_valid() && seconds_left >= 0)
data.finish_time = esphome::ESPTime::from_epoch_local(clock.timestamp + seconds_left).strftime("%H:%M"); data.finish_time = esphome::ESPTime::from_epoch_local(clock.timestamp + seconds_left).strftime("%H:%M");
bambu_display::tally(counts, data); bambu_display::render_overview(data, {id(saturn_overview_arc), id(saturn_overview_value), id(saturn_overview_finish)});
bambu_display::render_overview(data, {id(saturn_overview_arc), id(saturn_overview_value), id(saturn_overview_detail)}); }
{
const auto clock = id(ha_time).now();
std::string clock_text = "--:--";
if (clock.is_valid()) {
clock_text = clock.strftime("%I:%M %p");
if (!clock_text.empty() && clock_text[0] == '0') clock_text.erase(0, 1);
}
bambu_display::set_text(id(fleet_clock), clock_text);
} }
bambu_display::render_fleet_summary(id(fleet_summary), counts);
interval: interval:
- interval: 1s - interval: 1s
then: then:
@@ -1819,22 +1819,44 @@ lvgl:
on_load: on_load:
- script.execute: fleet_refresh - script.execute: fleet_refresh
widgets: widgets:
- label:
text: Print Status Overview
x: 16
y: 10
width: 520
height: 30
text_color: 65280
text_font: montserrat_22
long_mode: DOT
gesture_bubble: true
- label:
text: --:--
x: 548
y: 12
width: 236
height: 26
text_color: 15658734
text_font: montserrat_18
long_mode: DOT
gesture_bubble: true
id: fleet_clock
text_align: RIGHT
- arc: - arc:
id: prints_charming_overview_arc id: prints_charming_overview_arc
x: 23 x: 27
y: 8 y: 46
width: 154 width: 145
height: 154 height: 145
min_value: 0 min_value: 0
max_value: 100 max_value: 100
value: 0 value: 100
start_angle: 135 start_angle: 135
end_angle: 45 end_angle: 45
arc_width: 13 arc_width: 12
arc_color: 1647403 arc_color: 65280
indicator: indicator:
arc_color: 65280 arc_color: 65280
arc_width: 13 arc_width: 12
adjustable: false adjustable: false
gesture_bubble: true gesture_bubble: true
clickable: true clickable: true
@@ -1842,11 +1864,11 @@ lvgl:
- lvgl.page.show: prints_charming_page - lvgl.page.show: prints_charming_page
- label: - label:
text: -- text: --
x: 29 x: 27
y: 55 y: 90
width: 142 width: 145
height: 40 height: 40
text_color: 15658734 text_color: 16777215
text_font: montserrat_32 text_font: montserrat_32
long_mode: DOT long_mode: DOT
gesture_bubble: true gesture_bubble: true
@@ -1856,27 +1878,27 @@ lvgl:
on_click: on_click:
- lvgl.page.show: prints_charming_page - lvgl.page.show: prints_charming_page
- label: - label:
text: SYNCING text: '%'
x: 29 x: 27
y: 94 y: 124
width: 142 width: 145
height: 22 height: 24
text_color: 11449271 text_color: 16777215
text_font: montserrat_14 text_font: montserrat_16
long_mode: DOT long_mode: DOT
gesture_bubble: true gesture_bubble: true
id: prints_charming_overview_detail id: prints_charming_overview_percent
text_align: CENTER text_align: CENTER
clickable: true clickable: true
on_click: on_click:
- lvgl.page.show: prints_charming_page - lvgl.page.show: prints_charming_page
- label: - label:
text: PrintsCharming text: PrintsCharming
x: 15 x: 19
y: 145 y: 193
width: 170 width: 161
height: 22 height: 22
text_color: 65280 text_color: 15658734
text_font: montserrat_14 text_font: montserrat_14
long_mode: DOT long_mode: DOT
gesture_bubble: true gesture_bubble: true
@@ -1884,22 +1906,37 @@ lvgl:
clickable: true clickable: true
on_click: on_click:
- lvgl.page.show: prints_charming_page - lvgl.page.show: prints_charming_page
- label:
text: --
x: 19
y: 213
width: 161
height: 22
text_color: 15658734
text_font: montserrat_14
long_mode: DOT
gesture_bubble: true
id: prints_charming_overview_finish
text_align: CENTER
clickable: true
on_click:
- lvgl.page.show: prints_charming_page
- arc: - arc:
id: polly_pocket_overview_arc id: polly_pocket_overview_arc
x: 223 x: 227
y: 8 y: 46
width: 154 width: 145
height: 154 height: 145
min_value: 0 min_value: 0
max_value: 100 max_value: 100
value: 0 value: 100
start_angle: 135 start_angle: 135
end_angle: 45 end_angle: 45
arc_width: 13 arc_width: 12
arc_color: 1647403 arc_color: 65280
indicator: indicator:
arc_color: 65280 arc_color: 65280
arc_width: 13 arc_width: 12
adjustable: false adjustable: false
gesture_bubble: true gesture_bubble: true
clickable: true clickable: true
@@ -1907,11 +1944,11 @@ lvgl:
- lvgl.page.show: polly_pocket_page - lvgl.page.show: polly_pocket_page
- label: - label:
text: -- text: --
x: 229 x: 227
y: 55 y: 90
width: 142 width: 145
height: 40 height: 40
text_color: 15658734 text_color: 16777215
text_font: montserrat_32 text_font: montserrat_32
long_mode: DOT long_mode: DOT
gesture_bubble: true gesture_bubble: true
@@ -1921,27 +1958,27 @@ lvgl:
on_click: on_click:
- lvgl.page.show: polly_pocket_page - lvgl.page.show: polly_pocket_page
- label: - label:
text: SYNCING text: '%'
x: 229 x: 227
y: 94 y: 124
width: 142 width: 145
height: 22 height: 24
text_color: 11449271 text_color: 16777215
text_font: montserrat_14 text_font: montserrat_16
long_mode: DOT long_mode: DOT
gesture_bubble: true gesture_bubble: true
id: polly_pocket_overview_detail id: polly_pocket_overview_percent
text_align: CENTER text_align: CENTER
clickable: true clickable: true
on_click: on_click:
- lvgl.page.show: polly_pocket_page - lvgl.page.show: polly_pocket_page
- label: - label:
text: Polly-Pocket text: Polly-Pocket
x: 215 x: 219
y: 145 y: 193
width: 170 width: 161
height: 22 height: 22
text_color: 65280 text_color: 15658734
text_font: montserrat_14 text_font: montserrat_14
long_mode: DOT long_mode: DOT
gesture_bubble: true gesture_bubble: true
@@ -1949,22 +1986,37 @@ lvgl:
clickable: true clickable: true
on_click: on_click:
- lvgl.page.show: polly_pocket_page - lvgl.page.show: polly_pocket_page
- label:
text: --
x: 219
y: 213
width: 161
height: 22
text_color: 15658734
text_font: montserrat_14
long_mode: DOT
gesture_bubble: true
id: polly_pocket_overview_finish
text_align: CENTER
clickable: true
on_click:
- lvgl.page.show: polly_pocket_page
- arc: - arc:
id: ds_turd_flinger_overview_arc id: ds_turd_flinger_overview_arc
x: 423 x: 427
y: 8 y: 46
width: 154 width: 145
height: 154 height: 145
min_value: 0 min_value: 0
max_value: 100 max_value: 100
value: 0 value: 100
start_angle: 135 start_angle: 135
end_angle: 45 end_angle: 45
arc_width: 13 arc_width: 12
arc_color: 1647403 arc_color: 65280
indicator: indicator:
arc_color: 65280 arc_color: 65280
arc_width: 13 arc_width: 12
adjustable: false adjustable: false
gesture_bubble: true gesture_bubble: true
clickable: true clickable: true
@@ -1972,11 +2024,11 @@ lvgl:
- lvgl.page.show: ds_turd_flinger_page - lvgl.page.show: ds_turd_flinger_page
- label: - label:
text: -- text: --
x: 429 x: 427
y: 55 y: 90
width: 142 width: 145
height: 40 height: 40
text_color: 15658734 text_color: 16777215
text_font: montserrat_32 text_font: montserrat_32
long_mode: DOT long_mode: DOT
gesture_bubble: true gesture_bubble: true
@@ -1986,27 +2038,27 @@ lvgl:
on_click: on_click:
- lvgl.page.show: ds_turd_flinger_page - lvgl.page.show: ds_turd_flinger_page
- label: - label:
text: SYNCING text: '%'
x: 429 x: 427
y: 94 y: 124
width: 142 width: 145
height: 22 height: 24
text_color: 11449271 text_color: 16777215
text_font: montserrat_14 text_font: montserrat_16
long_mode: DOT long_mode: DOT
gesture_bubble: true gesture_bubble: true
id: ds_turd_flinger_overview_detail id: ds_turd_flinger_overview_percent
text_align: CENTER text_align: CENTER
clickable: true clickable: true
on_click: on_click:
- lvgl.page.show: ds_turd_flinger_page - lvgl.page.show: ds_turd_flinger_page
- label: - label:
text: Ds-Turd-Flinger text: Ds-Turd-Flinger
x: 415 x: 419
y: 145 y: 193
width: 170 width: 161
height: 22 height: 22
text_color: 65280 text_color: 15658734
text_font: montserrat_14 text_font: montserrat_14
long_mode: DOT long_mode: DOT
gesture_bubble: true gesture_bubble: true
@@ -2014,22 +2066,37 @@ lvgl:
clickable: true clickable: true
on_click: on_click:
- lvgl.page.show: ds_turd_flinger_page - lvgl.page.show: ds_turd_flinger_page
- label:
text: --
x: 419
y: 213
width: 161
height: 22
text_color: 15658734
text_font: montserrat_14
long_mode: DOT
gesture_bubble: true
id: ds_turd_flinger_overview_finish
text_align: CENTER
clickable: true
on_click:
- lvgl.page.show: ds_turd_flinger_page
- arc: - arc:
id: jordyns_layer_slayer_overview_arc id: jordyns_layer_slayer_overview_arc
x: 623 x: 627
y: 8 y: 46
width: 154 width: 145
height: 154 height: 145
min_value: 0 min_value: 0
max_value: 100 max_value: 100
value: 0 value: 100
start_angle: 135 start_angle: 135
end_angle: 45 end_angle: 45
arc_width: 13 arc_width: 12
arc_color: 1647403 arc_color: 65280
indicator: indicator:
arc_color: 65280 arc_color: 65280
arc_width: 13 arc_width: 12
adjustable: false adjustable: false
gesture_bubble: true gesture_bubble: true
clickable: true clickable: true
@@ -2037,11 +2104,11 @@ lvgl:
- lvgl.page.show: jordyns_layer_slayer_page - lvgl.page.show: jordyns_layer_slayer_page
- label: - label:
text: -- text: --
x: 629 x: 627
y: 55 y: 90
width: 142 width: 145
height: 40 height: 40
text_color: 15658734 text_color: 16777215
text_font: montserrat_32 text_font: montserrat_32
long_mode: DOT long_mode: DOT
gesture_bubble: true gesture_bubble: true
@@ -2051,27 +2118,27 @@ lvgl:
on_click: on_click:
- lvgl.page.show: jordyns_layer_slayer_page - lvgl.page.show: jordyns_layer_slayer_page
- label: - label:
text: SYNCING text: '%'
x: 629 x: 627
y: 94 y: 124
width: 142 width: 145
height: 22 height: 24
text_color: 11449271 text_color: 16777215
text_font: montserrat_14 text_font: montserrat_16
long_mode: DOT long_mode: DOT
gesture_bubble: true gesture_bubble: true
id: jordyns_layer_slayer_overview_detail id: jordyns_layer_slayer_overview_percent
text_align: CENTER text_align: CENTER
clickable: true clickable: true
on_click: on_click:
- lvgl.page.show: jordyns_layer_slayer_page - lvgl.page.show: jordyns_layer_slayer_page
- label: - label:
text: Jordyns-Layer-Slayer text: Jordyns-Layer-Slayer
x: 615 x: 619
y: 145 y: 193
width: 170 width: 161
height: 22 height: 22
text_color: 65280 text_color: 15658734
text_font: montserrat_14 text_font: montserrat_14
long_mode: DOT long_mode: DOT
gesture_bubble: true gesture_bubble: true
@@ -2079,22 +2146,37 @@ lvgl:
clickable: true clickable: true
on_click: on_click:
- lvgl.page.show: jordyns_layer_slayer_page - lvgl.page.show: jordyns_layer_slayer_page
- label:
text: --
x: 619
y: 213
width: 161
height: 22
text_color: 15658734
text_font: montserrat_14
long_mode: DOT
gesture_bubble: true
id: jordyns_layer_slayer_overview_finish
text_align: CENTER
clickable: true
on_click:
- lvgl.page.show: jordyns_layer_slayer_page
- arc: - arc:
id: constipation_orion_overview_arc id: constipation_orion_overview_arc
x: 123 x: 127
y: 204 y: 239
width: 154 width: 145
height: 154 height: 145
min_value: 0 min_value: 0
max_value: 100 max_value: 100
value: 0 value: 100
start_angle: 135 start_angle: 135
end_angle: 45 end_angle: 45
arc_width: 13 arc_width: 12
arc_color: 1647403 arc_color: 65280
indicator: indicator:
arc_color: 65280 arc_color: 65280
arc_width: 13 arc_width: 12
adjustable: false adjustable: false
gesture_bubble: true gesture_bubble: true
clickable: true clickable: true
@@ -2102,11 +2184,11 @@ lvgl:
- lvgl.page.show: constipation_orion_page - lvgl.page.show: constipation_orion_page
- label: - label:
text: -- text: --
x: 129 x: 127
y: 251 y: 283
width: 142 width: 145
height: 40 height: 40
text_color: 15658734 text_color: 16777215
text_font: montserrat_32 text_font: montserrat_32
long_mode: DOT long_mode: DOT
gesture_bubble: true gesture_bubble: true
@@ -2116,27 +2198,27 @@ lvgl:
on_click: on_click:
- lvgl.page.show: constipation_orion_page - lvgl.page.show: constipation_orion_page
- label: - label:
text: SYNCING text: '%'
x: 129 x: 127
y: 290 y: 317
width: 142 width: 145
height: 22 height: 24
text_color: 11449271 text_color: 16777215
text_font: montserrat_14 text_font: montserrat_16
long_mode: DOT long_mode: DOT
gesture_bubble: true gesture_bubble: true
id: constipation_orion_overview_detail id: constipation_orion_overview_percent
text_align: CENTER text_align: CENTER
clickable: true clickable: true
on_click: on_click:
- lvgl.page.show: constipation_orion_page - lvgl.page.show: constipation_orion_page
- label: - label:
text: Constipation-Orion text: Constipation-Orion
x: 115 x: 119
y: 341 y: 386
width: 170 width: 161
height: 22 height: 22
text_color: 65280 text_color: 15658734
text_font: montserrat_14 text_font: montserrat_14
long_mode: DOT long_mode: DOT
gesture_bubble: true gesture_bubble: true
@@ -2144,22 +2226,37 @@ lvgl:
clickable: true clickable: true
on_click: on_click:
- lvgl.page.show: constipation_orion_page - lvgl.page.show: constipation_orion_page
- label:
text: --
x: 119
y: 406
width: 161
height: 22
text_color: 15658734
text_font: montserrat_14
long_mode: DOT
gesture_bubble: true
id: constipation_orion_overview_finish
text_align: CENTER
clickable: true
on_click:
- lvgl.page.show: constipation_orion_page
- arc: - arc:
id: centauri_carbon_overview_arc id: centauri_carbon_overview_arc
x: 323 x: 327
y: 204 y: 239
width: 154 width: 145
height: 154 height: 145
min_value: 0 min_value: 0
max_value: 100 max_value: 100
value: 0 value: 100
start_angle: 135 start_angle: 135
end_angle: 45 end_angle: 45
arc_width: 13 arc_width: 12
arc_color: 1647403 arc_color: 65280
indicator: indicator:
arc_color: 65280 arc_color: 65280
arc_width: 13 arc_width: 12
adjustable: false adjustable: false
gesture_bubble: true gesture_bubble: true
clickable: true clickable: true
@@ -2167,11 +2264,11 @@ lvgl:
- lvgl.page.show: centauri_carbon_page - lvgl.page.show: centauri_carbon_page
- label: - label:
text: -- text: --
x: 329 x: 327
y: 251 y: 283
width: 142 width: 145
height: 40 height: 40
text_color: 15658734 text_color: 16777215
text_font: montserrat_32 text_font: montserrat_32
long_mode: DOT long_mode: DOT
gesture_bubble: true gesture_bubble: true
@@ -2181,27 +2278,27 @@ lvgl:
on_click: on_click:
- lvgl.page.show: centauri_carbon_page - lvgl.page.show: centauri_carbon_page
- label: - label:
text: SYNCING text: '%'
x: 329 x: 327
y: 290 y: 317
width: 142 width: 145
height: 22 height: 24
text_color: 11449271 text_color: 16777215
text_font: montserrat_14 text_font: montserrat_16
long_mode: DOT long_mode: DOT
gesture_bubble: true gesture_bubble: true
id: centauri_carbon_overview_detail id: centauri_carbon_overview_percent
text_align: CENTER text_align: CENTER
clickable: true clickable: true
on_click: on_click:
- lvgl.page.show: centauri_carbon_page - lvgl.page.show: centauri_carbon_page
- label: - label:
text: Centauri Carbon text: Centauri Carbon
x: 315 x: 319
y: 341 y: 386
width: 170 width: 161
height: 22 height: 22
text_color: 65280 text_color: 15658734
text_font: montserrat_14 text_font: montserrat_14
long_mode: DOT long_mode: DOT
gesture_bubble: true gesture_bubble: true
@@ -2209,22 +2306,37 @@ lvgl:
clickable: true clickable: true
on_click: on_click:
- lvgl.page.show: centauri_carbon_page - lvgl.page.show: centauri_carbon_page
- label:
text: --
x: 319
y: 406
width: 161
height: 22
text_color: 15658734
text_font: montserrat_14
long_mode: DOT
gesture_bubble: true
id: centauri_carbon_overview_finish
text_align: CENTER
clickable: true
on_click:
- lvgl.page.show: centauri_carbon_page
- arc: - arc:
id: saturn_overview_arc id: saturn_overview_arc
x: 523 x: 527
y: 204 y: 239
width: 154 width: 145
height: 154 height: 145
min_value: 0 min_value: 0
max_value: 100 max_value: 100
value: 0 value: 100
start_angle: 135 start_angle: 135
end_angle: 45 end_angle: 45
arc_width: 13 arc_width: 12
arc_color: 1647403 arc_color: 65280
indicator: indicator:
arc_color: 65280 arc_color: 65280
arc_width: 13 arc_width: 12
adjustable: false adjustable: false
gesture_bubble: true gesture_bubble: true
clickable: true clickable: true
@@ -2232,11 +2344,11 @@ lvgl:
- lvgl.page.show: saturn_page - lvgl.page.show: saturn_page
- label: - label:
text: -- text: --
x: 529 x: 527
y: 251 y: 283
width: 142 width: 145
height: 40 height: 40
text_color: 15658734 text_color: 16777215
text_font: montserrat_32 text_font: montserrat_32
long_mode: DOT long_mode: DOT
gesture_bubble: true gesture_bubble: true
@@ -2246,27 +2358,27 @@ lvgl:
on_click: on_click:
- lvgl.page.show: saturn_page - lvgl.page.show: saturn_page
- label: - label:
text: SYNCING text: '%'
x: 529 x: 527
y: 290 y: 317
width: 142 width: 145
height: 22 height: 24
text_color: 11449271 text_color: 16777215
text_font: montserrat_14 text_font: montserrat_16
long_mode: DOT long_mode: DOT
gesture_bubble: true gesture_bubble: true
id: saturn_overview_detail id: saturn_overview_percent
text_align: CENTER text_align: CENTER
clickable: true clickable: true
on_click: on_click:
- lvgl.page.show: saturn_page - lvgl.page.show: saturn_page
- label: - label:
text: Saturn text: Saturn
x: 515 x: 519
y: 341 y: 386
width: 170 width: 161
height: 22 height: 22
text_color: 65280 text_color: 15658734
text_font: montserrat_14 text_font: montserrat_14
long_mode: DOT long_mode: DOT
gesture_bubble: true gesture_bubble: true
@@ -2275,17 +2387,20 @@ lvgl:
on_click: on_click:
- lvgl.page.show: saturn_page - lvgl.page.show: saturn_page
- label: - label:
text: SYNCING text: --
x: 90 x: 519
y: 404 y: 406
width: 620 width: 161
height: 22 height: 22
text_color: 11449271 text_color: 15658734
text_font: montserrat_14 text_font: montserrat_14
long_mode: DOT long_mode: DOT
gesture_bubble: true gesture_bubble: true
id: fleet_summary id: saturn_overview_finish
text_align: CENTER text_align: CENTER
clickable: true
on_click:
- lvgl.page.show: saturn_page
- button: - button:
x: 16 x: 16
y: 446 y: 446
+6 -5
View File
@@ -92,14 +92,15 @@ inline void setup() {
{'script.execute': 'fleet_refresh'}, {'delay': '300ms'}, {'script.execute': 'fleet_refresh'}, {'delay': '300ms'},
{'snapshot.take': {'id': 'panel_display', 'filename': 'fleet.bmp'}}, {'snapshot.take': {'id': 'panel_display', 'filename': 'fleet.bmp'}},
{'lambda': Lambda( {'lambda': Lambda(
'if (std::string(lv_label_get_text(id(fleet_summary))) != ' 'if (std::string(lv_label_get_text(id(fleet_clock))) == "--:--") '
+ json.dumps(f'{len(printers)} printing') '{ ESP_LOGE("preview", "Fleet clock render failed"); exit(7); }')}]
+ ') { ESP_LOGE("preview", "Fleet summary render failed"); exit(7); }')}]
for printer in printers: for printer in printers:
pid = printer['id'] pid = printer['id']
steps.append({'lambda': Lambda( steps.append({'lambda': Lambda(
f'if (std::string(lv_label_get_text(id({pid}_overview_detail))) != "PRINTING") ' f'if (std::string(lv_label_get_text(id({pid}_overview_value))) != "67" || '
f'{{ ESP_LOGE("preview", "Fleet row render failed: {pid}"); exit(7); }}')}) f'std::string(lv_label_get_text(id({pid}_overview_percent))) != "%" || '
f'std::string(lv_label_get_text(id({pid}_overview_finish))) == "--") '
f'{{ ESP_LOGE("preview", "Fleet gauge render failed: {pid}"); exit(7); }}')})
for printer in printers: for printer in printers:
steps += [{'lvgl.page.show': printer['id'] + '_page'}, steps += [{'lvgl.page.show': printer['id'] + '_page'},
{'script.execute': printer['id'] + '_refresh'}, {'delay': '300ms'}, {'script.execute': printer['id'] + '_refresh'}, {'delay': '300ms'},
+7
View File
@@ -123,6 +123,13 @@ int main() {
data.connected = false; data.connected = false;
assert(data.overview_task() == "Waiting for Home Assistant"); assert(data.overview_task() == "Waiting for Home Assistant");
assert(data.overview_meta() == "--"); assert(data.overview_meta() == "--");
data.trays = {{"A1", "PLA", "#FF8800FF", "off"}, {"A2", "PETG", "00FF00", "on"}};
assert(data.active_filament_color() == GREEN);
data.trays[1].active = "off";
data.trays[0].active = "on";
assert(data.active_filament_color() == 0xFF8800);
data.trays.clear();
assert(data.active_filament_color() == GREEN);
FleetCounts counts; FleetCounts counts;
data.connected = true; data.connected = true;
+6 -2
View File
@@ -157,14 +157,18 @@ class FleetTests(unittest.TestCase):
[printer['id'] for printer in self.printers]) [printer['id'] for printer in self.printers])
for arc, printer in zip(arcs, self.printers): for arc, printer in zip(arcs, self.printers):
self.assertEqual(arc['on_click'], [{'lvgl.page.show': printer['id'] + '_page'}]) self.assertEqual(arc['on_click'], [{'lvgl.page.show': printer['id'] + '_page'}])
self.assertEqual(arc['width'], 154) self.assertGreaterEqual(arc['width'], 120)
self.assertLessEqual(arc['width'], 154)
self.assertEqual(arc['start_angle'], 135) self.assertEqual(arc['start_angle'], 135)
self.assertLessEqual(arc['x'] + arc['width'], 800) self.assertLessEqual(arc['x'] + arc['width'], 800)
self.assertLessEqual(arc['y'] + arc['height'], 480) self.assertLessEqual(arc['y'] + arc['height'], 480)
code = next(script['then'][0]['lambda'] for script in package['script'] if script['id'] == 'fleet_refresh') code = next(script['then'][0]['lambda'] for script in package['script'] if script['id'] == 'fleet_refresh')
for printer in self.printers: for printer in self.printers:
self.assertIn(f'id({printer["id"]}_overview_arc)', code) self.assertIn(f'id({printer["id"]}_overview_arc)', code)
self.assertIn(f'id({printer["id"]}_overview_detail)', code) self.assertIn(f'id({printer["id"]}_overview_finish)', code)
titles = [next(iter(widget.values())).get('text') for widget in page['widgets']]
self.assertIn('Print Status Overview', titles)
self.assertNotIn('fleet_summary', {next(iter(widget.values())).get('id') for widget in page['widgets']})
shown = [step['if']['condition']['lvgl.page.is_showing'] for step in package['interval'][0]['then']] shown = [step['if']['condition']['lvgl.page.is_showing'] for step in package['interval'][0]['then']]
self.assertIn('fleet_page', shown) self.assertIn('fleet_page', shown)
charming = next(item for item in package['lvgl']['pages'] if item['id'] == 'prints_charming_page') charming = next(item for item in package['lvgl']['pages'] if item['id'] == 'prints_charming_page')