Note
This is a daily beta build (2026-03-25). It contains the latest fixes and improvements but may have undiscovered issues.
Docker users: Update by pulling the new image:
docker pull ghcr.io/maziggy/bambuddy:daily
or
docker pull maziggy/bambuddy:daily
**Tip:** Use [Watchtower](https://containrrr.dev/watchtower/) to automatically update when new daily builds are pushed.
New Features
- Missing Spool Assignment Notification (#763) — When a print starts and the AMS mapping references tray slots without assigned spools, Bambuddy now shows a warning toast in the frontend and can send push notifications via any configured notification provider. The notification includes the printer name, missing slot labels (e.g. A2, Ext-L), and expected material profile. A new "Missing Spool Assignment" toggle is available under Print Events in notification provider settings (off by default). Fully integrated with i18n (all 7 locales). Contributed by Keybored02.
- Mid-Print Spool Reassignment Tracking (#763) — Usage tracking now correctly handles spool changes during a print. If a spool assignment is changed after a print starts, the system uses the live assignment for filament deduction; otherwise it falls back to the snapshot taken at print start. This ensures accurate filament tracking even when swapping spools mid-print. Contributed by Keybored02.
- Auto-Link Untagged Inventory Spools on AMS Insert (#538) — When a Bambu Lab spool is inserted into the AMS and no existing tag match is found, the system now checks if there is an untagged inventory spool with the same material, subtype, and color. If found, the RFID tag is automatically linked to that existing spool instead of creating a duplicate entry. Uses FIFO ordering (oldest spool first) so spools are consumed in purchase order. Matching is case-insensitive. Requested by wreuel.
- External Folder Mounting for File Manager (#124) — Host directories (NAS shares, USB drives, network storage) can now be mounted into the File Manager without copying files. Click "Link External" to point at a Docker bind-mounted path. Files are indexed into the database on scan but accessed directly from their original location — nothing is copied. Supports read-only mode (default, blocks uploads/moves/deletes), hidden file filtering, and automatic thumbnail extraction for 3MF, STL, gcode, and image files. External folders show a distinct icon and info bar with a rescan button. Deleting an external folder only removes the database index, never the actual files. Requested by S1N4X.
Improved
- SpoolBuddy AMS Slot Action Picker — Clicking an AMS slot on the SpoolBuddy AMS page now shows a picker with contextual actions: Configure AMS Slot (set filament preset, K-profile, color), and either Assign Spool / Link to Spoolman (when no spool is mapped) or Unassign / Unlink (when one is). Works with both internal inventory and Spoolman. Previously the slot click went straight to the configure modal with no way to manage spool assignments.
- Unassign Button in Edit Spool Modal — The edit spool modal now has an "Unassign" button next to "Delete Tag" that removes the spool's AMS slot assignment, clearing the location column in the inventory table.
- SpoolBuddy Settings Device Tab No Longer Scrolls — Removed the branding card, folded Device ID into the Device Info card, placed Backend/Auth config and diagnostic buttons side by side in a 2-column layout, removed the redundant online/offline status row from Device Info, and tightened spacing throughout. The Device tab now fits on the small SpoolBuddy touchscreen without scrolling.
- Spool Notes in Assign Spool Modal (#793) — Spool cards in the Assign Spool modal now show the spool's note as a hover tooltip, making it easier to identify spools by tracking IDs or other metadata stored in notes. Works with both internal inventory and Spoolman-synced spools. Requested by LegionCanadian.
- WiFi Safeguard for SpoolBuddy Pi — The install script now drops an APT hook (
/etc/apt/apt.conf.d/80-preserve-wifi) that backs up NetworkManager WiFi connections before everyapt upgradeand restores them if they get wiped. Prevents headless SpoolBuddy Pis from losing WiFi connectivity after Raspberry Pi OS package upgrades (observed with Bookworm kernel/raspi-config updates that clear/etc/NetworkManager/system-connections/). - SpoolBuddy Install Script Now Upgrades System Packages — The install script now runs
apt-get upgrade -yafter installing required packages and the WiFi safeguard. This ensures the Pi is fully up to date before SpoolBuddy is deployed, and the WiFi safeguard protects connectivity during the upgrade.
Fixed
- Delete Tag Leaves Stale Tag Type — The "Delete Tag" button in the spool edit modal only cleared
tag_uidbut lefttray_uuid,tag_type, anddata_originintact. All tag-related fields are now cleared together. - SpoolBuddy NFC Write Fails on NTAG Tags — Multiple issues prevented writing to NTAG 213/215/216 tags. (1) Some chips report SAK
0x04(MIFARE Ultralight family) instead of0x00during anticollision — both0x00and0x04are now accepted. (2) TX CRC was disabled for NTAG commands but the spec requires it — enabled for both WRITE and READ. (3) The PN5180 state machine needed IDLE→TRANSCEIVE resets (not justset_transceive_mode()) and Crypto1 cleared before NTAG operations. (4) The 4-bit WRITE ACK cannot be captured by the PN5180 (SOF detected but no RX_IRQ) — removed per-page ACK checking. (5) Post-write read-back verification also failed (second READ command gets no response from the PN5180) — removed verification since the tag reliably ACKs each write. - Database Connection Pool Exhaustion on Large Printer Farms — Users with 100+ printers connected simultaneously experienced
QueuePool limit of size 10 overflow 20 reached, connection timed outerrors. Increased the SQLAlchemy connection pool from 30 total (10 base + 20 overflow) to 220 (20 base + 200 overflow), and raised the SQLite busy_timeout from 5 to 15 seconds to reduce write contention under heavy concurrent MQTT updates. - SpoolBuddy Update Check Always Shows "Up to Date" — The SpoolBuddy daemon update check compared the device's firmware version against GitHub releases instead of the running Bambuddy backend version. This meant the check could incorrectly report "up to date" even when the daemon was behind. Fixed by comparing directly against
APP_VERSIONfrom the backend config. - SpoolBuddy Updates Now Use SSH — Replaced the fragile self-update mechanism (daemon pulls its own code via git, permission errors on
.git/, hardcodedmainbranch) with SSH-based updates driven by the Bambuddy backend. Bambuddy now SSHes into the SpoolBuddy Pi and runs git fetch/checkout, pip install, systemctl restart, and kiosk browser restart remotely. Updates automatically use the same branch as Bambuddy. SSH key pairing is fully automatic — Bambuddy generates an ED25519 keypair and includes the public key in the device registration response; the daemon deploys it toauthorized_keyson first connect. The install script creates thespoolbuddyuser with a bash shell and sudoers entries for daemon and kiosk restart. A "Force Update" button allows re-deploying even when versions match. The SSH public key is also shown in SpoolBuddy Settings → Updates → SSH Setup for manual pairing if needed. - Frontend Not Updating After Deploy — The service worker used stale-while-revalidate for JS/CSS assets, serving the old cached bundle even after a new build was deployed. Changed to network-first for JS/CSS (Vite content-hashes filenames so cache-busting is built in), bumped SW cache version, and added
Cache-Control: no-cacheto thesw.jsendpoint so browsers always pick up new service worker versions immediately. The SpoolBuddy kiosk now skips SW registration entirely and unregisters any existing SW — a touchscreen kiosk has no use for offline caching and it was the main source of stale frontend issues after updates. - SpoolBuddy Kiosk Starts Before Network Is Ready — On fresh installs, the kiosk browser launched before the network was fully up, showing a connection error for 10-15 seconds until connectivity was restored. The gettytty1 autologin override now waits for
network-online.targetso Chromium has connectivity when it starts. - SpoolBuddy Update UI Stale After Restart — After a SpoolBuddy update, the UI permanently showed the old version and "update available" because: (1) the SSH update set status to
"complete"after the daemon had already re-registered, overwriting the cleared state; (2) the kiosk restart navigated away from the updates page; (3) query cache served stale data. Fixed by letting daemon re-registration clear all update status, removing the kiosk restart in favor of a frontend-drivenwindow.location.reload()triggered via WebSocket when the daemon comes back online, and adding proper loading states to Check/Force Update buttons. - Virtual Printer Proxy A1 Printing Fails (#757) — BambuStudio could not send prints to A1 (and potentially P1S) virtual printers in proxy mode. The slicer connects to undocumented proprietary ports 2024-2026 on these models, which the proxy was not forwarding, causing BambuStudio to show an access code dialog instead of printing. Added transparent TCP pass-through proxying for ports 2024-2026. These ports are silently ignored on models that don't use them (X1C, H2C, P2S). Also added ports 2024-2026 to the docker-compose.yml bridge-mode port mapping. Reported by Utility9298.
- Spool Assignment on Empty AMS Slots (#784) — Empty AMS slots (no physical spool detected) showed "Assign Spool" and "Configure" buttons in the hover popup. Assigning a spool to an empty slot created a stuck state because no "Unassign" button is available for empty slots. Truly empty slots now hide both buttons, while slots with a spool inserted but filament not loaded still show configure/assign. Also fixed stale AMS slot data on H2D and other printers that only send
{id, state}in incremental MQTT updates — filament load/unload transitions now update in real-time without requiring a reconnect. Reported by RosdasHH. - Spoolman Sidebar Opens Root URL Instead of Spool Page — When Spoolman is enabled, clicking the Filament sidebar item embedded Spoolman at its root URL instead of the spool management page. The iframe now navigates to
<spoolman_url>/spool. - Log Flood: "State is FINISH but completion NOT triggered" (#790) — A diagnostic log message introduced in 0.2.2.1 fired on every MQTT update while a printer sat in FINISH or FAILED state, flooding logs with thousands of lines per minute in printer farms. Fixed by only logging once on the initial state transition, and marking
_completion_triggered = Truewhen a terminal state is first seen without a prior RUNNING state so the flag is clean for the next print cycle. Reported by user. - H2D External Spool Print Fails With "Failed to get AMS mapping table" (#797) — Printing from an external spool on H2D (and H2D Pro) through Bambuddy failed with
0700_8012 "Failed to get AMS mapping table", while the same print worked fine from BambuStudio. Bambuddy was passing raw virtual tray IDs (254/255) in the flatams_mappingarray, but BambuStudio converts these to -1 and relies onams_mapping2for external spool routing. The H2D firmware rejects raw 254/255 in the flat array. Also fixed theams_mapping2format for external trays — each virtual tray is its own AMS unit withslot_id: 0, not a shared unit differentiated by slot. Reported by Lukas-ESG. - SpoolBuddy Scale First Reading Always Wrong — The NAU7802 ADC always returns a stale max-scale value (
0x7FFFFF) on its first conversion after power-up, which polluted the moving average and made the initial weight report wildly inaccurate. Fixed by flushing the first reading duringinit()so all subsequent reads return valid data. Also extracted both hardware drivers out of diagnostic scripts into proper modules — the NAU7802 scale driver fromscripts/scale_diag.pyintodaemon/nau7802.py, and the PN5180 NFC driver fromscripts/read_tag.pyintodaemon/pn5180.py. The production daemon was importing driver classes from test scripts since the original SpoolBuddy commit. Removed the now-unnecessarysys.pathhack frommain.py. - ffmpeg Process Leak Causing Memory Growth (#776) — Camera stream ffmpeg processes accumulated over time, consuming several GB of RAM. When a user closed the camera viewer, the frontend sent a stop signal that killed the ffmpeg process, but the backend stream generator interpreted the dead process as a dropped connection and respawned ffmpeg — up to 30 reconnection attempts per stream. The orphan cleanup couldn't catch these because they were tracked as "active". Fixed by signaling the generator's disconnect event from the stop endpoint before killing the process, checking for stream removal before reconnecting, and tracking frame timestamps per-stream instead of per-printer so stale detection works correctly when multiple streams exist. Reported by ChrisTheDBA, confirmed by peter-k-de.