|
|
@@ -0,0 +1,121 @@
|
|
|
+"""An A2L with an AMS 2 Pro and an AMS Lite shows both on the card (#3499).
|
|
|
+
|
|
|
+The firmware sends unit ids as strings ("0"); the AMS Lite's physical id 16 is
|
|
|
+normalised to the int 6. With both units attached the merge sorted "0" against
|
|
|
+6 and raised, so the unit list was never stored. The frame's own AMS object
|
|
|
+stayed in its place, and every later frame (and the AMS labels API) failed on
|
|
|
+its string keys: the card showed only the external spool until one AMS was
|
|
|
+unplugged and the printer reconnected.
|
|
|
+
|
|
|
+Frame values follow the reporter's support package: AMS 2 Pro with four bare
|
|
|
+slots, AMS Lite with four Bambu PLA Basic spools, ams_exist_bits "1001",
|
|
|
+tray_exist_bits "f000000".
|
|
|
+"""
|
|
|
+
|
|
|
+from unittest.mock import patch
|
|
|
+
|
|
|
+from backend.app.services.bambu_mqtt import BambuMQTTClient
|
|
|
+
|
|
|
+
|
|
|
+def _client() -> BambuMQTTClient:
|
|
|
+ return BambuMQTTClient(ip_address="10.0.0.1", serial_number="A2L", access_code="c", model="A2L")
|
|
|
+
|
|
|
+
|
|
|
+def _lite_tray(slot: int, colour: str) -> dict:
|
|
|
+ return {
|
|
|
+ "id": str(slot),
|
|
|
+ "state": 3,
|
|
|
+ "remain": -1,
|
|
|
+ "tray_type": "PLA",
|
|
|
+ "tray_sub_brands": "PLA Basic",
|
|
|
+ "tray_info_idx": "GFA00",
|
|
|
+ "tray_color": colour,
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+def _frame(lite_id=16) -> dict:
|
|
|
+ return {
|
|
|
+ "ams": {
|
|
|
+ "ams": [
|
|
|
+ {"id": "0", "info": "2003", "tray": [{"id": str(n)} for n in range(4)]},
|
|
|
+ {
|
|
|
+ "id": lite_id,
|
|
|
+ "info": "30001005",
|
|
|
+ "tray": [
|
|
|
+ _lite_tray(0, "000000FF"),
|
|
|
+ _lite_tray(1, "3F8E43FF"),
|
|
|
+ _lite_tray(2, "0056B8FF"),
|
|
|
+ _lite_tray(3, "FFFFFFFF"),
|
|
|
+ ],
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ "ams_exist_bits": "1001",
|
|
|
+ "tray_exist_bits": "f000000",
|
|
|
+ "tray_now": "255",
|
|
|
+ "power_on_flag": True,
|
|
|
+ },
|
|
|
+ "gcode_state": "IDLE",
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+def _units(client: BambuMQTTClient) -> list:
|
|
|
+ units = client.state.raw_data.get("ams")
|
|
|
+ assert isinstance(units, list), f"AMS units are {type(units).__name__}, not a list"
|
|
|
+ return units
|
|
|
+
|
|
|
+
|
|
|
+def test_both_units_are_stored():
|
|
|
+ client = _client()
|
|
|
+
|
|
|
+ client._process_message({"print": _frame()})
|
|
|
+
|
|
|
+ units = _units(client)
|
|
|
+ assert [str(u["id"]) for u in units] == ["0", "6"]
|
|
|
+ assert [t["tray_color"] for t in units[1]["tray"]] == ["000000FF", "3F8E43FF", "0056B8FF", "FFFFFFFF"]
|
|
|
+
|
|
|
+
|
|
|
+def test_a_string_lite_id_is_stored_too():
|
|
|
+ client = _client()
|
|
|
+
|
|
|
+ client._process_message({"print": _frame(lite_id="16")})
|
|
|
+
|
|
|
+ assert [str(u["id"]) for u in _units(client)] == ["0", "6"]
|
|
|
+
|
|
|
+
|
|
|
+def test_later_frames_keep_both_units():
|
|
|
+ client = _client()
|
|
|
+ for _ in range(3):
|
|
|
+ client._process_message({"print": _frame()})
|
|
|
+
|
|
|
+ assert [str(u["id"]) for u in _units(client)] == ["0", "6"]
|
|
|
+
|
|
|
+
|
|
|
+def test_a_frame_the_ams_handling_fails_on_leaves_no_ams_object_behind():
|
|
|
+ client = _client()
|
|
|
+
|
|
|
+ # Any failure in the AMS handling, as the mixed-id sort was.
|
|
|
+ with patch.object(client, "_handle_ams_data", side_effect=TypeError("boom")):
|
|
|
+ client._process_message({"print": _frame()})
|
|
|
+
|
|
|
+ assert "ams" not in client.state.raw_data
|
|
|
+
|
|
|
+
|
|
|
+def test_a_stored_ams_object_does_not_block_later_frames():
|
|
|
+ # An install already in the broken state: the AMS object in place of the list.
|
|
|
+ client = _client()
|
|
|
+ client.state.raw_data["ams"] = {"ams": [], "ams_exist_bits": "1001"}
|
|
|
+
|
|
|
+ client._process_message({"print": _frame()})
|
|
|
+
|
|
|
+ assert [str(u["id"]) for u in _units(client)] == ["0", "6"]
|
|
|
+
|
|
|
+
|
|
|
+def test_units_are_in_numeric_order():
|
|
|
+ client = _client()
|
|
|
+ frame = _frame()
|
|
|
+ frame["ams"]["ams"].append({"id": "1", "tray": [{"id": str(n)} for n in range(4)]})
|
|
|
+ frame["ams"]["ams_exist_bits"] = "1003"
|
|
|
+
|
|
|
+ client._process_message({"print": frame})
|
|
|
+
|
|
|
+ assert [str(u["id"]) for u in _units(client)] == ["0", "1", "6"]
|