The original #1322 fix widened empty-slot detection to (state == 11 OR
tray_type != ""), which closed the configured-slot reconfig case but
didn't help the "Reset Slot on printer screen with spool still inserted"
flow. On these firmwares the AMS reports state=3, tray_type="" after a
Reset Slot regardless of whether a spool is physically present, so the
empty-detection still decided "empty", skipped MQTT, marked pending —
and on_ams_change replay never re-fired because the AMS never reported
any state change either.
RosdasHH traced the path: tray_state=3 falls into the else: branch,
slot_is_empty = not (fingerprint_type and fingerprint_type.strip()),
fingerprint_type is "", so slot_is_empty=True, MQTT is skipped, and the
slot stays unconfigured forever. He verified empirically that removing
the gate makes the firmware accept the push when a spool is physically
present.
Drop the tray_type fallback entirely. Only state in {9, 10} (firmware's
explicit "no spool" / "spool present but no feed") short-circuits the
MQTT publish. Every other state — including 3 (default-idle, ambiguous)
and missing-state (older firmwares) — attempts the publish. Bambu's
"firmware silently drops on empty slots" behavior makes the worst case
a no-op for a truly-empty slot, and on_ams_change replay still serves
as the safety net for state=9/10 slots whose spools get inserted later.
pending_config is now (slot_is_definitely_empty OR not configured) so a
printer-offline / no-client publish failure correctly flags the
assignment for replay instead of falsely showing "configured".
The assign flow was sending slicer-invalid values for tray_info_idx and an
empty setting_id, which the slicer rejected — slot detail modal showed
empty fields. With a stored k-profile the realignment path masked the
issue; without one, garbage hit MQTT.
Backend (apply_spool_to_slot_via_mqtt):
- Discard tray_info_idx values that aren't real preset IDs: literal
material names ("PLA", "PETG-CF") AND PFUS-prefix cloud setting_ids
(valid as setting_id but rejected as tray_info_idx). Same check applied
to current_tray_info_idx so stale slot values don't get reused as
garbage.
- Local-preset path now reads the printer-recognized filament_id from
the preset's setting JSON (e.g. P4d64437) instead of falling through
to a generic material ID.
- Derive setting_id from filament_id_to_setting_id when empty so
ams_filament_setting always carries a matched pair.
- No stored k-profile: always send cali_idx=-1 (Default K), regardless
of the live cali_idx on the slot. The live value belongs to whatever
filament was there before, so reusing it would apply the wrong K to
the new spool.
Frontend (spool-form/utils.ts):
- Local preset options use String(preset.id) as the unique code instead
of preset.filament_type — every PLA local preset was collapsing onto
the same "PLA" code, so picking any of them saved slicer_filament=
"PLA" and lost the specific preset identity.
Spoolman counterpart in spoolman_inventory.py mirrors the cali_idx=-1
reset.
A1 Mini BMCU (01.07.02.00) and P1S Standard AMS (00.00.06.75) always
report tray.state=3, even for loaded configured slots. The empty-slot
detection preferred state==11 with tray_type as a fallback only when
state was absent, so every assign was classified as empty and MQTT
was skipped — both for "assign to unconfigured slot" and the secondary
"PETG over a PLA-configured slot won't reconfigure" symptom.
Empty-slot detection in the assign route and the on_ams_change replay
now treats the slot as loaded when EITHER state==11 OR tray_type is
non-empty. Reset-slot case (state=11 + tray_type="") still works
through the first clause; configured slots on these firmwares now
work through the second.
Truly empty unconfigured slots (state!=11 + tray_type="") still hit
the pending-config path, and the deferred publish now fires when the
user later configures the slot in Bambu Studio (tray_type goes
non-empty), since the replay uses the same disjunction.
feat(spoolman-inventory): squashed feature work for rebase onto dev
Squashed all commits from feature/spoolman-inventory-ui onto a single commit
to enable a clean rebase onto dev. Original per-commit history preserved at
backup tag backup/spoolman-inventory-ui-prerebase-20260507-105721.
feat(spoolman-inventory): squashed feature work for rebase onto dev
Squashed all commits from feature/spoolman-inventory-ui onto a single commit
to enable a clean rebase onto dev. Original per-commit history preserved at
backup tag backup/spoolman-inventory-ui-prerebase-20260507-105721.
The SpoolBuddy "weigh-then-assign" workflow tried to configure an empty AMS
slot at assign time, but Bambu firmware silently drops ams_filament_setting
and extrusion_cali_sel for unloaded slots — the MQTT calls completed and the
modal closed, yet BambuStudio kept showing the slot as default-PLA forever.
assign_spool now detects an empty target slot (fingerprint_type empty) and
persists the SpoolAssignment without publishing MQTT, returning a new
pending_config flag so the frontend can swap "Assigned!" for "Slot will
configure when you insert the spool." on_ams_change watches for the slot
to load (state == 11, which fires for 3rd-party tags too even when
tray_type stays empty) and replays the deferred ams_filament_setting +
extrusion_cali_sel — including the printer-kp realignment that converts
PFUS-prefix cloud user presets to the P-prefix local-preset filament_id
the slicer actually accepts.
The full assign-time MQTT block was extracted into
apply_spool_to_slot_via_mqtt so both the assign endpoint and the
on_ams_change replay path use the same resolution logic; the helper takes
~270 lines of duplication out of assign_spool.
After assigning a spool to an AMS slot, the Bambuddy UI could show the
wrong filament preset (e.g. "Bambu PLA Matte" instead of "Bambu PLA
Silk") even though the printer was configured correctly.
Two bugs:
1. AssignSpoolModal (PrintersPage hover card path) never saved the slot
preset mapping to the DB, so the display fell back to the old/stale
mapping from a previous manual configuration.
2. AssignToAmsModal (SpoolBuddy path) constructed the preset name from
spool.material + spool.subtype ("PLA Silk") instead of using the
authoritative spool.slicer_filament_name ("Bambu PLA Silk").
Fix: the backend now saves the slot preset mapping in assign_spool()
after successful MQTT configuration, using slicer_filament_name as the
display name. This covers both frontend paths and ensures the correct
name is always stored.
Two bugs caused spool assignments to always configure AMS slots with
generic Bambu filament IDs (e.g. GFB99 "Generic ABS") instead of the
spool's actual slicer preset:
1. PFUS* IDs (cloud-synced custom presets) were blanket-rejected and
replaced with generic IDs in both assign_spool and configure_ams_slot
2. Generic fallback IDs (GFB99, GFL99, etc.) were treated as "good"
presets by the slot-reuse logic, making them sticky once set
New priority: spool's own slicer_filament > slot's non-generic preset
(same material) > generic fallback.
BambuStudio actively resets AMS slots configured with unrecognized PFUS*
(user-local) preset IDs. Replace PFUS* with generic Bambu filament IDs
(e.g. GFL99 for PLA) in both the slot configure and inventory assignment
endpoints. When the slot already has a recognized cloud-synced preset for
the same material, reuse it to preserve K-profile calibration.
Also fix fill level bar not showing for brand new spools (weight_used=0)
by changing the condition from weight_used > 0 to weight_used != null.