Added Spoolman support to add unknown Bambu Lab spools and track them

This commit is contained in:
Martin Ziegler
2025-11-30 19:37:36 +01:00
parent a862958deb
commit 8bc263ad02
3 changed files with 44 additions and 11 deletions
+7 -5
View File
@@ -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
+18 -1
View File
@@ -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(
+19 -5
View File
@@ -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.