From 8bc263ad025e7ce20c21eb368dd5e69c13ae14d0 Mon Sep 17 00:00:00 2001 From: Martin Ziegler Date: Sun, 30 Nov 2025 19:37:36 +0100 Subject: [PATCH] Added Spoolman support to add unknown Bambu Lab spools and track them --- README.md | 12 +++++++----- backend/app/main.py | 19 ++++++++++++++++++- backend/app/services/spoolman.py | 24 +++++++++++++++++++----- 3 files changed, 44 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 4433d77a9..eda55d25d 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,7 @@ v∆v - **Spoolman Integration** - Sync AMS filament data with your Spoolman server - Automatic or manual sync modes - Per-printer or all-printer sync + - Auto-creates spools and filaments in Spoolman - Matches Bambu Lab spools by unique tray UUID - Tracks filament usage during prints - Third-party spools (SpoolEase, etc.) gracefully skipped @@ -644,17 +645,18 @@ Bambusy matches AMS spools to Spoolman spools using the **tray UUID** - a unique - Remaining filament weight (from AMS sensor) - Filament usage during prints (deducted from Spoolman inventory) +**Auto-Creation:** +- When a Bambu Lab spool is detected that doesn't exist in Spoolman, it's automatically created +- Filament types are matched by material and color, or created if needed +- The "Bambu Lab" vendor is auto-created if it doesn't exist +- New spools include a comment noting they were auto-created + **Limitations:** - Only **Bambu Lab original spools** can be synced (they have valid tray UUIDs) - Third-party spools (SpoolEase, refilled spools, etc.) are gracefully skipped - they won't cause errors -- Spools must exist in Spoolman before syncing - Bambusy doesn't create new spools automatically #### Troubleshooting Spoolman -**"Spool not found in Spoolman" errors:** -- The Bambu Lab spool exists in your AMS but hasn't been added to Spoolman yet -- Add the spool in Spoolman's web interface, matching the filament type and color - **Third-party spools showing in AMS:** - SpoolEase and other third-party spools are automatically skipped during sync - This is normal behavior - they don't have Bambu Lab tray UUIDs diff --git a/backend/app/main.py b/backend/app/main.py index 93fc06c10..5f13a34d8 100644 --- a/backend/app/main.py +++ b/backend/app/main.py @@ -69,7 +69,7 @@ from backend.app.services.bambu_ftp import download_file_async from backend.app.services.smart_plug_manager import smart_plug_manager from backend.app.services.tasmota import tasmota_service from backend.app.models.smart_plug import SmartPlug -from backend.app.services.spoolman import get_spoolman_client, init_spoolman_client +from backend.app.services.spoolman import get_spoolman_client, init_spoolman_client, close_spoolman_client # Track active prints: {(printer_id, filename): archive_id} @@ -933,6 +933,22 @@ async def lifespan(app: FastAPI): async with async_session() as db: await init_printer_connections(db) + # Auto-connect to Spoolman if enabled + async with async_session() as db: + from backend.app.api.routes.settings import get_setting + spoolman_enabled = await get_setting(db, "spoolman_enabled") + spoolman_url = await get_setting(db, "spoolman_url") + + if spoolman_enabled and spoolman_enabled.lower() == "true" and spoolman_url: + try: + client = await init_spoolman_client(spoolman_url) + if await client.health_check(): + logging.info(f"Auto-connected to Spoolman at {spoolman_url}") + else: + logging.warning(f"Spoolman at {spoolman_url} is not reachable") + except Exception as e: + logging.warning(f"Failed to auto-connect to Spoolman: {e}") + # Start the print scheduler asyncio.create_task(print_scheduler.run()) @@ -941,6 +957,7 @@ async def lifespan(app: FastAPI): # Shutdown print_scheduler.stop() printer_manager.disconnect_all() + await close_spoolman_client() app = FastAPI( diff --git a/backend/app/services/spoolman.py b/backend/app/services/spoolman.py index e07f6bbd7..a675fc858 100644 --- a/backend/app/services/spoolman.py +++ b/backend/app/services/spoolman.py @@ -586,12 +586,26 @@ class SpoolmanClient: location=location, ) - # Spool not found in Spoolman - log warning but don't create new - logger.warning( - f"Bambu Lab spool with tray_uuid {tray.tray_uuid} not found in Spoolman. " - f"Add this spool to Spoolman first to enable syncing." + # Spool not found - auto-create it + logger.info( + f"Creating new spool in Spoolman for {tray.tray_sub_brands} " + f"(tray_uuid: {tray.tray_uuid[:16]}...)" + ) + + # First find or create the filament type + filament = await self._find_or_create_filament(tray) + if not filament: + logger.error(f"Failed to find or create filament for {tray.tray_sub_brands}") + return None + + # Create the spool with tray_uuid stored as "tag" in extra field + return await self.create_spool( + filament_id=filament["id"], + remaining_weight=remaining, + location=location, + comment=f"Auto-created from {printer_name} AMS", + extra={"tag": tray.tray_uuid}, ) - return None async def _find_or_create_filament(self, tray: AMSTray) -> dict | None: """Find existing filament or create new one.