Pārlūkot izejas kodu

fix(ams): don't wipe an AMS-HT spool on a partial state=9 update (#2594)

The AMS merge clears a tray on a partial {id, state} update when state != 11
(the 4-slot AMS "emptied slot" signal, #784). An AMS-HT (single-tray high-temp
dry box, id >= 128) reports its loaded tray as state=9, so the partial the
printer sends on power-on was misread as "emptied" and wiped the HT-A spool's
tray_type/RFID/assignment seconds after power-on.

Skip the state-heuristic for HT units (id >= 128). Genuine HT removal still
clears via the explicit tray_type="" update and tray_exist_bits cleanup;
regular AMS (id < 128) is unchanged.
maziggy 1 mēnesi atpakaļ
vecāks
revīzija
059b733c41

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 1 - 0
CHANGELOG.md


+ 16 - 0
backend/app/services/bambu_mqtt.py

@@ -2078,10 +2078,26 @@ class BambuMQTTClient:
                             # 10=spool present but filament not in feeder) indicate
                             # the slot should be cleared.  Without this, old
                             # tray_type/tray_color persist indefinitely (#784).
+                            #
+                            # BUT this is regular-AMS semantics. An AMS-HT (single-
+                            # tray high-temp dry box, id >= 128) reports its loaded
+                            # tray as state=9, not 11 — it doesn't feed filament into
+                            # a shared buffer the way a 4-slot AMS does. Applying the
+                            # `state != 11 → empty` rule to an HT unit wiped a present
+                            # spool on every power-on, when the printer sends a partial
+                            # {id, state=9} for the HT tray (#2594). Skip the state
+                            # heuristic for HT units — a genuine HT spool removal still
+                            # clears via the explicit tray_type=="" case above and the
+                            # tray_exist_bits cleanup below.
+                            try:
+                                _is_ht_unit = int(ams_id) >= 128
+                            except (TypeError, ValueError):
+                                _is_ht_unit = False
                             tray_state = new_tray.get("state")
                             if (
                                 tray_state is not None
                                 and tray_state != 11
+                                and not _is_ht_unit
                                 and "tray_type" not in new_tray
                                 and merged_tray.get("tray_type")
                             ):

+ 57 - 0
backend/tests/unit/services/test_bambu_mqtt.py

@@ -1196,6 +1196,63 @@ class TestAMSTrayStateClearning:
         assert tray0["tray_color"] == "00FF00FF"
         assert tray0["remain"] == 75
 
+    def _seed_loaded_ht_tray(self, mqtt_client):
+        """Seed an AMS-HT unit (id 128, single tray) whose loaded tray reports
+        state=9 — the real HT resting state, unlike a 4-slot AMS's state=11."""
+        initial = {
+            "ams": [
+                {
+                    "id": 128,
+                    "tray": [
+                        {
+                            "id": 0,
+                            "tray_type": "PA",
+                            "tray_color": "161616FF",
+                            "tray_info_idx": "GFG99",
+                            "tag_uid": "AABBCCDD11223344",
+                            "tray_uuid": "AABBCCDD11223344AABBCCDD11223344",
+                            "remain": 60,
+                            "state": 9,
+                        }
+                    ],
+                }
+            ],
+            "power_on_flag": True,
+        }
+        mqtt_client._handle_ams_data(initial)
+
+    def test_ht_unit_state_9_preserves_tray_data(self, mqtt_client):
+        """#2594: an AMS-HT reports its loaded tray as state=9. A partial
+        {id, state=9} for the HT unit must NOT be read as 'empty' and wipe the
+        present spool — that made the HT-A spool vanish on every power-on."""
+        self._seed_loaded_ht_tray(mqtt_client)
+
+        # Printer sends a partial {id, state} for the HT tray on power-on.
+        update = {
+            "ams": [{"id": 128, "tray": [{"id": 0, "state": 9}]}],
+            "power_on_flag": True,
+        }
+        mqtt_client._handle_ams_data(update)
+
+        tray0 = mqtt_client.state.raw_data["ams"][0]["tray"][0]
+        assert tray0["tray_type"] == "PA", "HT state=9 must NOT clear a present spool (#2594)"
+        assert tray0["tray_uuid"] == "AABBCCDD11223344AABBCCDD11223344", "HT RFID must survive"
+        assert tray0["remain"] == 60
+
+    def test_ht_unit_explicit_empty_still_clears(self, mqtt_client):
+        """A genuine HT spool removal (explicit tray_type='') must still clear —
+        the #2594 fix only skips the state-heuristic, not the explicit path."""
+        self._seed_loaded_ht_tray(mqtt_client)
+
+        update = {
+            "ams": [{"id": 128, "tray": [{"id": 0, "tray_type": ""}]}],
+            "power_on_flag": False,
+        }
+        mqtt_client._handle_ams_data(update)
+
+        tray0 = mqtt_client.state.raw_data["ams"][0]["tray"][0]
+        assert tray0["tray_type"] == "", "explicit tray_type='' must still clear an HT tray"
+
 
 class TestApplyTrayExistBitsHelper:
     """Direct contract pinning for the shared ``apply_tray_exist_bits`` helper.

Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels