diff --git a/CLAUDE.md b/CLAUDE.md index 3fad1cb..161478f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -51,6 +51,9 @@ detection, `filament_error_sensitivity`), iHeater chamber heater. renames PAUSE/RESUME at startup and wraps them: `PAUSE -> AFC_PAUSE -> PAUSE -> PAUSE_BASE`, `RESUME -> AFC_RESUME -> RESUME -> HEAT_SOAK_RESUME -> _RESUME_PRINT -> RESUME_BASE`. + After a PAUSE, `_RESUME_PRINT` first purges with `BLOBIFIER_CHECKED` + (`_RESUME_PURGE`); a failed check raises an error, which aborts the whole + chain (AFC_RESUME's restore too), so the printer stays paused. - Only one `[save_variables]`, in `macros/save_variables.cfg`. - `PRINT_END` and `CANCEL_PRINT` share `_PRINT_CLEANUP` (heaters including `iHEATER_OFF`, fan, `M221 S100`, bdwidth off). Anything that must happen diff --git a/README.md b/README.md index d1e1f24..697e895 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ everything below, grouped by topic. Comment out what you do not use there. | `blobifier_hw.cfg` | servo and bucket switch pins | — | | **print/** | | | | `print_start_end.cfg` | `PRINT_WARMUP`, `PRINT_START`, `PRINT_END` | Beacon, AFC, Blobifier, `HEAT_SOAK`, iHeater, bdwidth, bd_pressure PA macros | -| `pause_resume.cfg` | `PAUSE`, `RESUME`, `CANCEL_PRINT`, `M600` (RESUME also handles a running `HEAT_SOAK`; CANCEL_PRINT runs the same cleanup as `PRINT_END`) | `heating/heat_soak.cfg`, `leds/` | +| `pause_resume.cfg` | `PAUSE`, `RESUME`, `CANCEL_PRINT`, `M600` (RESUME also handles a running `HEAT_SOAK`, and after a PAUSE purges 40 mm with `BLOBIFIER_CHECKED` first: a failed check keeps the print paused, `RESUME PURGE=0` skips the purge; CANCEL_PRINT runs the same cleanup as `PRINT_END`) | `heating/heat_soak.cfg`, `leds/`, `blobifier/`, `afc/purge_check.cfg` | | `filament.cfg` | `LOAD_FILAMENT`, `UNLOAD_FILAMENT` | — | | `homing.cfg` | `HOME` | — | | `idle_timeout.cfg` | `[idle_timeout]`: heaters, chamber heater and motors off | iHeater macros | diff --git a/macros/afc/purge_check.cfg b/macros/afc/purge_check.cfg index b1f14ca..687e8ed 100644 --- a/macros/afc/purge_check.cfg +++ b/macros/afc/purge_check.cfg @@ -49,6 +49,7 @@ variable_pressure_min_ms: 5000 # placeholder: longest continuous pressure needed variable_bdwidth_warmup_ms: 15000 variable_start_counts: 0 variable_start_e: 0.0 +variable_last_failed: False # last check failed in enforce mode (read by _RESUME_PURGE_VERIFY) gcode: [gcode_macro BLOBIFIER_CHECKED] @@ -150,6 +151,7 @@ gcode: RESPOND MSG="PURGE_CHECK {lane}: {motion}; {press} -> {verdict}" {% if failed and cfg.mode == "enforce" %} RESPOND TYPE=error MSG="PURGE_CHECK: {lane} {failed|join(', ')} - check extruder and lane" - PAUSE + SET_GCODE_VARIABLE MACRO=_PURGE_CHECK_CFG VARIABLE=last_failed VALUE=True + PAUSE ; no effect while already paused (resume purge): see _RESUME_PURGE_VERIFY {% endif %} {% endif %} diff --git a/macros/print/pause_resume.cfg b/macros/print/pause_resume.cfg index b7908fa..216ce35 100644 --- a/macros/print/pause_resume.cfg +++ b/macros/print/pause_resume.cfg @@ -6,6 +6,10 @@ # -> RESUME_BASE, then AFC restores the saved position # RESUME is defined only here: heating/heat_soak.cfg used to define its own, # which replaced this one completely (no unretract, no fan restore). +# After a PAUSE, _RESUME_PRINT purges into the Blobifier with the purge check +# (BLOBIFIER_CHECKED, afc/purge_check.cfg) before going back to the print, so +# the nozzle is primed and clean. If the check fails the resume stops with an +# error and the printer stays paused. RESUME PURGE=0 resumes without the purge. # https://klipperscreen.readthedocs.io/en/latest/macros/#recommended [gcode_macro PAUSE] @@ -33,10 +37,12 @@ gcode: HEAT_SOAK_RESUME ON_RESUME=_RESUME_PRINT {rawparams} [gcode_macro _RESUME_PRINT] -description: Resume after PAUSE: unretract, restore the part fan, continue the print +description: Resume after PAUSE: purge and check (or unretract), restore the part fan, continue the print +variable_purge_length: 40 # mm purged before resuming after a PAUSE; 0 = only unretract gcode: {% set pause = printer["gcode_macro PAUSE"] %} {% set extrude = printer['gcode_macro _TOOLHEAD_PARK_PAUSE_CANCEL'].extrude %} + {% set purge = params.PURGE|default(purge_length)|float %} #### get VELOCITY parameter if specified #### {% if 'VELOCITY' in params|upper %} {% set get_params = ('VELOCITY=' + params.VELOCITY) %} @@ -47,9 +53,13 @@ gcode: # Only undo what PAUSE did; HEAT_SOAK pauses with PAUSE_BASE (no retract, no park) {% if pause.parked %} {% if printer.extruder.can_extrude|lower == 'true' %} - M83 - G1 E{extrude} F2100 - {% if printer.gcode_move.absolute_extrude |lower == 'true' %} M82 {% endif %} + {% if purge > 0 and 'gcode_macro BLOBIFIER' in printer %} + _RESUME_PURGE LENGTH={purge} ; also replaces the unretract; stops here if the check fails + {% else %} + M83 + G1 E{extrude} F2100 + {% if printer.gcode_move.absolute_extrude |lower == 'true' %} M82 {% endif %} + {% endif %} {% else %} {action_respond_info("Extruder not hot enough")} {% endif %} @@ -67,6 +77,27 @@ gcode: RESUME_BASE {get_params} _status_printing +[gcode_macro _RESUME_PURGE] +description: Purge LENGTH mm into the Blobifier (with the purge check if installed) before resuming +gcode: + {% if 'gcode_macro BLOBIFIER_CHECKED' in printer %} + SET_GCODE_VARIABLE MACRO=_PURGE_CHECK_CFG VARIABLE=last_failed VALUE=False + BLOBIFIER_CHECKED PURGE_LENGTH={params.LENGTH} + _RESUME_PURGE_VERIFY + {% else %} + BLOBIFIER PURGE_LENGTH={params.LENGTH} + {% endif %} + +# Separate macro so the check result is read after the purge. Raising an +# error aborts the whole RESUME (AFC_RESUME included): the printer stays +# paused at the bucket and PAUSE.parked stays set, so the next RESUME purges +# and checks again. +[gcode_macro _RESUME_PURGE_VERIFY] +gcode: + {% if printer["gcode_macro _PURGE_CHECK_CFG"].last_failed %} + {action_raise_error("Purge check failed: the print stays paused. Check the extruder and lane, then RESUME again (RESUME PURGE=0 resumes without purging).")} + {% endif %} + [gcode_macro _TOOLHEAD_PARK_PAUSE_CANCEL] description: Helper: park toolhead used in PAUSE and CANCEL_PRINT variable_extrude: 2.0