Show errors and warnings on the display (_ERROR, _WARN)

action_raise_error aborts while the macro renders, so an M117 in the same
macro never ran and errors such as the RESUME lane check only reached the
console. messages.cfg adds _ERROR (M117, then raise in a separate macro)
and _WARN (RESPOND TYPE=error + M117); all errors and warnings use them.
PAUSE shows AFC's error as the pause reason; RESUME, CANCEL_PRINT and
PRINT_WARMUP clear the display.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
mangavalkandClaude Opus 5.5 committed 2026-10-16 17:41:41 +02:00
1 parent a67e99015f
commit fbdb2d5e1d
11 files changed
+78 -29

No files matched your search

+1 -1
View File
@@ -162,7 +162,7 @@ gcode:
{% set verdict = 'FAIL: ' ~ failed|join(', ') if failed else ('OK' if checked else 'NOTHING CHECKED') %}
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"
_WARN MSG="PURGE_CHECK: {lane} {failed|join(', ')} - check extruder and lane" DISPLAY="Purge check failed: {lane}, paused"
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 %}
+7 -7
View File
@@ -49,13 +49,13 @@ gcode:
{% set min_temp = printer.configfile.settings.extruder.min_extrude_temp|float %}
{% set temp = params.TEMP|default([printer.extruder.target, 0]|max)|float %}
{% if 'bdpressure_check' not in printer %}
{action_raise_error("PURGE_UNTIL_EMPTY: needs bdpressure_check.py and [bdpressure_check]")}
_ERROR MSG="PURGE_UNTIL_EMPTY: needs bdpressure_check.py and [bdpressure_check]"
{% elif printer.print_stats.state == "printing" %}
{action_raise_error("PURGE_UNTIL_EMPTY: printer is printing, pause the print first")}
_ERROR MSG="PURGE_UNTIL_EMPTY: printer is printing, pause the print first"
{% elif "xyz" not in printer.toolhead.homed_axes %}
{action_raise_error("PURGE_UNTIL_EMPTY: home the printer first")}
_ERROR MSG="PURGE_UNTIL_EMPTY: home the printer first"
{% elif temp < min_temp %}
{action_raise_error("PURGE_UNTIL_EMPTY: give the filament temperature, e.g. PURGE_UNTIL_EMPTY TEMP=240")}
_ERROR MSG="PURGE_UNTIL_EMPTY: give the filament temperature, e.g. PURGE_UNTIL_EMPTY TEMP=240" DISPLAY="PURGE_UNTIL_EMPTY: give TEMP=..."
{% else %}
BDP_CHECK_QUERY
_PURGE_UNTIL_EMPTY_RUN MAX={max_purges} LENGTH={length} UNSYNC={unsync} TEMP={temp}
@@ -65,7 +65,7 @@ gcode:
[gcode_macro _PURGE_UNTIL_EMPTY_RUN]
gcode:
{% if not printer.bdpressure_check.available %}
{action_raise_error("PURGE_UNTIL_EMPTY: bd_pressure load-check firmware not found")}
_ERROR MSG="PURGE_UNTIL_EMPTY: bd_pressure load-check firmware not found" DISPLAY="PURGE_UNTIL_EMPTY: no bd_pressure"
{% endif %}
SET_GCODE_VARIABLE MACRO=PURGE_UNTIL_EMPTY VARIABLE=done VALUE=0
SET_GCODE_VARIABLE MACRO=PURGE_UNTIL_EMPTY VARIABLE=count VALUE=0
@@ -105,7 +105,7 @@ gcode:
{% set p = printer.bdpressure_check %}
{% set n = cfg.count + 1 %}
{% if not p.available %}
{action_raise_error("PURGE_UNTIL_EMPTY: lost the bd_pressure load-check reading, stopped. bdwidth runout response may still be off: SET_FILAMENT_SENSOR SENSOR=<bdwidth name> ENABLE=1")}
_ERROR MSG="PURGE_UNTIL_EMPTY: lost the bd_pressure load-check reading, stopped. bdwidth runout response may still be off: SET_FILAMENT_SENSOR SENSOR=<bdwidth name> ENABLE=1" DISPLAY="PURGE_UNTIL_EMPTY: lost bd_pressure, stopped"
{% endif %}
{% set empty = p.longest_ms < cfg.empty_ms %}
SET_GCODE_VARIABLE MACRO=PURGE_UNTIL_EMPTY VARIABLE=count VALUE={n}
@@ -123,5 +123,5 @@ gcode:
{% if cfg.done %}
RESPOND MSG="PURGE_UNTIL_EMPTY: no more filament after {cfg.count} purge{'s' if cfg.count != 1 else ''}. The last bit between the extruder gears and the nozzle is pushed out by the next load."
{% else %}
RESPOND TYPE=error MSG="PURGE_UNTIL_EMPTY: still pressure after {params.MAX} purges. The lane may still be feeding, or the nozzle is blocked - check before running it again."
_WARN MSG="PURGE_UNTIL_EMPTY: still pressure after {params.MAX} purges. The lane may still be feeding, or the nozzle is blocked - check before running it again." DISPLAY="PURGE_UNTIL_EMPTY: still pressure, check lane and nozzle"
{% endif %}
+2 -3
View File
@@ -53,11 +53,10 @@ gcode:
{% endif %}
G1 X{th.axis_maximum.x - 10} Y{th.axis_maximum.y - 10} F5000
{% elif cfg.soft_fail|int == 1 %}
RESPOND TYPE=error MSG="AFC: XY drift detected! X={'%.3f' % d.x} Y={'%.3f' % d.y} mm. Axes are re-homed, print PAUSED. Run AFC_XY_RESUME to continue, or CANCEL_PRINT."
M117 AFC: XY drift! See console. Paused.
_WARN MSG="AFC: XY drift detected! X={'%.3f' % d.x} Y={'%.3f' % d.y} mm. Axes are re-homed, print PAUSED. Run AFC_XY_RESUME to continue, or CANCEL_PRINT." DISPLAY="AFC: XY drift! See console. Paused."
PAUSE
{% else %}
RESPOND TYPE=error MSG="AFC: XY drift X={'%.3f' % d.x} Y={'%.3f' % d.y} mm -> M112"
_WARN MSG="AFC: XY drift X={'%.3f' % d.x} Y={'%.3f' % d.y} mm -> M112"
M112
{% endif %}
+3 -3
View File
@@ -291,9 +291,9 @@ gcode:
# ======================================================================================
{% if "xyz" not in printer.toolhead.homed_axes %}
RESPOND MSG="BLOBIFIER: Not homed! Home xyz before blobbing"
_WARN MSG="BLOBIFIER: Not homed! Home xyz before blobbing"
{% elif printer.quad_gantry_level and printer.quad_gantry_level.applied == False %}
RESPOND MSG="BLOBIFIER: QGL not applied! run quad_gantry_level before blobbing"
_WARN MSG="BLOBIFIER: QGL not applied! run quad_gantry_level before blobbing"
{% else %}
# Part cooling fan
@@ -780,7 +780,7 @@ gcode:
{% set position_x = bl.skew_correction %}
{% if "xyz" not in printer.toolhead.homed_axes %}
{action_raise_error("BLOBIFIER: Not homed. Home xyz first")}
_ERROR MSG="BLOBIFIER: Not homed. Home xyz first"
{% endif %}
SET_GCODE_VARIABLE MACRO=_BLOBIFIER_COUNT VARIABLE=last_shake VALUE={count.current_blobs}
+1
View File
@@ -12,6 +12,7 @@
#####################################################################
[include save_variables.cfg] # the one [save_variables] for all macros
[include messages.cfg] # _ERROR, _WARN: errors and warnings also on the display
# Blobifier purge bucket (Turtleblobifier for AFC, modified)
[include blobifier/blobifier.cfg]
+32
View File
@@ -0,0 +1,32 @@
# Errors and warnings that also show on the display (M117: the status line in
# Mainsail and KlipperScreen, display_status.message)
#
# action_raise_error aborts while the macro is rendered, before any of its
# G-code runs, so an M117 in the same macro never shows. _ERROR sends the
# M117 first and raises the error in a separate macro: the display keeps the
# text and the calling macros are aborted as with action_raise_error.
#
# _ERROR MSG="full text for the console" DISPLAY="short text"
# _WARN MSG="full text for the console" DISPLAY="short text"
#
# DISPLAY defaults to MSG. No double quotes in either (they end the
# parameter). Nothing after an _ERROR in the calling macro runs, but
# anything that macro does while rendering (action_respond_info, ...) has
# already happened: put the rest in an else branch.
[gcode_macro _ERROR]
description: Show DISPLAY (default MSG) on the display, then raise MSG as an error (aborts the calling macros)
gcode:
M117 {params.DISPLAY|default(params.MSG)}
_RAISE_ERROR MSG="{params.MSG}"
[gcode_macro _RAISE_ERROR]
description: Helper for _ERROR: raise MSG as an error
gcode:
{action_raise_error(params.MSG)}
[gcode_macro _WARN]
description: Show MSG as an error line in the console and DISPLAY (default MSG) on the display, without stopping
gcode:
RESPOND TYPE=error MSG="{params.MSG}"
M117 {params.DISPLAY|default(params.MSG)}
+5 -8
View File
@@ -361,7 +361,7 @@ gcode:
SAVE_VARIABLE VARIABLE=pa_lane_{lane}_spool_id VALUE={spool_id}
{action_respond_info("Tracked lane %s -> spool_id %d" % (lane, spool_id))}
{% else %}
{action_raise_error("_PA_TRACK_LANE_SPOOL: LANE parameter required")}
_ERROR MSG="_PA_TRACK_LANE_SPOOL: LANE parameter required"
{% endif %}
@@ -404,14 +404,12 @@ gcode:
{% set cfg = printer["gcode_macro _PA_CFG"] %}
{% set vars = printer.save_variables.variables %}
{% if lane == "" %}
{action_raise_error("LANE_CALIBRATE_PA: LANE parameter required")}
{% endif %}
{% set lane_varname = "pa_lane_" ~ lane ~ "_spool_id" %}
{% set spool_id = vars[lane_varname]|default(0)|int if lane_varname in vars else 0 %}
{% if spool_id == 0 %}
{% if lane == "" %}
_ERROR MSG="LANE_CALIBRATE_PA: LANE parameter required"
{% elif spool_id == 0 %}
{action_respond_info("LANE_CALIBRATE_PA: no spool_id recorded for %s yet. Run SET_SPOOL_ID LANE=%s SPOOL_ID=<id> then _PA_TRACK_LANE_SPOOL LANE=%s SPOOL_ID=<id>." % (lane, lane, lane))}
{% else %}
{% set pa_varname = "pa_value_spool_" ~ spool_id %}
@@ -506,9 +504,8 @@ gcode:
# A cached value at the end of the scan is an earlier failed run, not a PA
{% set use_cache = cache_found and cached_pa < cfg.sweep_end_pa|float - 0.0001 %}
{% set keep = cached_pa if use_cache else cfg.fallback_pa|float %}
RESPOND TYPE=error MSG="PA calibration for {lane} (spool {spool_id}) rejected: {problems|join('; ')}. Nothing saved; using PA={'%.4f' % keep} ({'cached' if use_cache else 'fallback'}). Fix the cause, then LANE_CALIBRATE_PA LANE={lane} FORCE=1"
_WARN MSG="PA calibration for {lane} (spool {spool_id}) rejected: {problems|join('; ')}. Nothing saved; using PA={'%.4f' % keep} ({'cached' if use_cache else 'fallback'}). Fix the cause, then LANE_CALIBRATE_PA LANE={lane} FORCE=1" DISPLAY="PA cal rejected: {lane}, see console"
SET_PRESSURE_ADVANCE ADVANCE={keep}
M117 PA cal rejected: {lane}
{% else %}
{action_respond_info("Calibration complete for %s: PA=%.4f" % (lane, new_pa))}
M117 PA cal done: {new_pa|round(4)}
+17 -5
View File
@@ -29,6 +29,12 @@ gcode:
{% 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}'"
# AFC pauses after an error: show its first line. Pauses from these
# macros set their own display text before calling PAUSE.
{% set afc_msg = printer.AFC.message|default({}) %}
{% if printer.AFC.error_state and afc_msg.type|default('') == 'error' and afc_msg.message|default('') %}
M117 Paused: {afc_msg.message.split('\n')[0]|trim}
{% endif %}
{% 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
@@ -85,13 +91,16 @@ gcode:
{% endif %}
SET_GCODE_VARIABLE MACRO=PAUSE VARIABLE=parked VALUE=False
SET_GCODE_VARIABLE MACRO=PAUSE VARIABLE=expected_lane VALUE="''"
# Clear the pause reason from the display (no comment on an M117 line: it would show)
M117
{% 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.
# Raising an error (_ERROR, also shown on the display) 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:
@@ -101,9 +110,10 @@ gcode:
{% 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))}
_ERROR MSG="Lane check: the print needs {expected} ({tool}) but {loaded or 'no lane'} is loaded. Load {expected} with {tool}, then RESUME again (RESUME LANE_CHECK=0 resumes anyway)." DISPLAY="Lane check: load {expected} with {tool}, then RESUME"
{% else %}
RESPOND MSG="Lane check: {expected} loaded, OK"
{% endif %}
RESPOND MSG="Lane check: {expected} loaded, OK"
{% endif %}
[gcode_macro _RESUME_PURGE]
@@ -124,7 +134,7 @@ gcode:
[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).")}
_ERROR MSG="Purge check failed: the print stays paused. Check the extruder and lane, then RESUME again (RESUME PURGE=0 resumes without purging)." DISPLAY="Purge check failed: still paused, see console"
{% endif %}
[gcode_macro _TOOLHEAD_PARK_PAUSE_CANCEL]
@@ -191,6 +201,8 @@ gcode:
# Same cleanup as PRINT_END: heaters incl. chamber heater, fan, flow, bdwidth
_PRINT_CLEANUP
SET_GCODE_VARIABLE MACRO=PAUSE VARIABLE=parked VALUE=False
# Clear a pause reason from the display
M117
_status_ready
[gcode_macro M600]
+3 -1
View File
@@ -26,6 +26,8 @@ gcode:
RESET_FAILURE
CLEAR_PAUSE
# Clear what an earlier print or error left on the display
M117
_motion_detected
@@ -299,7 +301,7 @@ gcode:
RESTORE_GCODE_STATE NAME=_nozzle_unretract
SAVE_VARIABLE VARIABLE=nozzle_retract VALUE=0
{% else %}
RESPOND TYPE=error MSG="_NOZZLE_UNRETRACT: extruder too cold, {done} mm still retracted"
_WARN MSG="_NOZZLE_UNRETRACT: extruder too cold, {done} mm still retracted"
{% endif %}
{% endif %}