diff --git a/CLAUDE.md b/CLAUDE.md index ae3e987..d7df929 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -64,7 +64,12 @@ detection, `filament_error_sensitivity`), iHeater chamber heater. (remembered in the saved variable `nozzle_retract`); `PRINT_START` undoes it over the bucket with `_NOZZLE_UNRETRACT`. - Inside `gcode:` use `;` for comments on G-code lines; `#` lines are - stripped by the config parser. + stripped by the config parser. Never put a comment on an `M117` line: + M117 shows the raw rest of the line, comment included. +- Errors and warnings go through `_ERROR` / `_WARN` (`macros/messages.cfg`), + not `action_raise_error` / `RESPOND TYPE=error`, so they also show on the + display. `action_raise_error` aborts while rendering, so an `M117` in the + same macro would never run. No double quotes in `MSG`/`DISPLAY`. - After a refactor run `python tools/effective_config.py HEAD` and check that only the intended sections changed. - Render-test macros with Jinja2 using Klipper's delimiters diff --git a/README.md b/README.md index dc40b7e..46c361c 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ everything below, grouped by topic. Comment out what you do not use there. | File | Macros | Needs | |---|---|---| | `save_variables.cfg` | the one `[save_variables]` for all macros (file `bd_pa_variables.cfg` in the config folder) | — | +| `messages.cfg` | `_ERROR`, `_WARN`: errors and warnings shown in the console and on the display (M117, the status line in Mainsail and KlipperScreen); PAUSE shows AFC's error, RESUME, CANCEL_PRINT and PRINT_WARMUP clear the display | — | | **blobifier/** | | | | `blobifier.cfg` | `BLOBIFIER`, `BLOBIFIER_CLEAN`, `BLOBIFIER_PARK`, `BLOBIFIER_SHAKE_BUCKET`, ...: purge bucket and nozzle brush for AFC (Turtleblobifier, heavily modified) | Blobifier hardware, AFC | | `blobifier_hw.cfg` | servo and bucket switch pins | — | diff --git a/macros/afc/purge_check.cfg b/macros/afc/purge_check.cfg index c1707b5..3b81258 100644 --- a/macros/afc/purge_check.cfg +++ b/macros/afc/purge_check.cfg @@ -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 %} diff --git a/macros/afc/purge_until_empty.cfg b/macros/afc/purge_until_empty.cfg index 4ff8d4b..f177fa3 100644 --- a/macros/afc/purge_until_empty.cfg +++ b/macros/afc/purge_until_empty.cfg @@ -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= 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= 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 %} diff --git a/macros/afc/xy_safety_check.cfg b/macros/afc/xy_safety_check.cfg index 9495074..e3f847b 100644 --- a/macros/afc/xy_safety_check.cfg +++ b/macros/afc/xy_safety_check.cfg @@ -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 %} diff --git a/macros/blobifier/blobifier.cfg b/macros/blobifier/blobifier.cfg index 46da6a7..6835bb9 100644 --- a/macros/blobifier/blobifier.cfg +++ b/macros/blobifier/blobifier.cfg @@ -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} diff --git a/macros/klipper-macros.cfg b/macros/klipper-macros.cfg index f6d4a61..cdd8924 100644 --- a/macros/klipper-macros.cfg +++ b/macros/klipper-macros.cfg @@ -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] diff --git a/macros/messages.cfg b/macros/messages.cfg new file mode 100644 index 0000000..682d9f0 --- /dev/null +++ b/macros/messages.cfg @@ -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)} diff --git a/macros/pressure_advance/bd_pa_spoolman.cfg b/macros/pressure_advance/bd_pa_spoolman.cfg index 19b27ad..5e35960 100644 --- a/macros/pressure_advance/bd_pa_spoolman.cfg +++ b/macros/pressure_advance/bd_pa_spoolman.cfg @@ -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= then _PA_TRACK_LANE_SPOOL LANE=%s SPOOL_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)} diff --git a/macros/print/pause_resume.cfg b/macros/print/pause_resume.cfg index f98e758..c589c46 100644 --- a/macros/print/pause_resume.cfg +++ b/macros/print/pause_resume.cfg @@ -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] diff --git a/macros/print/print_start_end.cfg b/macros/print/print_start_end.cfg index f34b1bf..bccfa87 100644 --- a/macros/print/print_start_end.cfg +++ b/macros/print/print_start_end.cfg @@ -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 %}