Skip to content

spoolman: add per-tool spool tracking for multi-tool printers#1059

Open
goeland86 wants to merge 4 commits intoArksine:masterfrom
goeland86:master
Open

spoolman: add per-tool spool tracking for multi-tool printers#1059
goeland86 wants to merge 4 commits intoArksine:masterfrom
goeland86:master

Conversation

@goeland86
Copy link
Copy Markdown

Replace the single spool_id with a tool-indexed map to support StealthChanger, IDEX, and MMU setups. Each tool gets independent spool assignment and filament usage tracking.

Changes:

  • Replace spool_id attribute with _tool_spool_map dict + backward-compatible spool_id property (returns tool 0)
  • Add toolchanger discovery on klippy_ready with extruder name fallback
  • Per-tool _highest_epos watermarks for correct extrusion attribution across tool changes
  • API endpoints (GET/POST /server/spoolman/spool_id) accept optional tool parameter (default 0)
  • GET /server/spoolman/status response includes tool_spool_map
  • spoolman:active_spool_set notification includes tool field
  • History tracking via tool_spool_map auxiliary field
  • Spool deletion iterates full tool map (clears all tools using deleted spool)
  • DB migration from legacy single spoolman.spool_id key to spoolman.tool_spool_map; both keys maintained for rollback safety

Backward compatibility:

  • All changes are opt-in via the tool parameter; existing single-tool setups work identically
  • Legacy DB key continues to be written alongside the new format
  • spool_id property returns tool 0's spool for code that reads it directly

Tests:

  • 54 new unit tests covering: tool-spool map CRUD, backward-compat property, extrusion attribution across tool changes, extruder discovery parsing, spool deletion handling, GET/POST API endpoints, DB persistence with string key serialization, legacy migration, and historyreset callbacks — all for both single-tool and multi-tool scenarios

Fixes #1057

Signed-off-by: Jon Charnas goeland86@gmail.com

goeland86 and others added 3 commits March 17, 2026 09:00
Replace single spool_id with a tool-indexed map to support
StealthChanger, IDEX, and MMU setups. Each tool gets independent
spool assignment and filament usage tracking.

- Replace spool_id attr with _tool_spool_map + backward-compat property
- Add toolchanger discovery on klippy_ready with extruder fallback
- Per-tool _highest_epos watermarks for extrusion attribution
- API endpoints accept optional tool param (default 0)
- Status response includes tool_spool_map
- Notifications include tool field
- History tracking via tool_spool_map auxiliary field
- Spool deletion iterates full tool map
- DB migration from legacy single spool key

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Jon Charnas <goeland86@gmail.com>
Test tool-spool map CRUD, backward-compat spool_id property, extrusion
attribution across tool changes, extruder discovery, spool deletion
handling, API endpoints, DB persistence, migration, and history
callbacks. 54 tests covering single and multi-tool scenarios.

Signed-off-by: Jon Charnas <goeland86@gmail.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
WebRequest.get_int() does not accept None as a default. Use
web_request.get() with manual int conversion for the optional
tool parameter on GET requests.

Signed-off-by: Jon Charnas <goeland86@gmail.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@Arksine
Copy link
Copy Markdown
Owner

Arksine commented Mar 17, 2026

Thanks. Before I get into a detailed code review there are a couple of high level issues that we need to work out.

Maintaining compatibility with existing workflows

It appears to me that this could potentially break existing flows for filament changes in multi-extruder setups. If the user issues set_active_spool(<spool_id>) to change the current spool ID then only tool 0 will ever be changed, resulting in incorrect tracking for any other extruder. That said, I believe we could overcome this by setting all tracked spools to the requested spool ID when the tool is omitted rather than just tool 0.

Moonraker can't depend on APIs or printer objects that are not included in the official repo

This may be the bigger issue. We can't refer to objects or APIs on forks and/or modifications to Klipper. The potential for breakage and/or maintenance issues is too high. I can't reliably be sure that the modification will be maintained in sync with the current Klipper repo and I can't be sure that Klipper won't at some point in the future add a printer object with the same name. I also don't want to open up the can of worms that would exist when authors of other mods want to integrate directly with Moonraker.

If its possible to rewrite this with only dependencies on current hardcoded Klipper objects I will be open to the changes. Otherwise this could be revisited if MMU/Toolchanger support is merged in the official repo.

Edit: In addition, I just noticed that this PR includes AI generated code. I'm not sure yet what my policy will be on this, as we just started having these discussions. I may limit it to tests, analysis, and docs only. I may open it up to Moonraker's source with the caveat that only prior contributors that have demonstrated a working knowledge of the code base can depend on generative AI tools. There are potential licensing issues with AI generated code that need to be discussed, and ultimately I would like Moonraker (and Katapult) to have a policy that is consistent with Klipper.

@goeland86
Copy link
Copy Markdown
Author

So I thought I'd double checked single tool use-case, but I hadn't looked in detail at a multiplexing system. My main goal was for tool changer/IDEX support. So I'll see what tests I can run since I don't have an AMS-like system yet.

Regarding the unofficial printer objects, I'll try to refactor it as best I can. Is there a way to create moonraker add-ons that aren't independent services? If it's better to rework it in that way I'm happy to do so if refactoring proves impractical.

Regarding AI-generated code, I fully understand your concerns. I write C++ for a living, and I've worked a long time on the Recore's embedded image project as well. Grappling with licensing is something I'm quite familiar with, and I won't push you one way or another on that stance, but what I will say is that it's a lot less of a legal hurdle for open source projects than closed-source. It becomes primarily a matter of attribution, which the LLM in question may be able to properly trace.

If the code generated passes muster, both in real-world and unit-test cases, I see value in the output. I have been checking and re-directing Claude on a lot of points, regarding functionality as well as architecture, even if I'm not the most competent python programmer.

1. When tool is omitted from set_active_spool() or the POST API,
   apply the spool to ALL currently tracked tools instead of just
   tool 0. This preserves backward compatibility with existing
   filament-change workflows that call set_active_spool(spool_id)
   without specifying a tool.

2. Remove toolchanger dependency (_discover_toolchanger_tools and
   _handle_toolchanger_update). Tool discovery now relies solely
   on standard Klipper extruder objects (extruder, extruder1, etc.)
   which are part of the official Klipper repo.

Signed-off-by: Jon Charnas <goeland86@gmail.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add per-tool spool tracking for multi-tool printers

2 participants