fix(spoolman): repair dead slot-map persistence + isolate it per printer #83

Manually merged
viewit merged 2 commits from walterioo/KX-Bridge-Release:fix/spoolman-persist-per-printer into nightly 2026-07-02 21:37:02 +02:00
Contributor

Description

Fixes the two Spoolman slot→spool persistence bugs from #80.

Bug 1 — persistence was a no-op. The load (__init__) and save (handle_kx_spoolman_set_active) called config_loader.…, but the module is imported as env_loader (kobrax_moonraker_bridge.py:32), so it threw a NameError that the bare except swallowed. The mapping was never read on startup or written on change — it only survived in memory for the session. Now it goes through a local import and logs failures via log.warning instead of silently eating them.

Bug 2 — the map was global. It lived in one [spoolman] slot_spools key shared by every printer instance, so two AMS units clobbered each other. Now each printer gets its own [spoolman_<id>] section, with a read-fallback to the legacy global key so existing single-printer setups keep working. Mirrors the [filament_profiles_<id>] pattern from #75.

Also in here:

  • _build_mmu_object emits a real gate_spool_id from the per-printer map (was hardcoded [-1]), so Happy-Hare/OrcaSlicer can show the bound spool.
  • The spool dropdown in the print dialog showed [object Object] instead of the vendor name — it used sp.filament.vendor (the object) instead of sp.filament.vendor.name; aligned it with the slot-card builder that already does this.
  • config.ini.example documents the [spoolman] section.

Closes #80

Type

  • Bug fix
  • Documentation

Tested with

  • OrcaSlicer: 2.4.1-KX1 · Printer: 2x Anycubic Kobra X (multi-printer, ACE/AMS) · Moonraker: bridge-emulated (v0.9.3-1)

After a restart each printer loads its own [spoolman_<id>] map, isolated. A real 2-color print on the second printer deducted per slot — the dominant color landed at 38.81 g vs the slicer's 38.73 g estimate, the other color went to its own spool, and the unused slots stayed at 0 — confirming the mm-based deduction hits the right printer's spools. New tests in tests/test_spoolman_slot_map.py; flake8 clean on the changed code and pytest green locally.

Checklist

  • Tests added/updated
  • CHANGELOG.md updated (leaving to the maintainer's changelog step)
  • No debug code included
## Description Fixes the two Spoolman slot→spool persistence bugs from #80. **Bug 1 — persistence was a no-op.** The load (`__init__`) and save (`handle_kx_spoolman_set_active`) called `config_loader.…`, but the module is imported as `env_loader` (`kobrax_moonraker_bridge.py:32`), so it threw a `NameError` that the bare `except` swallowed. The mapping was never read on startup or written on change — it only survived in memory for the session. Now it goes through a local import and logs failures via `log.warning` instead of silently eating them. **Bug 2 — the map was global.** It lived in one `[spoolman] slot_spools` key shared by every printer instance, so two AMS units clobbered each other. Now each printer gets its own `[spoolman_<id>]` section, with a read-fallback to the legacy global key so existing single-printer setups keep working. Mirrors the `[filament_profiles_<id>]` pattern from #75. Also in here: - `_build_mmu_object` emits a real `gate_spool_id` from the per-printer map (was hardcoded `[-1]`), so Happy-Hare/OrcaSlicer can show the bound spool. - The spool dropdown in the print dialog showed `[object Object]` instead of the vendor name — it used `sp.filament.vendor` (the object) instead of `sp.filament.vendor.name`; aligned it with the slot-card builder that already does this. - `config.ini.example` documents the `[spoolman]` section. ## Related Issue Closes #80 ## Type - [x] Bug fix - [x] Documentation ## Tested with - OrcaSlicer: 2.4.1-KX1 · Printer: 2x Anycubic Kobra X (multi-printer, ACE/AMS) · Moonraker: bridge-emulated (v0.9.3-1) After a restart each printer loads its own `[spoolman_<id>]` map, isolated. A real 2-color print on the second printer deducted per slot — the dominant color landed at 38.81 g vs the slicer's 38.73 g estimate, the other color went to its own spool, and the unused slots stayed at 0 — confirming the mm-based deduction hits the right printer's spools. New tests in `tests/test_spoolman_slot_map.py`; `flake8` clean on the changed code and `pytest` green locally. ## Checklist - [x] Tests added/updated - [ ] CHANGELOG.md updated (leaving to the maintainer's changelog step) - [x] No debug code included
walterioo added 2 commits 2026-07-02 08:09:49 +02:00
The AMS-slot -> Spoolman-spool persistence never worked: KobraXBridge
referenced `config_loader` in both the load (__init__) and save
(handle_kx_spoolman_set_active) paths, but the module alias is `env_loader`
(kobrax_moonraker_bridge.py:32). The resulting NameError was swallowed by a
bare `except`, so the map was neither loaded on startup nor written on change
- it only appeared to persist.

The map also lived in a single global `[spoolman] slot_spools` key, so on a
multi-printer bridge two AMS units clobbered each other's mapping (same class
of bug as #74/#75 for filament profiles).

- config_loader: add list_spool_map()/save_spool_map(printer_id) using a
  per-printer `[spoolman_<id>]` section with read-fallback to the legacy
  global key, mirroring _filament_section/list_filament_profiles. The global
  `[spoolman]` section keeps server/sync_rate.
- bridge: load via config_loader.list_spool_map(self._printer_id); persist via
  save_spool_map(..., self._printer_id); surface failures via log.warning
  instead of a silent except.
- _build_mmu_object: emit real gate_spool_id from the per-printer map (was
  hardcoded [-1]*num_gates) so Happy-Hare/OrcaSlicer can show the bound spool.
- config.ini.example: document the [spoolman] section.
- tests: tests/test_spoolman_slot_map.py (per-printer isolation, persistence
  round-trip, server/sync_rate preservation, parser robustness).

Verified on a 2-printer bridge: after restart KX1 loads its spools and KX2
loads its own, isolated; a real multicolor print deducted per slot (white spool
1.02g vs 0.98g slicer estimate) against the correct printer's spools.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
fix(spoolman): show vendor name in the spool dropdown (was "[object Object]")
Some checks failed
PR Check / lint-and-test (pull_request) Has been cancelled
a39226d2dd
The print-dialog spool dropdown built its option label from
sp.filament.vendor (the whole vendor object) instead of
sp.filament.vendor.name, so options rendered as "#5 [object Object] PLA+
(1000g)". The sibling builder in the slot card already uses .vendor.name;
this aligns the two.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
viewit manually merged commit 51f22947c5 into nightly 2026-07-02 21:37:02 +02:00
walterioo deleted branch fix/spoolman-persist-per-printer 2026-07-03 01:32:25 +02:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

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