mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-09-30 03:01:21 +02:00
fix(notifications): defer first-layer photo until printer is actually printing (#1837)
P1S and other Bambu printers tick layer_num during the pre-print calibration
sequence (homing -> auto bed leveling -> bed-surface scan -> nozzle clean ->
purge / wipe), so a bare `2 <= layer_num <= 5` gate fires the first-layer
notification minutes before the first real extrusion. The attached photo
shows a lowered bed, parked toolhead, and a clean plate -- exactly the
state during PREPARE, not after layer 1.
The reporter's log timeline made it explicit:
- 13:54:27 PRINT START detected
- 14:10:13 [SNAPSHOT] Capturing fresh frame (notification fires here)
- 14:44:28 gcode_state: RUNNING (debug log, only visible because they
enabled debug logging mid-print)
So the notification went out ~30 minutes before the print actually started.
Fix in main.py:6043 -- the on_layer_change first-layer block now requires
both:
- state.state == "RUNNING" (gcode_state is RUNNING, not PREPARE)
- state.mc_print_sub_stage in (None, 0)
(0 = "Printing" in the canonical STAGE_NAMES at bambu_mqtt.py:376;
None preserved as a no-opinion fall-through for any firmware that
doesn't push the sub-stage so unknown-firmware installs keep
their existing behaviour)
_first_layer_notified is only set after the gate passes, so calibration
ticks are non-consuming -- the next on_layer_change edge fires the
notification once the printer is actually printing.
The trigger window widens from [2, 5] to [2, 10] so that if calibration
consumed several layer_num slots before RUNNING, the deferred edge
still falls inside. The RUNNING + sub-stage gate ensures we don't fire
on a stale layer count.
This commit is contained in:
+17
-4
@@ -6040,8 +6040,23 @@ async def lifespan(app: FastAPI):
|
||||
|
||||
await tl_layer_change(printer_id, layer_num)
|
||||
|
||||
# First layer complete notification (layer_num >= 2 means layer 1 is done)
|
||||
if 2 <= layer_num <= 5 and not _first_layer_notified.get(printer_id, False):
|
||||
# First layer complete notification (layer_num >= 2 means layer 1 is done).
|
||||
# Gate on actual printing state — Bambu firmware ticks layer_num during
|
||||
# the pre-print calibration sequence (homing / mesh-level / bed scan /
|
||||
# nozzle clean), so a bare layer_num check can fire minutes before the
|
||||
# first real extrusion. We require gcode_state == RUNNING and
|
||||
# mc_print_sub_stage in (0 = "Printing", None) so calibration sub-stages
|
||||
# (1, 9, 14, ...) are excluded. The window widens to [2, 10] because if
|
||||
# the layer counter advanced past 2 during PREPARE, the next on_layer_change
|
||||
# edge fires later; _first_layer_notified stays clear until we actually send
|
||||
# so a deferred re-evaluation can win. See issue #1837.
|
||||
if 2 <= layer_num <= 10 and not _first_layer_notified.get(printer_id, False):
|
||||
client = printer_manager.get_client(printer_id)
|
||||
state = client.state if client else None
|
||||
if not state or state.state != "RUNNING":
|
||||
return
|
||||
if state.mc_print_sub_stage not in (None, 0):
|
||||
return
|
||||
_first_layer_notified[printer_id] = True
|
||||
try:
|
||||
async with async_session() as db:
|
||||
@@ -6052,8 +6067,6 @@ async def lifespan(app: FastAPI):
|
||||
if not printer:
|
||||
return
|
||||
printer_name = printer.name
|
||||
client = printer_manager.get_client(printer_id)
|
||||
state = client.state if client else None
|
||||
filename = (state.subtask_name or state.gcode_file or "Unknown") if state else "Unknown"
|
||||
total_layers = state.total_layers if state else 0
|
||||
|
||||
|
||||
Reference in New Issue
Block a user