Filament Inventory & Spoolman¶
BamDude ships with a first-class filament inventory (Settings → Filaments). It is the source of truth for spool weight, RFID, location, and cost — no external service required. If you already run Spoolman, the optional sync layer keeps both systems in step; if you don't, BamDude does the whole job on its own.
You don't need Spoolman
Built-in inventory works fully standalone. Spoolman sync is purely an integration choice for users who already centralise spools across multiple tools (e.g. OctoPrint, Mainsail, Klipper, multiple slicer hosts). Pick whichever flow matches your setup.
BamDude-native — no external service, no network round-trips, every column lives in data/bamdude.db.
Add-on integration with a self-hosted Spoolman server. Bidirectional, tunable per concern (weight vs. location vs. partial-usage reporting).
Built-in Inventory¶
Open Settings → Filaments. Each row is a physical spool — manually added, RFID-imported, or auto-created from an AMS scan.
Adding spools¶
The "Add Spool" form covers everything BamDude tracks per spool:
| Field | Notes |
|---|---|
brand |
Free text (e.g. Polymaker, Bambu Lab, SUNLU). |
material |
PLA, PETG, ABS, TPU, PA, PC, PVA, ASA, … |
subtype |
Basic, Matte, Silk, CF, Tough, … |
color_name + hex |
Free-text colour name plus an #RRGGBBAA swatch. The hex input normalises every keystroke — paste #FFAA00 and BamDude pads it to FFAA00FF. |
purchase_date |
When you actually bought it. Distinct from created_at (when the row was imported). The "Added" column prefers this when set. |
filament_diameter |
1.75 or 2.85. Defaulted to 1.75. |
label_weight_g |
Advertised net weight on the label (default 1000 g). |
core_weight |
Empty-spool weight, used for scale-based remaining calculations. Looked up from the catalog when brand+spool match. |
lot |
1-based position inside a purchase bundle. The bulk-add path can auto-number 1..N server-side via the auto-increment lots checkbox. |
cost_per_kg |
Bare number, no currency symbol. Multiplied by per-print weight for the archive's cost field. |
note |
Free-form text (Kitchen shelf, Open since Apr 12, …). |
tag_uid / tray_uuid |
RFID identifiers. Empty for manually-added spools — bind a tag later via the matcher. |
Bulk-add takes a quantity and creates N rows in one go — combine with auto-increment lots to number a 5-spool bundle as lot 1..5 without typing each one.
Spool display-name template¶
The Filaments page synthesises a human label per spool via a user-configurable template — search and sort use the same string. Edit it under Settings → System → Spool Display Template.
Default: {brand} {material} {color_name} (renders as e.g. Polymaker PLA Jade White).
| Token | Source | Example |
|---|---|---|
{brand} |
column | Polymaker |
{material} |
column | PLA |
{subtype} |
column | Matte |
{color_name} |
column | Jade White |
{slicer_filament_name} |
column | Polymaker PolyTerra PLA @Bambu Lab X1C |
{note} |
column | Kitchen shelf |
{label_weight_g} |
column | 1000 |
{label_weight_kg} |
computed | 1 (round) or 0.75 (fractional) |
{remaining_g} |
computed label − used |
750 |
{remaining_kg} |
computed | 0.75 |
{remaining_pct} |
computed | 75% |
{color_hex} |
computed from rgba |
#FF3300 |
{cost_per_kg} |
column | 25 |
{purchase_date} |
column | 2026-04-15 |
{filament_diameter} |
column | 1.75 |
{lot} |
column | 3 |
Unknown tokens stay verbatim
Typo a token like {brnd} and the live preview keeps it as-is — that surfaces the mistake immediately instead of silently collapsing to an empty space.
Column visibility¶
Click Column Config on the Filaments page to toggle which columns are visible and in what order. Settings are per-user.
Visible by default: brand, material, color_name, remaining, location, note, purchase_date.
Hidden by default: created_at ("added time" — superseded by purchase_date).
Newly-added columns land at their default position rather than being appended to the end, so post-upgrade existing users don't have to re-arrange.
Auto-assign by RFID¶
The Filaments page header has an Auto-assign action: BamDude scans every connected printer's AMS slots, matches each slot's tag_uid / tray_uuid against inventory rows, and creates SpoolAssignment records in bulk. Useful after a multi-spool reload — one click, no manual picking.
Bind unknown RFID to a manual spool¶
When an unknown RFID tag appears on a printer, the AMS slot popover offers to bind it to an existing inventory row that doesn't have a tag yet. Use case: third-party brands without RFID, refilled cores, or a spool you bought before you started using BamDude. Pick the row, confirm, and the tag is now attached — next scan auto-resolves.
Spoolman Sync¶
Optional. Connect BamDude to a Spoolman instance and the two systems mirror each other.
:material-spool: What is Spoolman?¶
Spoolman is an open-source, self-hosted filament inventory manager for 3D printing. It runs as a separate service (Docker, bare metal, or a Spoolman-compatible cloud instance) and exposes a REST API for spool tracking, usage history, vendor/material taxonomy, low-stock alerts, and — most importantly for multi-tool setups — a single source of truth that other tools (OctoPrint, Mainsail, Klipper, multiple slicer hosts) can sync against.
If you only run BamDude, the built-in inventory above already does everything Spoolman does. The integration is for users who already have Spoolman because some other host in their setup needs it.
Connecting¶
- Settings → Integrations → Spoolman
- Set the URL (e.g.
http://192.168.1.50:7912or a docker-compose service alias likehttp://spoolman:7912) - (Optional) API Key — required only if your Spoolman instance is behind authentication; leave blank for the default open setup.
- Test Connection
- Save
Network reachability
BamDude must be able to reach the Spoolman URL from inside its own process. On docker-compose, put both services on the same network and use the service alias; on bare metal, a LAN hostname or static IP is enough.
Sync controls¶
| Setting | Effect |
|---|---|
spoolman_enabled |
Master switch. |
spoolman_sync_mode |
auto (push every AMS change immediately) or manual (wait for an explicit Sync button click). |
spoolman_disable_weight_sync |
Skip remaining_weight updates on existing Spoolman spools — only push location. Use this when Spoolman is your authoritative weight tracker (its granular usage reporting beats AMS estimates). |
spoolman_report_partial_usage |
When a print fails or is cancelled, report the estimated grams used up to the abort point based on layer progress, instead of dropping the whole estimate. Helps Spoolman keep an accurate weight after failures. |
What syncs¶
- AMS slot ↔ Spoolman spool — Each loaded slot maps to a Spoolman spool ID. Material, brand, colour, and (unless
disable_weight_syncis on) remaining weight are kept in step. - Print consumption — Each completed print reports the grams used to Spoolman as a usage event. Cancelled / failed prints respect
spoolman_report_partial_usage. - Location — BamDude writes the printer name + AMS coordinates to Spoolman's
locationfield (H2D-1 AMS-A Slot 3etc.). Always synced even with weight sync disabled. - RFID — Bambu Lab tray UUIDs are passed through to Spoolman's tag field.
Unlinking¶
In manual sync mode, each Bambu spool card shows an Unlink button — useful when you want to migrate a spool from Spoolman back to BamDude-only inventory without breaking the AMS assignment.
Sync Results¶
After every sync (auto or manual) BamDude shows a result panel:
- Synced count — number of spools successfully synced.
- Skipped spools — list of spools that couldn't sync, with a per-row reason (e.g. "Non-Bambu Lab spool", "No matching material in Spoolman", "Manual unlink in effect"). Each skipped row shows its location, color swatch, and the reason text.
- Errors — any HTTP / network / data errors encountered during the run.
Bambu Lab RFID detection
Auto-sync only fires for official Bambu Lab spools with RFID — third-party, refilled, or SpoolEase spools are intentionally skipped to avoid creating bogus rows in Spoolman. Bambu Lab spools are identified by their hardware identifiers (tray_uuid and tag_uid), not by filament preset name. Non-Bambu spools can still be manually linked (see below).
Usage tracking detail¶
Each completed print reports per-filament consumption to Spoolman as a usage event:
- BamDude extracts per-filament usage data from the archived 3MF file (slicer estimates).
- For partial prints (failures, cancellations), per-layer G-code analysis provides precise consumption up to the exact failure layer.
- On completion, each spool's usage is reported individually — multi-material prints update each linked spool separately.
- AMS remain-% fallback for slots the 3MF didn't cover. When a slot has no 3MF estimate — a no-3MF "Untitled" print (the
.gcode.3mfwas never downloadable, so the archive is a fallback row) or partial 3MF coverage where a loaded slot wasn't in the slice info — BamDude falls back per-slot to the AMS remaining-percentage drop. At completion it writes(remain% at start − remain% at end) × the spool's Spoolman filament reference weightgrams as the usage event. It uses the Spoolman reference weight (not the AMS's unreliable reported tray weight) and skips any slot swapped mid-print (tray UUID changed), since it can't split consumption across two spools. Before this, no-3MF "Untitled" prints reported zero weight change to Spoolman.
This matches BamDude's per-spool tracking model — the same numbers feeding the Stats page also feed Spoolman, just routed through Spoolman's usage-history table on top of BamDude's local archive.
AMS slot mapping (hover card)¶
Hover over any AMS slot on the Printers page to see:
| Field | Source |
|---|---|
| Vendor | Bambu Lab or Generic — read from the RFID tag. |
| Profile | Filament type and subtype (PLA Basic, PETG Translucent, …). |
| Color | Color name + swatch — resolved through the BamDude color catalog (single source of truth). |
| K Factor | Pressure-advance value currently active for this slot. |
| Fill Level | Remaining percentage, with visual bar. |
| Spool ID | Linked Spoolman spool ID (only when Spoolman is enabled and the slot is linked). |
Fill Level for AMS Lite / external spools¶
AMS Lite units (e.g. A1 series) have no weight sensor and always report 0% fill level. When a spool is linked to Spoolman and Spoolman has weight data, BamDude uses Spoolman's remaining weight instead:
- AMS with weight sensor — uses AMS percentage directly (no change).
- AMS Lite (reports 0%) — falls back to Spoolman:
(remaining_weight / filament_weight) × 100. - External spool — shows fill level from Spoolman if linked (otherwise shows
—).
When Spoolman data is the source, the hover card displays "(Spoolman)" next to the percentage so you can distinguish the data source.
Open / Link / Manual link buttons¶
Each AMS slot's hover card carries a primary action button whose label depends on link state:
| State | Button | What it does |
|---|---|---|
| Linked | Open in Spoolman | Opens the spool's page in Spoolman in a new tab — edit vendor, cost, notes, weight directly there. |
| Unlinked, Bambu Lab spool, candidates available | Link to Spoolman | Opens a picker showing all unlinked Spoolman spools — pick one, click Link to confirm. |
| Unlinked, Bambu Lab spool, no candidates | Link to Spoolman (disabled) | No unlinked Spoolman spools currently available — add one in Spoolman first. |
| Non-Bambu Lab spool | Manual Link | Manually associate this slot with a Spoolman spool — bypasses RFID matching for refilled cores or third-party spools. |
To unlink: open the spool in Spoolman and clear the extra.tag field.
Adding spools — AMS vs Inventory view comparison¶
| Surface | Action | When to use |
|---|---|---|
| From AMS hover | Add to Spoolman when an unknown filament appears in a slot | First-time onboarding, adding a freshly-loaded Bambu spool to Spoolman. |
| In Spoolman directly | Add Spool form on Spoolman's web UI | Bulk-import historical spools, adding spools you haven't loaded yet, vendor/cost data entry. |
| Inventory view (BamDude) | Add via Settings → Filaments | When you want the spool to live in BamDude's inventory regardless of Spoolman state — useful for full-detail rows that Spoolman doesn't track (e.g. lot number, custom notes). |
Both backends co-exist; the link is what lets the AMS hover card resolve a slot to a Spoolman row.
Auto-features¶
Three independent automation toggles (Settings → Spoolman):
- Auto-sync on print complete — every completed print reports per-filament usage individually to Spoolman, so spool quantities update automatically.
- Auto-detect on AMS change — when AMS filament changes, BamDude detects the new configuration, matches against Spoolman, and updates slot mappings without intervention.
- Auto-clear location on removal — when spools are removed from AMS, BamDude detects the empty slot, finds Spoolman spools with the matching location string, and clears the
locationfield. The spool is now available for other printers.
Location format
Spoolman locations follow the format Printer Name - AMS X Slot Y, e.g. H2D-Workshop - AMS A Slot 3.
Multi-printer sync¶
A single Spoolman instance serves multiple BamDude printers (and other tools) simultaneously:
- Each printer's AMS syncs independently.
- Different spools per printer, separate usage tracking.
- Unified inventory in Spoolman — one source of truth across the farm.
This is the main reason most farm operators choose to run Spoolman alongside BamDude even when BamDude's built-in inventory works standalone — Spoolman is the cross-tool hub.
Inventory UI (BamDude-side, Spoolman-backed)¶
When you run BamDude against Spoolman, the Inventory page (/inventory) and Printers page (/) light up a full first-class Spoolman experience: AMS slot assignments live in BamDude's own tables (so the assignment survives reboots and travels in BamDude backups), K-profiles per spool round-trip across BamDude installs that share the same Spoolman backend, and a free-form storage label sits next to every spool. Built on upstream Bambuddy #1241 ported in BamDude 0.4.4.
Three new pieces of state¶
| Where | What | Why it isn't on Spoolman directly |
|---|---|---|
spoolman_slot_assignments (BamDude DB) |
Which Spoolman spool ID lives in (printer_id, ams_id, tray_id). AMS 0..7 + 255 (external feed). One spool per slot. |
Spoolman's own location is free text — using it as the source of truth for "this spool is in printer X AMS A slot 3" loses structure (e.g. you can't filter inventory by "all spools currently loaded"). The structured table is queryable and gets cleared automatically on slot empty. |
spoolman_k_profile (BamDude DB) |
Pressure-advance + setting_id per (spoolman_spool_id, printer_id, extruder, nozzle_diameter). Single + dual extruder. |
A K-profile is bound to physical filament ↔ physical printer + nozzle, not to a Spoolman row alone. Storing it BamDude-side means re-tapping the same Bambu RFID on a different printer doesn't lose the calibration done elsewhere. |
spool.storage_location (BamDude DB column) |
Free-form label like Drybox 3, Shelf A4, Workshop / locker 2. |
Mirrors the Spoolman location field but lives BamDude-side too so it shows in the Inventory page columns + the spool form even on Spoolman-mode installs. |
The Spoolman location field is left untouched on Spoolman's side — operators can still populate it manually from Spoolman's own UI as a free-text label. BamDude's structured assignment table is the source of truth for "what's currently in printer X".
Printers page — Spoolman-mode slot integration¶
Every slot kind on the Printers page reads Spoolman state when Spoolman mode is on:
- Regular AMS slots (AMS 0..7, tray 0..3) — fill bar, preset name, color swatch, and the hover card "Assigned spool" pill all read from
spoolman_slot_assignmentsjoined againstspoolman_inventory/spools. When the slot has no RFID-linked spool, the slot-assignment row drives the fill computation. - HT (high-temperature) slots — same flow as regular AMS, plus the H2D Ext-R single-tray external slot.
- External Spool 254 / 255 — reads from the same assignment table; the slot's hover card shows the assigned spool name + remaining weight + storage location.
Per slot the hover card carries:
| Button | When it appears |
|---|---|
| Link to Spoolman | Slot has a Bambu RFID tag, no assignment exists yet, and there's at least one unlinked Spoolman spool whose extra.tag matches. |
| Manual Link | Slot has no RFID match (refilled core, third-party spool). Picker shows every unlinked Spoolman spool. |
| Assign | Slot is empty in inventory but operator wants to manually point it at a Spoolman spool (no RFID involved). |
| Unassign | Slot has either a Spoolman SlotAssignment OR a local SpoolAssignment — clears the BamDude-side assignment. |
| Open in Spoolman | Slot is RFID-linked. Opens the spool's Spoolman edit page in a new tab. |
The Link button auto-suppresses when a slot already has either a Spoolman SlotAssignment OR a local SpoolAssignment, so the operator can't accidentally double-bind.
K-profile auto-reapply on AMS change¶
When an AMS slot's contents change (RFID re-tap, slot reset, slicer-side extrusion_cali_sel issued from another path), BamDude looks up the assigned spool's stored K-profile for the exact (printer_id, extruder, nozzle_diameter) triplet. If the printer's live cali_idx differs from the stored K-profile's, BamDude re-issues the right extrusion_cali_sel over MQTT to restore the K-value the operator chose last time. Without this, firmware would reset the K back to slot index 0 on every re-tap.
Drift detection is bounded — BamDude only re-issues when there's a genuine difference, so the steady-state push doesn't spam the printer.
:material-storage: Storage location column¶
Settings → Filaments (Inventory page) gains a Storage location column shipped on every backend (local-DB inventory + Spoolman). Edit per row inline; the value is stored on spool.storage_location and surfaced everywhere the spool is rendered (cards, hover-cards, spool form, search). On Spoolman-mode installs the field is BamDude-local — Spoolman's own location field stays for the operator to manage independently if they prefer that flow.
Wider RFID UID support¶
BamDude widens spool.tag_uid from 16 to 32 chars on Postgres (SQLite ignores VARCHAR length). Bambu's RFID UIDs are 16 hex chars, but third-party tags (e.g. NTAG216 stickers) carry up to 32 hex chars — the wider column lets you bind those tags to refilled cores without truncation.
API surface¶
The full Spoolman inventory feature ships under /api/v1/spoolman/inventory/* (19 endpoints, all gated on RequirePermission(INVENTORY_*)). Highlights worth knowing about for scripting:
GET /spoolman/inventory/spools+GET /spoolman/inventory/spools/{id}— list / single spool with BamDude joins (slot assignment, storage location, K-profile counts).POST /spoolman/inventory/spools+POST /spoolman/inventory/spools/bulk+PATCH /spoolman/inventory/spools/{id}— create / bulk-create / update.POST /spoolman/inventory/spools/{id}/archive+/restore— soft-delete via Spoolman's archive flag.POST /spoolman/inventory/slot-assignments+DELETE /spoolman/inventory/slot-assignments/{id}— assign / unassign.GET /spoolman/inventory/slot-assignments— list-all-enriched (joined with spool data).POST /spoolman/inventory/spools/{id}/sync-weight— pull current AMS weight into the spool row.POST /spoolman/inventory/ams-weights/sync— bulk sync every assigned slot's weight in one call.GET /spoolman/inventory/spools/{id}/k-profiles+POST /spoolman/inventory/spools/{id}/k-profiles— per-spool K-profile read / save.PATCH /spoolman/inventory/filaments/{id}— rename + propagatespool_weightto every spool of that filament (togglekeep_existing_spoolsto cap the cascade).GET /spoolman/inventory/filaments+POST /spoolman/inventory/spools/{id}/link-tag— picker queries.
Full API contract: API Reference → Spoolman Inventory.
Moving off Spoolman: one-way import¶
Sync above keeps Spoolman as the source of truth. If you would rather stop
running Spoolman and keep its data, scripts/import_spoolman.py copies its
spools into BamDude's own inventory once, over the API:
python scripts/import_spoolman.py \
--spoolman-url http://localhost:7912 \
--bamdude-url http://localhost:8000 \
--api-key <a BamDude API key with inventory:update> \
--dry-run
Drop --dry-run to write. Each spool carries over its material, colour, brand,
label weight, used weight, cost per kg (computed from Spoolman's per-spool
price) and tag UID; the note records the Spoolman id it came from, so a second
run is easy to spot and undo.
It is an import, not a sync
It runs once and does not look back. Turn Spoolman sync off first, or the two will each believe they own the same spools.
Troubleshooting¶
Connection failed
- Verify the Spoolman URL — open it in a browser to confirm Spoolman itself is up.
- Check network reachability from inside the BamDude container/process to Spoolman (e.g.
curl http://spoolman:7912/api/v1/infofrom inside the BamDude container). - If Spoolman has authentication enabled, double-check the API Key.
- Firewall / Docker network isolation — both services need to be on the same network or have explicit routing.
Sync not working
- Confirm
spoolman_enabledis on and Test Connection still passes. - Check Spoolman's own logs — newer / older Spoolman versions occasionally tighten or change their REST contract.
- Verify the spool is recognised as Bambu Lab (auto-sync only fires for Bambu RFID — see above). For non-Bambu spools, use Manual Link.
- For multi-printer setups, confirm the printer name in BamDude matches the location string Spoolman expects.
Wrong spool linked
- Open the spool in Spoolman, clear the
extra.tagfield to unlink. - From BamDude's AMS hover card, Manual Link → pick the correct Spoolman spool.
- Verify the RFID tag UUID matches what Spoolman has stored — mismatched UUIDs are the most common cause of "linked, but pointing at the wrong row".
Originally based on Bambuddy documentation.