Add spool inventory: AMS slot assignment, usage tracking, and remaining weight editing

Built-in spool inventory with AMS slot assignment for non-BL spools,
automatic filament usage tracking via 3MF estimates, and remaining
weight editing in the spool form.

Inventory features:
- AMS slot assignment: assign/unassign manual spools to AMS tray slots
- Filter out Bambu Lab spools (RFID-managed) from assignment modal
- Filter out already-assigned spools (one spool per slot)
- Auto-unlink manual assignments when a BL spool is inserted
- Hide assign/unassign UI on BL-occupied slots
- Case-insensitive fingerprint matching for auto-unlink logic

Usage tracking:
- 3MF-based filament consumption tracking for non-BL spools
- Extract per-filament used_g from archived 3MF slice_info
- Map 3MF slot_id to AMS (ams_id, tray_id) positions
- Scale estimates by print progress for failed/aborted prints
- Skip BL spools (tracked via AMS remain% delta, Path 1)
- Prevent double-counting with handled_trays set

Other:
- Add remaining weight field to spool edit form
- Fix hardcoded "Empty" string in AssignSpoolModal (now i18n)
- Add backend unit tests for usage_tracker (11 tests)
- Add frontend tests for AssignSpoolModal filters (5 tests)
- Update CHANGELOG, README, wiki docs, and website
This commit is contained in:
maziggy
2026-02-12 15:42:27 +01:00
parent 1f0931e00c
commit e6e62f2a68
29 changed files with 10404 additions and 9316 deletions
+5 -1
View File
@@ -645,8 +645,12 @@ async def assign_spool(
fingerprint_type = None
state = printer_manager.get_status(data.printer_id)
if state and state.raw_data:
ams_data = state.raw_data.get("ams", {})
ams_list = (
ams_data.get("ams", []) if isinstance(ams_data, dict) else ams_data if isinstance(ams_data, list) else []
)
tray = _find_tray_in_ams_data(
state.raw_data.get("ams", {}).get("ams", []),
ams_list,
data.ams_id,
data.tray_id,
)