2026-10-10 15:20:28 +02:00
|
|
|
# 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
|
2026-10-12 18:18:40 +02:00
|
|
|
`D:\Claude\bd_pressure-load-check\bd_pressure`), bdwidth (CCD width/motion sensor on USB; switched off: its motion reading
|
|
|
|
|
stays at 0, its width compensation made the flow jump 77-119% and a USB
|
|
|
|
|
dropout once shut down Klipper. The macros work with or without
|
|
|
|
|
`[bdwidth fila_width_0]`; clogs and breaks are caught by AFC's buffer fault
|
2026-10-11 20:31:43 +02:00
|
|
|
detection, `filament_error_sensitivity`), iHeater chamber heater.
|
2026-10-10 15:20:28 +02:00
|
|
|
|
|
|
|
|
## 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
|
2026-10-10 15:28:52 +02:00
|
|
|
includes everything else. It must be included after `[include AFC/*.cfg]`
|
|
|
|
|
(a `rename_existing` of an AFC command only works if AFC loaded first).
|
|
|
|
|
On the Pi, `macros/` is linked as `~/printer_data/config/klipper-macros/`
|
|
|
|
|
and `scripts/` as `~/printer_data/config/klipper-macros-scripts/`.
|
2026-10-10 15:20:28 +02:00
|
|
|
- `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`.
|
2026-10-12 14:08:53 +02:00
|
|
|
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.
|
2026-10-10 15:20:28 +02:00
|
|
|
- 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.
|
2026-10-11 15:01:55 +02:00
|
|
|
- Do not use `G10`/`G11` in macros: Klipper's `G10` retracts only once until
|
|
|
|
|
a `G11`, and nothing on this printer sends `G11`. Use `_NOZZLE_RETRACT`
|
|
|
|
|
(remembered in the saved variable `nozzle_retract`); `PRINT_START` undoes
|
|
|
|
|
it over the bucket with `_NOZZLE_UNRETRACT`.
|
2026-10-10 15:20:28 +02:00
|
|
|
- Inside `gcode:` use `;` for comments on G-code lines; `#` lines are
|
2026-10-16 17:41:41 +02:00
|
|
|
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`.
|
2026-10-18 22:39:26 +02:00
|
|
|
- Nozzle guard (`print/nozzle_guard.cfg`, `extras/bdp_guard.py`): wrap only
|
|
|
|
|
moves where nothing may touch the nozzle in `_GUARD_ON PHASE=x` /
|
|
|
|
|
`_GUARD_OFF`. Never leave it on across contact homing, extrusion, purges,
|
|
|
|
|
the Blobifier park or AFC cuts and loads: in `mode: stop` that is an
|
|
|
|
|
instant shutdown.
|
2026-10-10 15:20:28 +02:00
|
|
|
- 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
|
2026-10-19 15:20:02 +02:00
|
|
|
13-18 s, peak 64-246 (ASA at 250-260C peaks highest); empty nozzle
|
|
|
|
|
about 30 ms. A real failed load in a
|
2026-10-18 23:11:02 +02:00
|
|
|
print start (AFC reported the lane loaded, nothing reached the nozzle):
|
|
|
|
|
longest 1915 ms, peak 45, caught by the 5000 ms limit.
|
2026-10-18 23:25:28 +02:00
|
|
|
- Nozzle guard (bdp_guard): peaks 1-8 in home_xy, QGL, Z homing, mesh and
|
|
|
|
|
the Z check; the brush scrub 47 (4 reads above 30 in a row, so it runs
|
|
|
|
|
in log mode); a light finger push on the cold nozzle gives 41
|
|
|
|
|
(threshold 30).
|
2026-10-18 23:11:02 +02:00
|
|
|
- Z check after a contact homing: Beacon vs Klipper Z about 0.06 mm.
|
2026-10-10 15:20:28 +02:00
|
|
|
- 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`.
|