diff --git a/backend/app/main.py b/backend/app/main.py index 30fe4cf2d..57ca07111 100644 --- a/backend/app/main.py +++ b/backend/app/main.py @@ -1,9 +1,16 @@ import asyncio +import logging from datetime import datetime from contextlib import asynccontextmanager from pathlib import Path from fastapi import FastAPI + +# Configure logging for all modules +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s %(levelname)s [%(name)s] %(message)s' +) from fastapi.staticfiles import StaticFiles from fastapi.responses import FileResponse @@ -67,21 +74,26 @@ async def on_print_start(printer_id: int, data: dict): # Build list of possible 3MF filenames to try possible_names = [] + # Bambu printers typically store files as "Name.gcode.3mf" + # The subtask_name is usually the best source for the filename + if subtask_name: + # Try common Bambu naming patterns + possible_names.append(f"{subtask_name}.gcode.3mf") + possible_names.append(f"{subtask_name}.3mf") + # Try original filename with .3mf extension if filename: - if filename.endswith(".3mf"): - possible_names.append(filename) - elif filename.endswith(".gcode"): - base = filename.rsplit(".", 1)[0] + # Extract just the filename part, not the full path + fname = filename.split("/")[-1] if "/" in filename else filename + if fname.endswith(".3mf"): + possible_names.append(fname) + elif fname.endswith(".gcode"): + base = fname.rsplit(".", 1)[0] + possible_names.append(f"{base}.gcode.3mf") possible_names.append(f"{base}.3mf") else: - # No extension - try adding .3mf - possible_names.append(f"{filename}.3mf") - possible_names.append(filename) - - # Try subtask_name with .3mf extension - if subtask_name and subtask_name != filename: - possible_names.append(f"{subtask_name}.3mf") + possible_names.append(f"{fname}.gcode.3mf") + possible_names.append(f"{fname}.3mf") # Remove duplicates while preserving order seen = set() @@ -107,15 +119,19 @@ async def on_print_start(printer_id: int, data: dict): temp_path.parent.mkdir(parents=True, exist_ok=True) for remote_path in remote_paths: - if await download_file_async( - printer.ip_address, - printer.access_code, - remote_path, - temp_path, - ): - downloaded_filename = try_filename - logger.info(f"Downloaded: {remote_path}") - break + logger.debug(f"Trying FTP download: {remote_path}") + try: + if await download_file_async( + printer.ip_address, + printer.access_code, + remote_path, + temp_path, + ): + downloaded_filename = try_filename + logger.info(f"Downloaded: {remote_path}") + break + except Exception as e: + logger.debug(f"FTP download failed for {remote_path}: {e}") if downloaded_filename: break diff --git a/backend/app/services/bambu_mqtt.py b/backend/app/services/bambu_mqtt.py index 69aca4da4..c0f4a9f00 100644 --- a/backend/app/services/bambu_mqtt.py +++ b/backend/app/services/bambu_mqtt.py @@ -1,6 +1,7 @@ import json import ssl import asyncio +import logging from collections import deque from datetime import datetime from typing import Callable @@ -8,6 +9,8 @@ from dataclasses import dataclass, field import paho.mqtt.client as mqtt +logger = logging.getLogger(__name__) + @dataclass class MQTTLogEntry: @@ -114,6 +117,12 @@ class BambuMQTTClient: """Process incoming MQTT message from printer.""" if "print" in payload: print_data = payload["print"] + # Log when we see gcode_state changes + if "gcode_state" in print_data: + logger.info( + f"[{self.serial_number}] Received gcode_state: {print_data.get('gcode_state')}, " + f"gcode_file: {print_data.get('gcode_file')}, subtask_name: {print_data.get('subtask_name')}" + ) self._update_state(print_data) def _update_state(self, data: dict): @@ -190,6 +199,13 @@ class BambuMQTTClient: self.state.raw_data = data + # Log state transitions for debugging + if "gcode_state" in data: + logger.debug( + f"[{self.serial_number}] gcode_state: {self._previous_gcode_state} -> {self.state.state}, " + f"file: {self.state.gcode_file}, subtask: {self.state.subtask_name}" + ) + # Detect print start (state changes TO RUNNING with a file) current_file = self.state.gcode_file or self.state.current_print is_new_print = ( @@ -206,6 +222,10 @@ class BambuMQTTClient: ) if (is_new_print or is_file_change) and self.on_print_start: + logger.info( + f"[{self.serial_number}] PRINT START detected - file: {current_file}, " + f"subtask: {self.state.subtask_name}, is_new: {is_new_print}, is_file_change: {is_file_change}" + ) self.on_print_start({ "filename": current_file, "subtask_name": self.state.subtask_name, @@ -218,6 +238,10 @@ class BambuMQTTClient: and self.state.state in ("FINISH", "FAILED") and self.on_print_complete ): + logger.info( + f"[{self.serial_number}] PRINT COMPLETE detected - state: {self.state.state}, " + f"file: {self._previous_gcode_file or current_file}" + ) self.on_print_complete({ "status": "completed" if self.state.state == "FINISH" else "failed", "filename": self._previous_gcode_file or current_file,