diff --git a/backend/app/services/bambu_mqtt.py b/backend/app/services/bambu_mqtt.py index bbad81216..622419025 100644 --- a/backend/app/services/bambu_mqtt.py +++ b/backend/app/services/bambu_mqtt.py @@ -1317,6 +1317,18 @@ class BambuMQTTClient: if isinstance(ipcam_data, dict): # Check ipcam_record field for live view status self.state.ipcam = ipcam_data.get("ipcam_record") == "enable" + # Check timelapse field (H2D sends it here, not in xcam) + if "timelapse" in ipcam_data: + timelapse_enabled = ipcam_data.get("timelapse") == "enable" + if timelapse_enabled != self.state.timelapse: + logger.info( + f"[{self.serial_number}] timelapse changed (from ipcam): {self.state.timelapse} -> {timelapse_enabled}" + ) + self.state.timelapse = timelapse_enabled + # Track if timelapse was ever active during this print + if self.state.timelapse and self._was_running: + self._timelapse_during_print = True + logger.info(f"[{self.serial_number}] Timelapse detected during print (from ipcam)") else: self.state.ipcam = ipcam_data is True diff --git a/backend/tests/integration/test_print_lifecycle.py b/backend/tests/integration/test_print_lifecycle.py index 4892b418e..4b8af8c76 100644 --- a/backend/tests/integration/test_print_lifecycle.py +++ b/backend/tests/integration/test_print_lifecycle.py @@ -282,6 +282,58 @@ class TestTimelapseTracking: assert completion_data["status"] == "aborted" assert "hms_errors" in completion_data + @pytest.mark.asyncio + async def test_timelapse_detected_from_ipcam_data(self): + """Verify timelapse is detected from ipcam data (H2D sends it there, not xcam).""" + from backend.app.services.bambu_mqtt import BambuMQTTClient + + client = BambuMQTTClient( + ip_address="192.168.1.100", + serial_number="TEST123", + access_code="12345678", + ) + + completion_data = {} + + def on_complete(data): + completion_data.update(data) + + client.on_print_start = lambda data: None + client.on_print_complete = on_complete + + # Start print with timelapse in ipcam data (H2D format) + client._process_message( + { + "print": { + "gcode_state": "RUNNING", + "gcode_file": "/data/Metadata/test.gcode", + "subtask_name": "Test", + "ipcam": { + "ipcam_record": "enable", + "timelapse": "enable", + "resolution": "1080p", + }, + } + } + ) + + assert client._timelapse_during_print is True, "Timelapse should be detected from ipcam data" + + # Complete print + client._process_message( + { + "print": { + "gcode_state": "FINISH", + "gcode_file": "/data/Metadata/test.gcode", + "subtask_name": "Test", + } + } + ) + + assert ( + completion_data["timelapse_was_active"] is True + ), "timelapse_was_active should be True when timelapse was in ipcam" + class TestCallbackErrorHandling: """Test that callback errors are properly logged."""