feat: Spoolman filament tracking integration #65

Merged
viewit merged 5 commits from p2l/KX-Bridge-Release:feature/spoolman into master 2026-06-23 14:16:41 +02:00
Contributor

Adds optional Spoolman integration for live filament consumption tracking, mirroring what Moonraker's built-in [spoolman] support does for Klipper printers.

How it works

The printer reports a supplies_usage field in every print/report MQTT message — a cumulative extrusion counter in mm, reset each print. This was discovered during development by logging raw MQTT payloads and cross-checking against the slicer's own estimate (within ~1%). It is the direct equivalent of Klipper's print_stats.filament_used and gives accurate consumption for both completed and cancelled prints with no estimation needed.

Filament length is reported to Spoolman via PUT /api/v1/spool/{id}/use with use_length (mm), letting Spoolman convert to weight using the spool's own filament profile density.

Config

Add to config.ini:

[spoolman]
server = http://192.168.x.x:7912
sync_rate = 0  # mid-print sync interval in seconds (0 = end of print only)

Or via env vars: SPOOLMAN_SERVER, SPOOLMAN_SYNC_RATE.

UI

  • The filament assignment dialog (shown before each print) gains a Spoolman section: one spool dropdown per assigned AMS slot, populated from the Spoolman spool list. Hidden when Spoolman is not configured.
  • The AMS slot display shows a 🧵 #N badge on any slot that has a mapped spool.
  • Assignments persist across prints.

New API endpoints

Method Path Description
GET /kx/spoolman/status configured flag, server URL, current slot→spool map
GET /kx/spoolman/spools spool list proxied from Spoolman
POST /kx/spoolman/active-spool body: {"slot_map": {"0": 42}}

Notes

  • The purge/prime sequence the printer runs before each print is included in supplies_usage and therefore in the Spoolman report — this matches Moonraker's behaviour.

Known limitation: multi-colour filament split

For multi-slot (multi-colour) prints, supplies_usage is a single aggregate counter, so the current implementation splits total consumption equally across all mapped spools.

Moonraker does not need to approximate here: Klipper tracks each extruder motor independently, so each spool receives its real measured value.

However, the data to do this properly is already in the MQTT stream. multiColorBox/report exposes loaded_slot — which slot is currently loaded in the toolhead — and this changes each time the AMS switches during a multi-colour print. By accumulating supplies_usage deltas against the loaded_slot value at each poll tick (every ~3 seconds), per-slot consumption can be tracked with only small inaccuracy at tool-change boundaries. The feed_status field even signals when a loading/unloading transition is in progress, which could be used to pause accumulation during purges to avoid attributing them to the wrong slot.

This incremental per-slot tracking is the intended improvement path for a follow-up, and would bring multi-colour accuracy close to what Klipper provides.

Adds optional [Spoolman](https://github.com/Donkie/Spoolman) integration for live filament consumption tracking, mirroring what Moonraker's built-in `[spoolman]` support does for Klipper printers. ## How it works The printer reports a `supplies_usage` field in every `print/report` MQTT message — a cumulative extrusion counter in mm, reset each print. This was discovered during development by logging raw MQTT payloads and cross-checking against the slicer's own estimate (within ~1%). It is the direct equivalent of Klipper's `print_stats.filament_used` and gives accurate consumption for both completed and cancelled prints with no estimation needed. Filament length is reported to Spoolman via `PUT /api/v1/spool/{id}/use` with `use_length` (mm), letting Spoolman convert to weight using the spool's own filament profile density. ## Config Add to `config.ini`: ```ini [spoolman] server = http://192.168.x.x:7912 sync_rate = 0 # mid-print sync interval in seconds (0 = end of print only) ``` Or via env vars: `SPOOLMAN_SERVER`, `SPOOLMAN_SYNC_RATE`. ## UI - The filament assignment dialog (shown before each print) gains a **Spoolman section**: one spool dropdown per assigned AMS slot, populated from the Spoolman spool list. Hidden when Spoolman is not configured. - The AMS slot display shows a 🧵 #N badge on any slot that has a mapped spool. - Assignments persist across prints. ## New API endpoints | Method | Path | Description | |---|---|---| | GET | `/kx/spoolman/status` | configured flag, server URL, current slot→spool map | | GET | `/kx/spoolman/spools` | spool list proxied from Spoolman | | POST | `/kx/spoolman/active-spool` | body: `{"slot_map": {"0": 42}}` | ## Notes - The purge/prime sequence the printer runs before each print is included in `supplies_usage` and therefore in the Spoolman report — this matches Moonraker's behaviour. ## Known limitation: multi-colour filament split For multi-slot (multi-colour) prints, `supplies_usage` is a single aggregate counter, so the current implementation splits total consumption equally across all mapped spools. Moonraker does not need to approximate here: Klipper tracks each extruder motor independently, so each spool receives its real measured value. However, the data to do this properly is already in the MQTT stream. `multiColorBox/report` exposes `loaded_slot` — which slot is currently loaded in the toolhead — and this changes each time the AMS switches during a multi-colour print. By accumulating `supplies_usage` deltas against the `loaded_slot` value at each poll tick (every ~3 seconds), per-slot consumption can be tracked with only small inaccuracy at tool-change boundaries. The `feed_status` field even signals when a loading/unloading transition is in progress, which could be used to pause accumulation during purges to avoid attributing them to the wrong slot. This incremental per-slot tracking is the intended improvement path for a follow-up, and would bring multi-colour accuracy close to what Klipper provides.
p2l added 2 commits 2026-06-18 21:44:24 +02:00
- Raise FileNotFoundError with clear message when TLS certs are missing
  rather than a cryptic SSL error
- Use getaddrinfo(AF_INET) before create_connection to force IPv4 and
  avoid dual-stack resolution failures on some networks
- Comment out hardcoded PRINTER_IP in bridge.sh

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds optional Spoolman (https://github.com/Donkie/Spoolman) integration
for live filament consumption tracking.

Config (config.ini [spoolman] section or env vars):
  SPOOLMAN_SERVER    = http://192.168.x.x:7912
  SPOOLMAN_SYNC_RATE = 30   # mid-print sync interval in seconds (0=end only)

How it works:
- Uses supplies_usage from the printer's own MQTT print/report payload —
  the printer's cumulative extrusion counter in mm, reset each print.
  Discovered via MQTT payload inspection: matches slicer estimate within
  ~1% for model filament, and also captures the printer's purge/prime
  sequence that the slicer doesn't count.
- Reports to Spoolman via PUT /api/v1/spool/{id}/use with use_length (mm),
  letting Spoolman convert to weight using the spool's filament profile.
- Accurate for both completed and cancelled prints — no estimation needed.
- For multi-slot prints, total filament is split equally across mapped spools
  (v1 approximation; per-slot MQTT breakdown not available).

UI changes:
- Filament assignment dialog gains a Spoolman section (hidden when not
  configured): one spool dropdown per assigned AMS slot, loaded async
  from GET /kx/spoolman/spools.
- AMS slot display shows a 🧵 #N badge on any slot with a mapped spool.
- Spool assignments persist across prints (sticky until changed).

New API endpoints:
  GET  /kx/spoolman/status        — configured flag, server URL, slot map
  GET  /kx/spoolman/spools        — spool list proxied from Spoolman
  POST /kx/spoolman/active-spool  — body: {"slot_map": {"0": 42, "1": 17}}

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
p2l added 2 commits 2026-06-18 21:50:35 +02:00
Adds optional Spoolman (https://github.com/Donkie/Spoolman) integration
for live filament consumption tracking.

Config (config.ini [spoolman] section or env vars):
  SPOOLMAN_SERVER    = http://192.168.x.x:7912
  SPOOLMAN_SYNC_RATE = 30   # mid-print sync interval in seconds (0=end only)

How it works:
- Uses supplies_usage from the printer's own MQTT print/report payload —
  the printer's cumulative extrusion counter in mm, reset each print.
  Discovered via MQTT payload inspection: matches slicer estimate within
  ~1% for model filament, and also captures the printer's purge/prime
  sequence that the slicer doesn't count.
- Reports to Spoolman via PUT /api/v1/spool/{id}/use with use_length (mm),
  letting Spoolman convert to weight using the spool's filament profile.
- Accurate for both completed and cancelled prints — no estimation needed.
- For multi-slot prints, total filament is split equally across mapped spools
  (v1 approximation; per-slot MQTT breakdown not available).

UI changes:
- Filament assignment dialog gains a Spoolman section (hidden when not
  configured): one spool dropdown per assigned AMS slot, loaded async
  from GET /kx/spoolman/spools.
- AMS slot display shows a 🧵 #N badge on any slot with a mapped spool.
- Spool assignments persist across prints (sticky until changed).

New API endpoints:
  GET  /kx/spoolman/status        — configured flag, server URL, slot map
  GET  /kx/spoolman/spools        — spool list proxied from Spoolman
  POST /kx/spoolman/active-spool  — body: {"slot_map": {"0": 42, "1": 17}}

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds optional Spoolman (https://github.com/Donkie/Spoolman) integration
for live filament consumption tracking.

Config (config.ini [spoolman] section or env vars):
  SPOOLMAN_SERVER    = http://192.168.x.x:7912
  SPOOLMAN_SYNC_RATE = 30   # mid-print sync interval in seconds (0=end only)

How it works:
- Uses supplies_usage from the printer's own MQTT print/report payload —
  the printer's cumulative extrusion counter in mm, reset each print.
  Discovered via MQTT payload inspection: matches slicer estimate within
  ~1% for model filament, and also captures the printer's purge/prime
  sequence that the slicer doesn't count.
- Reports to Spoolman via PUT /api/v1/spool/{id}/use with use_length (mm),
  letting Spoolman convert to weight using the spool's filament profile.
- Accurate for both completed and cancelled prints — no estimation needed.
- For multi-slot prints, total filament is split equally across mapped spools
  (v1 approximation; per-slot MQTT breakdown not available).

UI changes:
- Filament assignment dialog gains a Spoolman section (hidden when not
  configured): one spool dropdown per assigned AMS slot, loaded async
  from GET /kx/spoolman/spools.
- AMS slot display shows a 🧵 #N badge on any slot with a mapped spool.
- Spool assignments persist across prints (sticky until changed).

New API endpoints:
  GET  /kx/spoolman/status        — configured flag, server URL, slot map
  GET  /kx/spoolman/spools        — spool list proxied from Spoolman
  POST /kx/spoolman/active-spool  — body: {"slot_map": {"0": 42, "1": 17}}

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Owner

Sounds very good . I will check Monday.

Sounds very good . I will check Monday.
p2l added 1 commit 2026-06-19 15:38:52 +02:00
Replace equal-split with poll-based per-slot accumulation using
loaded_slot from multiColorBox/report:

- _spoolman_attribute_tick(activity_map): called each poll cycle after
  both print/report and multiColorBox/report are processed. Attributes
  the supplies_usage delta to whichever slot is currently loaded.
  Skips attribution during loading/unloading transitions (tool changes
  + purges) so filament consumed during a slot swap is not charged to
  the wrong spool.

- _spoolman_unreported(): returns {slot_idx: mm} not yet sent to
  Spoolman. Uses per-slot data when available, falls back to equal
  split for single-extruder/no-AMS setups where _ams_loaded_slot
  stays -1 throughout the print.

- _spoolman_report(): shared fire-and-forget sender used by both
  notify_end and sync_midprint, eliminating duplicated loop logic.

Per-slot state (_spoolman_slot_usage, _spoolman_slot_reported,
_spoolman_last_usage) is reset at print start and when spool
assignments change.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
viewit merged commit fd0ce5a63d into master 2026-06-23 14:16:41 +02:00
Owner

Merged — thank you @p2l! This is a clean and well-thought-out implementation. The supplies_usage MQTT field maps perfectly to what Moonraker does for Klipper, and the per-slot attribution via loaded_slot delta ticks is the right approach for multi-colour accuracy.

One minor thing for a follow-up: the import requests call inside _req() could be moved to the module top level, though Python caches imports so it has no real runtime cost.

Will ship in the next release.

Merged — thank you @p2l! This is a clean and well-thought-out implementation. The `supplies_usage` MQTT field maps perfectly to what Moonraker does for Klipper, and the per-slot attribution via `loaded_slot` delta ticks is the right approach for multi-colour accuracy. One minor thing for a follow-up: the `import requests` call inside `_req()` could be moved to the module top level, though Python caches imports so it has no real runtime cost. Will ship in the next release.
p2l deleted branch feature/spoolman 2026-06-23 23:16:54 +02:00
Sign in to join this conversation.
No Reviewers
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: viewit/KX-Bridge-Release#65
No description provided.