Просмотр исходного кода

Fix inventory usage tracker missing external spool mapping (#677)

  When all higher-priority slot-to-tray mapping methods failed (MQTT
  mapping, print command mapping, queue mapping, color matching), the
  internal usage tracker fell back to slot_id - 1 which can never reach
  external spool IDs (254/255) or AMS-HT IDs (128+). Added position-based
  resolution using sorted available tray IDs, matching the Spoolman fix
  from PR #686.
maziggy 5 месяцев назад
Родитель
Сommit
220717f174
2 измененных файлов с 19 добавлено и 3 удалено
  1. 1 0
      CHANGELOG.md
  2. 18 3
      backend/app/services/usage_tracker.py

+ 1 - 0
CHANGELOG.md

@@ -47,6 +47,7 @@ All notable changes to Bambuddy will be documented in this file.
 - **Debug Logging Banner Timer Shows Negative Time** — When enabling debug logging, the banner showed a negative duration (e.g. "-60m -59s") equal to the server's UTC offset. The `enabled_at` timestamp was stored using `datetime.now()` (local time, no timezone indicator), but the frontend interpreted it as UTC. Now stores and compares all debug logging timestamps in UTC.
 - **Non-Bambu Lab Spools Can't Link/Unlink to Spoolman** ([#653](https://github.com/maziggy/bambuddy/pull/653)) — The "Link to Spoolman" button was not shown for non-Bambu Lab spools (which lack RFID tag UIDs). Now generates a fallback tag from the printer ID, AMS ID, and tray ID for spools without RFID identifiers. Also added an "Unlink from Spoolman" button for non-Bambu spools that are already linked. Contributed by @shrunbr.
 - **Spoolman Location Not Updated on Link/Unlink** ([#669](https://github.com/maziggy/bambuddy/pull/669)) — Linking a spool to Spoolman did not set the spool's location field. Now sets the Spoolman location to the printer name, AMS name, and slot number (e.g. "P2S-1 - AMS-A 3") when linking, and clears it when unlinking. Contributed by @shrunbr.
+- **Inventory Usage Tracker Missing External Spool Mapping** ([#677](https://github.com/maziggy/bambuddy/issues/677)) — When all higher-priority slot-to-tray mapping methods failed (MQTT mapping, print command mapping, queue mapping, color matching), the internal inventory usage tracker fell back to `slot_id - 1` which can never reach external spool IDs (254/255) or AMS-HT IDs (128+). Added position-based resolution using sorted available tray IDs from the printer's AMS state, matching the fix applied to Spoolman tracking in #686. Contributed by @shrunbr.
 
 
 ## [0.2.2b2] - 2026-03-06

+ 18 - 3
backend/app/services/usage_tracker.py

@@ -475,7 +475,8 @@ async def _track_from_3mf(
     2. MQTT mapping field from printer state (universal, all print sources)
     3. Queue item ams_mapping (for queue-initiated prints)
     4. tray_now from printer state (for single-filament non-queue prints)
-    5. Default mapping: slot_id - 1 = global_tray_id (last resort)
+    5. Position-based default using sorted available tray IDs (handles external spools)
+    6. Default mapping: slot_id - 1 = global_tray_id (last resort)
     """
     from backend.app.core.config import settings as app_settings
     from backend.app.models.archive import PrintArchive
@@ -804,12 +805,26 @@ async def _track_from_3mf(
             # Single-filament non-queue print: use actual tray from printer state
             global_tray_id = tray_now_override
         else:
-            # Queue mapping or default: slot_id - 1, overridden by ams_mapping
-            global_tray_id = slot_id - 1
+            # Explicit mapping (print command, MQTT, queue, color match)
+            global_tray_id = None
             if slot_to_tray and slot_id <= len(slot_to_tray):
                 mapped = slot_to_tray[slot_id - 1]
                 if isinstance(mapped, int) and mapped >= 0:
                     global_tray_id = mapped
+            # Position-based default: sort available tray IDs so external spools (254/255)
+            # naturally follow standard AMS trays, matching slicer slot numbering
+            if global_tray_id is None:
+                _state = printer_manager.get_status(printer_id)
+                _raw = getattr(_state, "raw_data", None) if _state else None
+                if _raw:
+                    from backend.app.services.spoolman_tracking import build_ams_tray_lookup
+
+                    available_trays = sorted(build_ams_tray_lookup(_raw).keys())
+                    if slot_id <= len(available_trays):
+                        global_tray_id = available_trays[slot_id - 1]
+            # Final fallback: slot_id - 1 (legacy, works for pure AMS without external spools)
+            if global_tray_id is None:
+                global_tray_id = slot_id - 1
 
         if global_tray_id >= 254:
             # External spool: ams_id=255 (sentinel), tray_id=slot index (0 or 1)