Fix pause/resume chain, shared print cleanup, add CLAUDE.md
- RESUME is defined only in print/pause_resume.cfg; heat_soak.cfg's duplicate replaced it (no unretract, no fan restore). It now runs HEAT_SOAK_RESUME -> _RESUME_PRINT -> RESUME_BASE. - PAUSE runs PAUSE_BASE first, then retracts and parks once (X20 Y345); a parked flag makes resume undo only what PAUSE did. - New _PRINT_CLEANUP shared by PRINT_END and CANCEL_PRINT: heaters incl. iHEATER_OFF, fan, M221 S100, bdwidth off, mesh and skew cleared. In PRINT_END it runs after RESTORE_GCODE_STATE so the flow reset sticks. - Add CLAUDE.md and tools/effective_config.py. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
eaf9c82617
commit
9dc733b5bb
7 files changed
+245
-85
No files matched your search
@@ -0,0 +1,84 @@
|
|||||||
|
# klipper-macros
|
||||||
|
|
||||||
|
Klipper macros, Klipper modules and scripts for one printer, installed on
|
||||||
|
the printer's Raspberry Pi with `install.sh` and updated through Moonraker.
|
||||||
|
See README.md for the user-facing description.
|
||||||
|
|
||||||
|
## The printer
|
||||||
|
|
||||||
|
Voron 2.4 350, Klipper + Moonraker + Mainsail on a Raspberry Pi 4
|
||||||
|
(`http://mainsailos.local`, Moonraker API on port 80). AFC Box Turtle with
|
||||||
|
5 lanes, Blobifier purge bucket, Beacon (Z homing and probing), Nitehawk-SB
|
||||||
|
toolboard (USB), Leviathan mainboard as USB-CAN bridge, bd_pressure
|
||||||
|
(load-check firmware, branch `load-check-extension` in
|
||||||
|
`D:\Claude\bd_pressure-load-check\bd_pressure`), bdwidth (measures width and
|
||||||
|
motion optically with a CCD; its motion reading is unreliable, so the purge
|
||||||
|
check runs with `motion_check: False`), iHeater chamber heater.
|
||||||
|
|
||||||
|
## Working with the printer
|
||||||
|
|
||||||
|
- Read freely through Moonraker: `GET /server/files/config/<path>`,
|
||||||
|
`/server/files/logs/klippy.log`, `/printer/objects/query?...`,
|
||||||
|
`/server/gcode_store`. The merged config Klipper loaded is in klippy.log
|
||||||
|
after `===== Config file =====`.
|
||||||
|
- Do **not** change anything on the printer (upload files, edit config, send
|
||||||
|
G-code, restart services) unless the user asks for that specific action.
|
||||||
|
Prepare files here and let the user upload them.
|
||||||
|
- Never run anything that moves the printer or heats while a print may be
|
||||||
|
running; check `print_stats.state` first.
|
||||||
|
|
||||||
|
## Repo layout
|
||||||
|
|
||||||
|
- `macros/klipper-macros.cfg` is the only file `printer.cfg` includes; it
|
||||||
|
includes everything else. On the Pi, `macros/` is linked as
|
||||||
|
`~/printer_data/config/klipper-macros/`.
|
||||||
|
- `extras/*.py` are linked into `~/klipper/klippy/extras/`.
|
||||||
|
- `scripts/` MCU firmware update scripts (printer-specific IDs).
|
||||||
|
- `tools/effective_config.py` expands the includes like Klipper and compares
|
||||||
|
the result between git refs.
|
||||||
|
|
||||||
|
## Rules for macro changes
|
||||||
|
|
||||||
|
- **Never define the same `[gcode_macro X]` in two files.** Klipper merges
|
||||||
|
sections with the same name and the later file wins completely (this is
|
||||||
|
how heat_soak.cfg's RESUME silently replaced the real RESUME). Include
|
||||||
|
order in `klipper-macros.cfg` matters for this.
|
||||||
|
- `RESUME` and `PAUSE` are defined only in `print/pause_resume.cfg`. AFC
|
||||||
|
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`.
|
||||||
|
- 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
|
||||||
|
at the end of every print goes there. `RESTORE_GCODE_STATE` restores the
|
||||||
|
flow (M221), so reset flow after it, not before.
|
||||||
|
- Inside `gcode:` use `;` for comments on G-code lines; `#` lines are
|
||||||
|
stripped by the config parser.
|
||||||
|
- 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
|
||||||
|
(`jinja2.Environment('{%', '%}', '{', '}')`) and mocked `printer` objects.
|
||||||
|
|
||||||
|
## Rules for the Python modules (`extras/`)
|
||||||
|
|
||||||
|
- Klipper only loads changed `.py` files when the **Klipper service**
|
||||||
|
restarts (`sudo systemctl restart klipper`); `RESTART` and
|
||||||
|
`FIRMWARE_RESTART` keep the old code in memory.
|
||||||
|
- Event handlers must never raise: an exception in a handler shuts Klipper
|
||||||
|
down. Example: Beacon sends `homing:home_rails_end` with `rails=[]` and a
|
||||||
|
homing state whose `get_trigger_position` raises.
|
||||||
|
- Keep them read-only wrappers where possible (look up the other module's
|
||||||
|
object, do not patch third-party files).
|
||||||
|
|
||||||
|
## Reference values
|
||||||
|
|
||||||
|
- Purge check (150 mm Blobifier purge): good load = longest pressure
|
||||||
|
13-18 s, peak 64-181; empty nozzle about 30 ms.
|
||||||
|
- XY drift check: endstop noise about 0.01-0.02 mm; limit 0.1 mm (one motor
|
||||||
|
skipping one cycle = 0.4 mm shows as 0.2 mm in X and Y).
|
||||||
|
|
||||||
|
## Git
|
||||||
|
|
||||||
|
- LF line endings everywhere (`.gitattributes`); the files run on Linux.
|
||||||
|
- Commit only when the user says so; never push without asking. Remote:
|
||||||
|
`https://mangavalk.com/mangavalk/klipper-macros.git`.
|
||||||
@@ -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 | — |
|
| `blobifier_hw.cfg` | servo and bucket switch pins | — |
|
||||||
| **print/** | | |
|
| **print/** | | |
|
||||||
| `print_start_end.cfg` | `PRINT_WARMUP`, `PRINT_START`, `PRINT_END` | Beacon, AFC, Blobifier, `HEAT_SOAK`, iHeater, bdwidth, bd_pressure PA macros |
|
| `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` | — |
|
| `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/` |
|
||||||
| `filament.cfg` | `LOAD_FILAMENT`, `UNLOAD_FILAMENT` | — |
|
| `filament.cfg` | `LOAD_FILAMENT`, `UNLOAD_FILAMENT` | — |
|
||||||
| `homing.cfg` | `HOME` | — |
|
| `homing.cfg` | `HOME` | — |
|
||||||
| `idle_timeout.cfg` | `[idle_timeout]`: heaters, chamber heater and motors off | iHeater macros |
|
| `idle_timeout.cfg` | `[idle_timeout]`: heaters, chamber heater and motors off | iHeater macros |
|
||||||
@@ -59,6 +59,14 @@ Firmware update scripts for all MCUs (Klipper and Katapult). They contain
|
|||||||
this printer's CAN UUIDs and serial IDs: see [scripts/README.md](scripts/README.md)
|
this printer's CAN UUIDs and serial IDs: see [scripts/README.md](scripts/README.md)
|
||||||
before using them on another printer.
|
before using them on another printer.
|
||||||
|
|
||||||
|
### Tools (`tools/`)
|
||||||
|
|
||||||
|
`effective_config.py` builds the config Klipper gets from
|
||||||
|
`klipper-macros.cfg` (includes expanded, duplicate sections merged) and
|
||||||
|
compares it between git refs, for example `python tools/effective_config.py HEAD`
|
||||||
|
after a change. `CLAUDE.md` has the notes for working on this repo with
|
||||||
|
Claude Code.
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
|
|
||||||
On the Klipper host:
|
On the Klipper host:
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ gcode:
|
|||||||
description: Resume while heat soaking results in the soaking phase being skipped, any complete callback is run
|
description: Resume while heat soaking results in the soaking phase being skipped, any complete callback is run
|
||||||
gcode:
|
gcode:
|
||||||
# {% set ON_RESUME = (params.ON_RESUME | default("_HEAT_SOAK__BASE_RESUME")) | string %}
|
# {% set ON_RESUME = (params.ON_RESUME | default("_HEAT_SOAK__BASE_RESUME")) | string %}
|
||||||
{% set ON_RESUME = (params.ON_RESUME | default("_HEAT_SOAK__BASE_RESUME")) | string %}
|
{% set ON_RESUME = (params.ON_RESUME | default("RESUME_BASE")) | string %}
|
||||||
{% set heat_soak = printer['gcode_macro HEAT_SOAK'] %}
|
{% set heat_soak = printer['gcode_macro HEAT_SOAK'] %}
|
||||||
{% set stage = heat_soak.stage %}
|
{% set stage = heat_soak.stage %}
|
||||||
{% if stage == "heating" %}
|
{% if stage == "heating" %}
|
||||||
@@ -133,11 +133,8 @@ gcode:
|
|||||||
{ON_RESUME} {% for p in params %}{'%s=%s ' % (p, params[p])}{% endfor %}
|
{ON_RESUME} {% for p in params %}{'%s=%s ' % (p, params[p])}{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
[gcode_macro RESUME]
|
# RESUME is defined in print/pause_resume.cfg and calls HEAT_SOAK_RESUME
|
||||||
description: Resume while heat soaking results in the soaking phase being skipped, any complete callback is run
|
# (a second [gcode_macro RESUME] here would replace that one completely).
|
||||||
rename_existing: _HEAT_SOAK__BASE_RESUME
|
|
||||||
gcode:
|
|
||||||
HEAT_SOAK_RESUME ON_RESUME=_HEAT_SOAK__BASE_RESUME
|
|
||||||
|
|
||||||
[delayed_gcode _heat_soaker]
|
[delayed_gcode _heat_soaker]
|
||||||
# description: internal macro to handle heat soaking activity
|
# description: internal macro to handle heat soaking activity
|
||||||
|
|||||||
@@ -5,9 +5,8 @@
|
|||||||
#
|
#
|
||||||
# [include klipper-macros/klipper-macros.cfg]
|
# [include klipper-macros/klipper-macros.cfg]
|
||||||
#
|
#
|
||||||
# Comment out what you do not use. Keep the order where noted: some
|
# Comment out what you do not use. Every macro is defined in exactly one
|
||||||
# macros (PAUSE, RESUME, CANCEL_PRINT) are defined in more than one file
|
# file: Klipper merges sections with the same name and the last one wins.
|
||||||
# and the last definition wins.
|
|
||||||
#####################################################################
|
#####################################################################
|
||||||
|
|
||||||
[include save_variables.cfg] # the one [save_variables] for all macros
|
[include save_variables.cfg] # the one [save_variables] for all macros
|
||||||
@@ -16,7 +15,7 @@
|
|||||||
[include blobifier/blobifier.cfg]
|
[include blobifier/blobifier.cfg]
|
||||||
|
|
||||||
# Printing
|
# Printing
|
||||||
[include print/pause_resume.cfg] # before heating/heat_soak.cfg
|
[include print/pause_resume.cfg]
|
||||||
[include print/filament.cfg]
|
[include print/filament.cfg]
|
||||||
[include print/homing.cfg]
|
[include print/homing.cfg]
|
||||||
[include print/idle_timeout.cfg]
|
[include print/idle_timeout.cfg]
|
||||||
@@ -25,7 +24,7 @@
|
|||||||
# Heating
|
# Heating
|
||||||
[include heating/bed_fans.cfg]
|
[include heating/bed_fans.cfg]
|
||||||
[include heating/chamber_iheater.cfg]
|
[include heating/chamber_iheater.cfg]
|
||||||
[include heating/heat_soak.cfg] # its RESUME wraps the one above
|
[include heating/heat_soak.cfg]
|
||||||
[include heating/soak_my_bed.cfg]
|
[include heating/soak_my_bed.cfg]
|
||||||
[include heating/filament_drying.cfg]
|
[include heating/filament_drying.cfg]
|
||||||
|
|
||||||
|
|||||||
@@ -1,44 +1,42 @@
|
|||||||
# PAUSE, RESUME, CANCEL_PRINT, M600 (based on the KlipperScreen recommended macros)
|
# 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).
|
||||||
|
|
||||||
# https://klipperscreen.readthedocs.io/en/latest/macros/#recommended
|
# https://klipperscreen.readthedocs.io/en/latest/macros/#recommended
|
||||||
[gcode_macro PAUSE]
|
[gcode_macro PAUSE]
|
||||||
description: Pause the actual running print
|
description: Pause the actual running print
|
||||||
rename_existing: PAUSE_BASE
|
rename_existing: PAUSE_BASE
|
||||||
variable_saved_fan_speed: 0.0
|
variable_saved_fan_speed: 0.0
|
||||||
|
variable_parked: False # set by PAUSE, used by _RESUME_PRINT
|
||||||
gcode:
|
gcode:
|
||||||
# SAVE_GCODE_STATE NAME=PAUSE_MACRO_state
|
{% if not printer.pause_resume.is_paused %}
|
||||||
# Save current fan speed
|
SET_GCODE_VARIABLE MACRO=PAUSE VARIABLE=saved_fan_speed VALUE={printer.fan.speed}
|
||||||
{% set current_fan = printer.fan.speed %}
|
# Pause first, so the saved state is the print position, then retract and park
|
||||||
SET_GCODE_VARIABLE MACRO=PAUSE VARIABLE=saved_fan_speed VALUE={current_fan}
|
PAUSE_BASE
|
||||||
|
_TOOLHEAD_PARK_PAUSE_CANCEL
|
||||||
# Current position
|
SET_GCODE_VARIABLE MACRO=PAUSE VARIABLE=parked VALUE=True
|
||||||
{% set x = printer.toolhead.position.x|float %}
|
# Set fan to S28 (28/255 ≈ 0.1098)
|
||||||
{% set y = printer.toolhead.position.y|float %}
|
M106 S28
|
||||||
|
{% else %}
|
||||||
# Determine target positions
|
PAUSE_BASE
|
||||||
{% set target_x = 340 if (x < 340 or x > 350) else x %}
|
|
||||||
{% set target_y = 340 if (y < 340 or y > 350) else y %}
|
|
||||||
|
|
||||||
# Only move if needed
|
|
||||||
{% if target_x != x or target_y != y %}
|
|
||||||
G90
|
|
||||||
G1 X{target_x} Y{target_y} F12000
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
# Pause print
|
|
||||||
PAUSE_BASE
|
|
||||||
|
|
||||||
_TOOLHEAD_PARK_PAUSE_CANCEL
|
|
||||||
# Set fan to S28 (28/255 ≈ 0.1098)
|
|
||||||
M106 S28
|
|
||||||
|
|
||||||
[gcode_macro RESUME]
|
[gcode_macro RESUME]
|
||||||
description: Resume the actual running print
|
description: Resume the print (while HEAT_SOAK runs: skip the soak phase)
|
||||||
rename_existing: RESUME_BASE
|
rename_existing: RESUME_BASE
|
||||||
variable_skip_restore: 0
|
|
||||||
gcode:
|
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
|
||||||
|
gcode:
|
||||||
|
{% set pause = printer["gcode_macro PAUSE"] %}
|
||||||
{% set extrude = printer['gcode_macro _TOOLHEAD_PARK_PAUSE_CANCEL'].extrude %}
|
{% set extrude = printer['gcode_macro _TOOLHEAD_PARK_PAUSE_CANCEL'].extrude %}
|
||||||
{% set skip = printer['gcode_macro RESUME'].skip_restore|int %}
|
|
||||||
#### get VELOCITY parameter if specified ####
|
#### get VELOCITY parameter if specified ####
|
||||||
{% if 'VELOCITY' in params|upper %}
|
{% if 'VELOCITY' in params|upper %}
|
||||||
{% set get_params = ('VELOCITY=' + params.VELOCITY) %}
|
{% set get_params = ('VELOCITY=' + params.VELOCITY) %}
|
||||||
@@ -46,40 +44,28 @@ gcode:
|
|||||||
{% set get_params = "" %}
|
{% set get_params = "" %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
##### end of definitions #####
|
##### end of definitions #####
|
||||||
{% if printer.extruder.can_extrude|lower == 'true' %}
|
# Only undo what PAUSE did; HEAT_SOAK pauses with PAUSE_BASE (no retract, no park)
|
||||||
M83
|
{% if pause.parked %}
|
||||||
G1 E{extrude} F2100
|
{% if printer.extruder.can_extrude|lower == 'true' %}
|
||||||
{% if printer.gcode_move.absolute_extrude |lower == 'true' %} M82 {% endif %}
|
M83
|
||||||
{% else %}
|
G1 E{extrude} F2100
|
||||||
{action_respond_info("Extruder not hot enough")}
|
{% if printer.gcode_move.absolute_extrude |lower == 'true' %} M82 {% endif %}
|
||||||
{% endif %}
|
{% else %}
|
||||||
|
{action_respond_info("Extruder not hot enough")}
|
||||||
#BLOBIFIER_CLEAN
|
{% endif %}
|
||||||
#G1 Z10
|
|
||||||
|
|
||||||
# Restore saved fan speed
|
# Restore saved fan speed
|
||||||
{% set old_fan = printer["gcode_macro PAUSE"].saved_fan_speed %}
|
{% set old_fan = pause.saved_fan_speed %}
|
||||||
{% if old_fan > 0 %}
|
{% if old_fan > 0 %}
|
||||||
{% set fan_pwm = (old_fan * 255) | int %}
|
M106 S{[(old_fan * 255)|int, 255]|min}
|
||||||
{% if fan_pwm > 255 %}
|
{% else %}
|
||||||
{% set fan_pwm = 255 %}
|
|
||||||
{% endif %}
|
|
||||||
M106 S{fan_pwm}
|
|
||||||
{% else %}
|
|
||||||
M107
|
M107
|
||||||
|
{% endif %}
|
||||||
|
SET_GCODE_VARIABLE MACRO=PAUSE VARIABLE=parked VALUE=False
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if skip == 0 %}
|
RESUME_BASE {get_params}
|
||||||
# RESTORE_GCODE_STATE name=PAUSE_MACRO_state
|
|
||||||
RESUME_BASE {get_params}
|
|
||||||
{% else %}
|
|
||||||
RESPOND PREFIX="AFC" MSG="Skipping RESTORE_GCODE_STATE (drift resume)"
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
_status_printing
|
_status_printing
|
||||||
CLEAR_PAUSE
|
|
||||||
RESET_FAILURE
|
|
||||||
SET_GCODE_VARIABLE MACRO=RESUME VARIABLE=skip_restore VALUE=0
|
|
||||||
|
|
||||||
[gcode_macro _TOOLHEAD_PARK_PAUSE_CANCEL]
|
[gcode_macro _TOOLHEAD_PARK_PAUSE_CANCEL]
|
||||||
description: Helper: park toolhead used in PAUSE and CANCEL_PRINT
|
description: Helper: park toolhead used in PAUSE and CANCEL_PRINT
|
||||||
@@ -129,12 +115,12 @@ gcode:
|
|||||||
_TOOLHEAD_PARK_PAUSE_CANCEL
|
_TOOLHEAD_PARK_PAUSE_CANCEL
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
STOP_HEAT_SOAK
|
STOP_HEAT_SOAK
|
||||||
|
|
||||||
TURN_OFF_HEATERS
|
|
||||||
CANCEL_PRINT_BASE_KLIPPERSCREEN
|
CANCEL_PRINT_BASE_KLIPPERSCREEN
|
||||||
|
# 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]
|
[gcode_macro M600]
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ gcode:
|
|||||||
|
|
||||||
[gcode_macro _NOTHING]
|
[gcode_macro _NOTHING]
|
||||||
gcode:
|
gcode:
|
||||||
_HEAT_SOAK__BASE_RESUME
|
RESUME_BASE
|
||||||
|
|
||||||
[gcode_macro PRINT_START]
|
[gcode_macro PRINT_START]
|
||||||
gcode:
|
gcode:
|
||||||
@@ -220,8 +220,6 @@ gcode:
|
|||||||
|
|
||||||
_motion_detected
|
_motion_detected
|
||||||
|
|
||||||
M221 S100
|
|
||||||
|
|
||||||
M400 ; wait for buffer to clear
|
M400 ; wait for buffer to clear
|
||||||
G92 E0 ; zero the extruder
|
G92 E0 ; zero the extruder
|
||||||
# G1 E-0.5 F1800 ; retract filament
|
# G1 E-0.5 F1800 ; retract filament
|
||||||
@@ -234,21 +232,27 @@ gcode:
|
|||||||
G0 X{x_safe} Y{y_safe} Z{z_safe} F20000 ; move nozzle to remove stringing
|
G0 X{x_safe} Y{y_safe} Z{z_safe} F20000 ; move nozzle to remove stringing
|
||||||
G0 X{th.axis_maximum.x//2} Y{th.axis_maximum.y - 5} F3600 ; park nozzle at rear
|
G0 X{th.axis_maximum.x//2} Y{th.axis_maximum.y - 5} F3600 ; park nozzle at rear
|
||||||
M107 ; turn off fan
|
M107 ; turn off fan
|
||||||
|
|
||||||
{% if printer.pause_resume.is_paused|lower == 'false' and park|lower == 'true'%}
|
|
||||||
_TOOLHEAD_PARK_PAUSE_CANCEL
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
SET_BDWIDTH NAME=fila_width_0 COMMAND=DISABLE ;disable the bdwidth
|
|
||||||
|
|
||||||
#SET_PIN PIN=caselight VALUE=0.03
|
#SET_PIN PIN=caselight VALUE=0.03
|
||||||
_status_part_ready
|
_status_part_ready
|
||||||
|
|
||||||
UPDATE_DELAYED_GCODE ID=_delayed_motors_off DURATION=3600
|
UPDATE_DELAYED_GCODE ID=_delayed_motors_off DURATION=3600
|
||||||
|
|
||||||
|
RESTORE_GCODE_STATE NAME=STATE_PRINT_END
|
||||||
|
# After the restore: RESTORE_GCODE_STATE also restores the flow (M221)
|
||||||
|
_PRINT_CLEANUP
|
||||||
|
|
||||||
|
# End-of-print cleanup shared by PRINT_END and CANCEL_PRINT
|
||||||
|
[gcode_macro _PRINT_CLEANUP]
|
||||||
|
description: Heaters (incl. chamber heater) and part fan off, flow back to 100%, bdwidth off, mesh and skew cleared
|
||||||
|
gcode:
|
||||||
|
TURN_OFF_HEATERS
|
||||||
|
iHEATER_OFF ; stops the chamber heater control loop too
|
||||||
|
M107
|
||||||
|
SET_BDWIDTH NAME=fila_width_0 COMMAND=DISABLE ; also sets M221 S100
|
||||||
|
M221 S100
|
||||||
BED_MESH_CLEAR
|
BED_MESH_CLEAR
|
||||||
SET_SKEW CLEAR=1
|
SET_SKEW CLEAR=1
|
||||||
RESTORE_GCODE_STATE NAME=STATE_PRINT_END
|
|
||||||
|
|
||||||
[delayed_gcode _delayed_motors_off]
|
[delayed_gcode _delayed_motors_off]
|
||||||
gcode:
|
gcode:
|
||||||
|
|||||||
@@ -0,0 +1,82 @@
|
|||||||
|
"""Show or compare the config Klipper builds from macros/klipper-macros.cfg.
|
||||||
|
|
||||||
|
Klipper expands [include ...] in order and merges sections with the same
|
||||||
|
name (the last value of an option wins). This script does the same, so a
|
||||||
|
refactor can be checked for unintended changes.
|
||||||
|
|
||||||
|
python tools/effective_config.py list sections of the working tree
|
||||||
|
python tools/effective_config.py HEAD compare HEAD with the working tree
|
||||||
|
python tools/effective_config.py A B compare two git refs
|
||||||
|
python tools/effective_config.py HEAD -v also print old/new values
|
||||||
|
"""
|
||||||
|
import configparser
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
BASE = os.path.join('macros', 'klipper-macros.cfg')
|
||||||
|
|
||||||
|
|
||||||
|
def expand(path):
|
||||||
|
lines = []
|
||||||
|
with open(path, encoding='utf-8') as f:
|
||||||
|
for line in f.read().replace('\r\n', '\n').split('\n'):
|
||||||
|
m = re.match(r'^\[include ([^\]]+)\]', line.split('#')[0])
|
||||||
|
if m:
|
||||||
|
inc = os.path.join(os.path.dirname(path), m.group(1).strip())
|
||||||
|
lines += expand(inc)
|
||||||
|
else:
|
||||||
|
lines.append(line)
|
||||||
|
return lines
|
||||||
|
|
||||||
|
|
||||||
|
def load(root):
|
||||||
|
cp = configparser.RawConfigParser(strict=False,
|
||||||
|
inline_comment_prefixes=(';', '#'))
|
||||||
|
cp.read_string('\n'.join(expand(os.path.join(root, BASE))))
|
||||||
|
return {s: dict(cp.items(s)) for s in cp.sections()}
|
||||||
|
|
||||||
|
|
||||||
|
def checkout(ref, tmp):
|
||||||
|
archive = subprocess.run(['git', '-C', ROOT, 'archive', ref, 'macros'],
|
||||||
|
check=True, capture_output=True).stdout
|
||||||
|
subprocess.run(['tar', '-x', '-C', tmp], input=archive, check=True)
|
||||||
|
return tmp
|
||||||
|
|
||||||
|
|
||||||
|
def main(argv):
|
||||||
|
verbose = '-v' in argv
|
||||||
|
refs = [a for a in argv if a != '-v']
|
||||||
|
with tempfile.TemporaryDirectory() as t1, tempfile.TemporaryDirectory() as t2:
|
||||||
|
if not refs:
|
||||||
|
for s in sorted(load(ROOT)):
|
||||||
|
print(s)
|
||||||
|
return 0
|
||||||
|
old = load(checkout(refs[0], t1))
|
||||||
|
new = load(checkout(refs[1], t2) if len(refs) > 1 else ROOT)
|
||||||
|
added, removed = sorted(set(new) - set(old)), sorted(set(old) - set(new))
|
||||||
|
changed = 0
|
||||||
|
for s in added:
|
||||||
|
print('added ', s)
|
||||||
|
for s in removed:
|
||||||
|
print('removed ', s)
|
||||||
|
for s in sorted(set(old) & set(new)):
|
||||||
|
keys = sorted(k for k in set(old[s]) | set(new[s])
|
||||||
|
if old[s].get(k) != new[s].get(k))
|
||||||
|
if keys:
|
||||||
|
changed += 1
|
||||||
|
print('changed ', s, keys)
|
||||||
|
if verbose:
|
||||||
|
for k in keys:
|
||||||
|
print(' old %s: %r' % (k, old[s].get(k)))
|
||||||
|
print(' new %s: %r' % (k, new[s].get(k)))
|
||||||
|
print('%d sections, %d added, %d removed, %d changed'
|
||||||
|
% (len(new), len(added), len(removed), changed))
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
sys.exit(main(sys.argv[1:]))
|
||||||
Reference in new issue
Block a user