Browse Source

docs(spoolman): native tags lookup order, written tags and padded chip UIDs

maziggy 2 days ago
parent
commit
842dd9109b

+ 8 - 1
backend/app/api/routes/spoolman_inventory.py

@@ -1396,6 +1396,7 @@ async def link_tag_to_spoolman_spool(
 
 
 _HEX_TAG_RE = re.compile(r"^[0-9A-F]{8,64}$")
+_AMS_CHIP_UID_PADDING = "00000100"
 
 
 @router.post("/tags/migrate")
@@ -1439,6 +1440,12 @@ async def migrate_tags_to_native(
         if is_slot_fallback_tag(tag, serials):
             report["slot_ids"] += 1
             continue
+        # The AMS pads a Bambu chip's 4-byte UID to 8 bytes ("D3E68F32" arrives as
+        # "D3E68F3200000100"). The native tag is the chip's own UID, as the AMS
+        # sync stores it, so it matches what a reader sees.
+        bambu = len(tag) == 32
+        if len(tag) == 16 and tag.endswith(_AMS_CHIP_UID_PADDING):
+            tag, bambu = tag[:8], True
         holder = native_holder.get(tag)
         if holder == spool["id"]:
             report["already"] += 1
@@ -1447,7 +1454,7 @@ async def migrate_tags_to_native(
             holder = None
         if holder is None and not dry_run:
             async with _translate_spoolman_errors():
-                holder = await client.claim_native_tag(spool["id"], tag, "bambu" if len(tag) == 32 else None)
+                holder = await client.claim_native_tag(spool["id"], tag, "bambu" if bambu else None)
         if holder is not None:
             report["conflicts"].append({"spool_id": spool["id"], "tag": tag, "holder": holder})
             continue

+ 17 - 0
backend/tests/integration/test_spoolman_native_tags_3168.py

@@ -496,6 +496,23 @@ class TestMigration:
         assert dry["conflicts"] == real["conflicts"] == []
         assert (fake.native(1), fake.native(9)) == ([], [CHIP])
 
+    async def test_a_padded_ams_chip_uid_is_copied_as_the_chips_own_uid(self, async_client, spoolman_on):
+        fake = FakeSpoolman()
+        fake.add_spool(1, extra_tag=f"{CHIP}00000100")  # linked from an AMS slot
+        fake.add_spool(2, extra_tag="E004015012345678")  # an 8-byte reader UID stays whole
+        fake.add_spool(3, extra_tag=f"{OTHER_CHIP}00000100", tags=[OTHER_CHIP])  # already native
+
+        with serving(fake):
+            dry = (await async_client.post(f"{INVENTORY}/tags/migrate")).json()
+            real = (await async_client.post(f"{INVENTORY}/tags/migrate", params={"dry_run": "false"})).json()
+
+        assert dry["moved"] == real["moved"] == [1, 2]
+        assert dry["already"] == real["already"] == 1
+        assert (fake.native(1), fake.native(2)) == ([CHIP], ["E004015012345678"])
+        assert fake.spools[1]["tags"][0]["format"] == "bambu"
+        # extra.tag keeps the AMS's padded form, which the AMS sync matches on.
+        assert fake.spools[1]["extra"]["tag"] == json.dumps(f"{CHIP}00000100")
+
     async def test_an_older_server_is_refused(self, async_client, spoolman_on):
         fake = FakeSpoolman(tag_api=False)
         fake.add_spool(1, extra_tag=TRAY_UUID)