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

Log home_flag changes on printers without cfg to check AMS Filament Backup in update frames (#3259)

maziggy 3 дней назад
Родитель
Сommit
170335e8dc
2 измененных файлов с 42 добавлено и 0 удалено
  1. 21 0
      backend/app/services/bambu_mqtt.py
  2. 21 0
      backend/tests/unit/services/test_bambu_mqtt.py

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

@@ -1494,6 +1494,8 @@ class BambuMQTTClient:
         # True once the printer has sent `cfg`; from then on AMS Filament Backup
         # True once the printer has sent `cfg`; from then on AMS Filament Backup
         # is read from cfg only, never from home_flag (#3259).
         # is read from cfg only, never from home_flag (#3259).
         self._backup_cfg_seen: bool = False
         self._backup_cfg_seen: bool = False
+        # Last home_flag written by the #3259 probe log below.
+        self._backup_home_flag_logged: int | None = None
 
 
         # Track last requested tray ID for H2D dual-nozzle printers
         # Track last requested tray ID for H2D dual-nozzle printers
         # H2D only reports slot number (0-3) in tray_now, not global tray ID
         # H2D only reports slot number (0-3) in tray_now, not global tray ID
@@ -2339,6 +2341,25 @@ class BambuMQTTClient:
                     new_backup = parse_ams_filament_backup_from_cfg(print_data["cfg"])
                     new_backup = parse_ams_filament_backup_from_cfg(print_data["cfg"])
                 elif not self._backup_cfg_seen and len(print_data) > 30:
                 elif not self._backup_cfg_seen and len(print_data) > 30:
                     new_backup = parse_ams_filament_backup_from_home_flag(print_data.get("home_flag"))
                     new_backup = parse_ams_filament_backup_from_home_flag(print_data.get("home_flag"))
+                # Probe for #3259: does bit 10 stay right in the small update
+                # frames these printers send between full reports? Logged on
+                # every change, so a heartbeat that clears bit 10 shows up as
+                # a flip. Remove once a P1S capture answers it.
+                home_flag = print_data.get("home_flag")
+                if (
+                    not self._backup_cfg_seen
+                    and isinstance(home_flag, int)
+                    and not isinstance(home_flag, bool)
+                    and home_flag != self._backup_home_flag_logged
+                ):
+                    self._backup_home_flag_logged = home_flag
+                    logger.debug(
+                        "[%s] home_flag probe: 0x%08X bit10=%d keys=%d",
+                        self.serial_number,
+                        home_flag & 0xFFFFFFFF,
+                        (home_flag >> 10) & 1,
+                        len(print_data),
+                    )
             if new_backup is not None and new_backup != self.state.ams_filament_backup:
             if new_backup is not None and new_backup != self.state.ams_filament_backup:
                 hold_start = self._xcam_hold_start.get("print_option_auto_switch_filament")
                 hold_start = self._xcam_hold_start.get("print_option_auto_switch_filament")
                 if hold_start is not None and (time.time() - hold_start) <= self._xcam_hold_time:
                 if hold_start is not None and (time.time() - hold_start) <= self._xcam_hold_time:

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

@@ -7269,6 +7269,27 @@ class TestCommandAckIsNotTelemetry:
 
 
         assert mqtt_client.state.ams_filament_backup is True
         assert mqtt_client.state.ams_filament_backup is True
 
 
+    def test_home_flag_probe_logs_each_change_with_frame_size(self, mqtt_client, caplog):
+        """#3259 probe: small frames are logged too, but only when home_flag changes."""
+        caplog.set_level(logging.DEBUG, logger="backend.app.services.bambu_mqtt")
+
+        mqtt_client._process_message(self._full_status(home_flag=7554719))  # bit10=1
+        mqtt_client._process_message({"print": {"command": "push_status", "home_flag": 7554719}})
+        mqtt_client._process_message({"print": {"command": "push_status", "home_flag": -1024}})
+
+        probes = [r.getMessage() for r in caplog.records if "home_flag probe" in r.getMessage()]
+        assert len(probes) == 2
+        assert "0x0073469F bit10=1 keys=32" in probes[0]
+        assert "0xFFFFFC00 bit10=1 keys=2" in probes[1]
+
+    def test_home_flag_probe_silent_once_printer_sent_cfg(self, mqtt_client, caplog):
+        caplog.set_level(logging.DEBUG, logger="backend.app.services.bambu_mqtt")
+
+        mqtt_client._process_message(self._full_status(cfg="C0340FC219"))
+        mqtt_client._process_message({"print": {"command": "push_status", "home_flag": 0}})
+
+        assert not [r for r in caplog.records if "home_flag probe" in r.getMessage()]
+
     def test_project_file_ack_does_not_clear_timelapse_state(self, mqtt_client):
     def test_project_file_ack_does_not_clear_timelapse_state(self, mqtt_client):
         """The ack echoes the per-job timelapse request, not the recorder."""
         """The ack echoes the per-job timelapse request, not the recorder."""
         mqtt_client.state.timelapse = True
         mqtt_client.state.timelapse = True