# PAUSE, RESUME, CANCEL_PRINT, M600 (based on the KlipperScreen recommended macros) # # Chain on this printer (AFC renames PAUSE/RESUME at startup): # PAUSE -> AFC_PAUSE (saves position, z-hop) -> this PAUSE -> PAUSE_BASE # RESUME -> AFC_RESUME -> this RESUME -> HEAT_SOAK_RESUME -> _RESUME_PRINT # -> 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. # Before that it checks the AFC lane: PAUSE stores the lane the print needs # (the lane AFC was loading when a tool change failed, otherwise the loaded # lane), and RESUME stops with an error when another lane (or none) is loaded. # RESUME LANE_CHECK=0 resumes anyway (e.g. after remapping with SET_MAP). # https://klipperscreen.readthedocs.io/en/latest/macros/#recommended [gcode_macro PAUSE] description: Pause the actual running print rename_existing: PAUSE_BASE variable_saved_fan_speed: 0.0 variable_parked: False # set by PAUSE, used by _RESUME_PRINT variable_expected_lane: '' # AFC lane the print needs after RESUME ('' = no check) gcode: {% if not printer.pause_resume.is_paused %} # AFC sets next_lane during a tool change and still has it when a failed # change pauses the print; it clears it once CHANGE_TOOL returns {% if 'AFC' in printer %} {% set lane = printer.AFC.next_lane or printer.AFC.current_load or '' %} SET_GCODE_VARIABLE MACRO=PAUSE VARIABLE=expected_lane VALUE="'{lane}'" {% endif %} SET_GCODE_VARIABLE MACRO=PAUSE VARIABLE=saved_fan_speed VALUE={printer.fan.speed} # Pause first, so the saved state is the print position, then retract and park PAUSE_BASE _TOOLHEAD_PARK_PAUSE_CANCEL SET_GCODE_VARIABLE MACRO=PAUSE VARIABLE=parked VALUE=True # Set fan to S28 (28/255 ≈ 0.1098) M106 S28 {% else %} PAUSE_BASE {% endif %} [gcode_macro RESUME] description: Resume the print (while HEAT_SOAK runs: skip the soak phase) rename_existing: RESUME_BASE gcode: HEAT_SOAK_RESUME ON_RESUME=_RESUME_PRINT {rawparams} [gcode_macro _RESUME_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) %} {%else %} {% set get_params = "" %} {% endif %} ##### end of definitions ##### # Only undo what PAUSE did; HEAT_SOAK pauses with PAUSE_BASE (no retract, no park) {% if pause.parked %} _RESUME_LANE_CHECK {'LANE_CHECK=%s' % params.LANE_CHECK if 'LANE_CHECK' in params else ''} {% if printer.extruder.can_extrude|lower == 'true' %} {% 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 %} # Restore saved fan speed {% set old_fan = pause.saved_fan_speed %} {% if old_fan > 0 %} M106 S{[(old_fan * 255)|int, 255]|min} {% else %} M107 {% endif %} SET_GCODE_VARIABLE MACRO=PAUSE VARIABLE=parked VALUE=False SET_GCODE_VARIABLE MACRO=PAUSE VARIABLE=expected_lane VALUE="''" {% endif %} RESUME_BASE {get_params} _status_printing # Raising an error aborts the whole RESUME like a failed purge check: the # printer stays paused and the next RESUME checks again. [gcode_macro _RESUME_LANE_CHECK] description: Stop the resume when AFC has another lane loaded than the one the print needs gcode: {% set expected = printer["gcode_macro PAUSE"].expected_lane %} {% if expected and 'AFC' in printer and params.LANE_CHECK|default(1)|int %} {% set loaded = printer.AFC.current_load %} {% if loaded != expected %} {% set obj = 'AFC_stepper ' ~ expected %} {% set tool = printer[obj].map if obj in printer else '?' %} {action_raise_error("Lane check: the print needs %s (%s) but %s is loaded. Load %s with %s, then RESUME again (RESUME LANE_CHECK=0 resumes anyway)." % (expected, tool, loaded or 'no lane', expected, tool))} {% endif %} RESPOND MSG="Lane check: {expected} loaded, OK" {% endif %} [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 gcode: ##### set park positon for x and y ##### # default is your max posion from your printer.cfg # {% set x_park = printer.toolhead.axis_maximum.x|float - 5.0 %} {% set x_park = 20.0 %} {% set y_park = printer.toolhead.axis_maximum.y|float - 5.0 %} {% set z_park_delta = 2.0 %} ##### calculate save lift position ##### {% set max_z = printer.toolhead.axis_maximum.z|float %} {% set act_z = printer.toolhead.position.z|float %} {% if act_z < (max_z - z_park_delta) %} {% set z_safe = z_park_delta %} {% else %} {% set z_safe = max_z - act_z %} {% endif %} ##### end of definitions ##### {% if printer.extruder.can_extrude|lower == 'true' %} M83 G1 E-{extrude} F2100 {% if printer.gcode_move.absolute_extrude |lower == 'true' %} M82 {% endif %} {% else %} {action_respond_info("Extruder not hot enough")} {% endif %} {% if "xyz" in printer.toolhead.homed_axes %} G91 G1 Z{z_safe} F900 G90 G1 X{x_park} Y{y_park} F6000 {% if printer.gcode_move.absolute_coordinates|lower == 'false' %} G91 {% endif %} {% else %} {action_respond_info("Printer not homed")} {% endif %} [gcode_macro CANCEL_PRINT] description: Cancel the actual running print rename_existing: CANCEL_PRINT_BASE_KLIPPERSCREEN variable_park: True gcode: {% set pause = printer["gcode_macro PAUSE"] %} {% set park_retract = printer['gcode_macro _TOOLHEAD_PARK_PAUSE_CANCEL'].extrude %} ## Move head and retract only if not already in the pause state and park set to true {% if printer.pause_resume.is_paused|lower == 'false' and park|lower == 'true'%} _TOOLHEAD_PARK_PAUSE_CANCEL {% endif %} STOP_HEAT_SOAK CANCEL_PRINT_BASE_KLIPPERSCREEN # Same end-of-print retract as PRINT_END (skipped if the nozzle is already cold); # EXTRA: the park retract of PAUSE or of the park above, so PRINT_START undoes it too {% if printer.pause_resume.is_paused %} _NOZZLE_RETRACT EXTRA={park_retract if pause.parked else 0} {% elif park and printer.extruder.can_extrude %} _NOZZLE_RETRACT EXTRA={park_retract} {% else %} _NOZZLE_RETRACT {% endif %} # Same cleanup as PRINT_END: heaters incl. chamber heater, fan, flow, bdwidth _PRINT_CLEANUP SET_GCODE_VARIABLE MACRO=PAUSE VARIABLE=parked VALUE=False _status_ready [gcode_macro M600] # # M600 # https://github.com/simplisticton/common-macros/tree/main # # Mimic Marlin's Pause for filament change command description: Pause for filament change gcode: PAUSE M117 Paused M118 Print paused for filament change... type "Resume" to continue