From 851f42a0245ba75ff23fe6205e5d935f5c9bb10d Mon Sep 17 00:00:00 2001 From: Martin Ziegler Date: Fri, 5 Dec 2025 11:45:14 +0100 Subject: [PATCH] Wiring up AMS module --- backend/app/services/bambu_mqtt.py | 60 ++++++++++++++++++++++++++---- 1 file changed, 52 insertions(+), 8 deletions(-) diff --git a/backend/app/services/bambu_mqtt.py b/backend/app/services/bambu_mqtt.py index f7518a10f..b65483c9e 100644 --- a/backend/app/services/bambu_mqtt.py +++ b/backend/app/services/bambu_mqtt.py @@ -125,6 +125,10 @@ class PrinterState: # mc_print_sub_stage - filament change step indicator from print.mc_print_sub_stage # Used by OrcaSlicer/BambuStudio to track progress during filament load/unload mc_print_sub_stage: int = 0 + # AMS mapping for dual nozzle: which slot is active (from ams.ams_exist_bits/tray_exist_bits) + ams_mapping: list = field(default_factory=list) + # Per-AMS extruder map: {ams_id: extruder_id} where 0=right, 1=left + ams_extruder_map: dict = field(default_factory=dict) # Stage name mapping from BambuStudio DeviceManager.cpp @@ -692,13 +696,45 @@ class BambuMQTTClient: f"(matches incoming slot {parsed_tray_now})" ) else: - # No match or no existing global ID, use slot number as-is - # This happens when filament was loaded before app started or via printer touchscreen - logger.debug( - f"[{self.serial_number}] H2D tray_now: no pending_tray_target, " - f"using slot {parsed_tray_now} as global ID (may be incorrect for H2D)" - ) - self.state.tray_now = parsed_tray_now + # No match or no existing global ID - find active AMS from info field + # For H2D, the AMS with info starting with "1" is actively feeding + # (info starting with "2" means idle) + inferred_global_id = None + active_ams_id = None + + # Use ams_list from the current message (already extracted above at line 625) + for ams_unit in ams_list: + ams_id = ams_unit.get("id") + if ams_id is None: + continue + try: + ams_id = int(ams_id) + except (ValueError, TypeError): + continue + + # Check if this AMS is active (info starts with "1") + info = ams_unit.get("info") + if info is not None: + info_str = str(info) + if info_str.startswith("1"): + active_ams_id = ams_id + inferred_global_id = ams_id * 4 + parsed_tray_now + logger.info( + f"[{self.serial_number}] H2D tray_now: " + f"AMS {ams_id} is active (info={info_str}), " + f"slot {parsed_tray_now} -> global ID {inferred_global_id}" + ) + break + + if inferred_global_id is not None: + self.state.tray_now = inferred_global_id + else: + # Fallback: use slot number as-is (may be incorrect for H2D) + logger.debug( + f"[{self.serial_number}] H2D tray_now: no active AMS found (no info starting with '1'), " + f"using slot {parsed_tray_now} as global ID (may be incorrect for H2D)" + ) + self.state.tray_now = parsed_tray_now else: # tray_now > 3 means it's already a global ID, or 255 means unloaded # Note: Do NOT clear pending_tray_target on tray_now=255 here. @@ -747,6 +783,7 @@ class BambuMQTTClient: pass if ams_extruder_map: self.state.raw_data["ams_extruder_map"] = ams_extruder_map + self.state.ams_extruder_map = ams_extruder_map # Also set on state for inference logic logger.debug(f"[{self.serial_number}] ams_extruder_map: {ams_extruder_map}") # Create a hash of relevant AMS data to detect changes @@ -2425,14 +2462,21 @@ class BambuMQTTClient: logger.warning(f"[{self.serial_number}] Cannot unload filament: not connected") return False + # Build unload command with all required fields (per HA-Bambulab integration) command = { "print": { "command": "ams_change_filament", "target": 255, # 255 = unload + "ams_id": 255, + "slot_id": 0, + "curr_temp": 0, + "tar_temp": 0, "sequence_id": "0" } } - self._client.publish(self.topic_publish, json.dumps(command)) + command_json = json.dumps(command) + logger.info(f"[{self.serial_number}] Publishing ams_change_filament (unload) command: {command_json}") + self._client.publish(self.topic_publish, command_json) logger.info(f"[{self.serial_number}] Unloading filament") # Clear tracked load request since we're unloading