github maziggy/bambuddy v0.2.3b2-daily.20260408
Daily Beta Build v0.2.3b2-daily.20260408

pre-release7 hours ago

Note

This is a daily beta build (2026-04-08). 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

  • Optional PostgreSQL Database Support — Bambuddy can now use an external PostgreSQL database instead of the built-in SQLite. Set the DATABASE_URL environment variable (e.g., postgresql+asyncpg://user:passhost:5432/bambuddy) to connect to Postgres. SQLite remains the default when no DATABASE_URL is set. All features work with both backends including full-text archive search (FTS5 on SQLite, tsvector+GIN on PostgreSQL), backup/restore (file copy vs pg_dump/pg_restore), health diagnostics, and cross-database restore (import a SQLite backup into PostgreSQL with automatic type conversion and FK handling).
  • Shortest Job First Queue Scheduling (#879) — New SJF toggle badge on the queue page header. When enabled, the scheduler starts shorter print jobs before longer ones instead of FIFO order. A starvation guard ensures long jobs that get skipped once are protected from being skipped again — they move to the front of the queue on the next cycle. The queue display automatically reorders to show the scheduler's actual execution order. Print duration is cached on queue items at creation time from the 3MF metadata.
  • Auto-Print G-code Injection (#422) — Configure custom start and end G-code snippets per printer model in Settings (Workflow tab) for bed-clearing systems like Farmloop, SwapMod, AutoClear, and Printflow 3D. When adding a print to the queue, enable "Inject G-code" to have the scheduler inject the configured snippets into the 3MF before uploading to the printer. The original file is never modified — injection creates a temporary copy for upload only.
  • External Folder Subfolder Preservation (#890) — Scanning an external folder now mirrors the real directory structure into the file manager folder tree instead of flattening all files into the root. Subdirectories are created as child LibraryFolders with correct parent/child hierarchy, and files are assigned to their matching subfolder. Hidden directories are skipped when "Show hidden files" is disabled. Subfolders that are deleted from disk are automatically cleaned up on the next scan. Created subfolders inherit the parent's read-only and show-hidden settings.
  • LDAP Authentication (#794) — Users can now authenticate against an LDAP/Active Directory server. Configure the LDAP server URL, bind DN, search base, and user filter in Settings > Authentication > LDAP. Supports StartTLS, LDAPS (SSL), and plaintext connections. LDAP groups can be mapped to BamBuddy groups (Administrators, Operators, Viewers) for automatic role assignment. Auto-provisioning creates BamBuddy accounts on first LDAP login when enabled. Local admin accounts remain as fallback when the LDAP server is unreachable. Password management features (change password, forgot password, admin reset) are automatically disabled for LDAP users.
  • SpoolBuddy Quick Menu (#893) — Swipe down from the top of the SpoolBuddy display to open a quick-access control panel. Toggle printer power via smart plugs directly from the display, and manage the SpoolBuddy system with restart daemon, restart browser, reboot, and shutdown controls. All destructive actions require confirmation. The menu shows real-time smart plug state (ON/OFF) for each printer that has a linked power plug.

Improved

  • Database Engine Info on System Page — The System Information page now shows the active database engine (SQLite or PostgreSQL) and its version in the Database section, making it easy to verify which backend is in use.
  • Plate Number in Printer View (#881) — Printer cards and the stream overlay now show the plate number alongside the filename when printing plate 2+ of a multi-plate 3MF file (e.g. "MyModel — Plate 3"). Single-plate prints are unchanged.
  • Printer Name in Queue for Model-Based Jobs (#881) — Queue items assigned to a printer type ("Any P1S") now show the actual printer name once the scheduler assigns a specific printer, instead of continuing to display the generic model target while printing or in history.
  • AMS Drying Support for H2S (#886) — Remote AMS drying and queue auto-drying now work on H2S printers with firmware 01.02.00.00 or later.
  • REST Smart Plug: Separate Power/Energy URLs and Unit Multipliers (#472) — REST/Webhook smart plugs can now use individual URLs for power and energy data instead of requiring all values in a single status response. Each value falls back to the shared Status URL when no separate URL is configured, so existing setups work without changes. Added power and energy multipliers for unit conversion (e.g., set energy multiplier to 0.001 to convert Wh to kWh). Useful for platforms like ioBroker that expose each data point as a separate API endpoint.

Security

  • Path Traversal in File Upload Endpoints — Archive upload endpoints (/upload, /upload-bulk, /{id}/source, /source-by-name, /{id}/f3d, /{id}/timelapse) used the client-supplied filename directly in file paths without stripping directory components. An authenticated attacker could write files outside the intended directory via directory traversal (e.g. ../../evil.3mf). All upload endpoints now sanitize filenames by extracting only the basename before constructing paths. Reported responsibly by Sacha Vaudey via securitybambuddy.cool.
  • Unauthenticated Bug Report Endpoints — The bug report endpoints (/start-logging, /stop-logging, /submit) had no authentication, allowing anyone on the network to enable debug logging, retrieve system logs, and trigger bug report submissions with system diagnostics when authentication was enabled. All three endpoints now require authentication — start-logging requires settings:update permission, stop-logging and submit require settings:read. Endpoints remain open when authentication is disabled (the default). Reported responsibly by Sacha Vaudey via securitybambuddy.cool.
  • API Key Empty Printer List Grants Full Access — An API key with an empty printer_ids list ([]) was treated identically to null (global access to all printers), granting full printer access instead of no access. Now null means global access (admin key) and [] means no printer access. Existing API keys with empty lists are automatically migrated to null on startup. Also fixed the webhook queue endpoint which used a falsy check that would bypass the filter for empty lists. Reported responsibly by Sacha Vaudey via securitybambuddy.cool.
  • Missing HTTP Security Headers — API responses did not include standard security headers. Added a middleware that sets X-Content-Type-Options: nosniff (prevents MIME-sniffing), X-Frame-Options: DENY (prevents clickjacking via iframe embedding), and Referrer-Policy: strict-origin-when-cross-origin (limits URL leakage to external services) on every response. Content-Security-Policy was omitted because the React SPA uses inline styles extensively and a permissive CSP would provide no meaningful protection. Strict-Transport-Security was omitted because Bambuddy is a LAN application commonly accessed over HTTP — HSTS would lock users out. Reported responsibly by Sacha Vaudey via securitybambuddy.cool.
  • Camera Snapshot Temp Files World-Readable — Camera snapshot and plate detection endpoints created temporary JPEG files in /tmp with default 0644 permissions, making them readable by any local user. Switched from NamedTemporaryFile(delete=False) to mkstemp with explicit 0600 permissions so only the application user can read them. Cleanup was already handled via finally blocks. Reported responsibly by Sacha Vaudey via securitybambuddy.cool.

Fixed

  • Spool Weight Not Updated After Print (#839) — Filament usage tracking failed silently in several scenarios: (1) when FTP download failed and a fallback archive was created without a 3MF file, the primary tracking path was skipped entirely — now falls back to matching the 3MF from the library or a previous archive of the same file; (2) external/VT tray spools were never tracked by the AMS remain% fallback because it only iterated AMS unit trays — now captures and tracks VT tray remain% deltas; (3) notifications showed "Unknown" for time and filament on fallback archives — now enriches notifications with usage tracker results and captures estimated print time from MQTT at archive creation; (4) when auto-archive was disabled, archive_id was None at print completion so the entire 3MF tracking path was skipped — now searches library files and previous archives by filename to find the 3MF even without an archive, and captures the AMS slot-to-tray mapping at print start so it's available at completion regardless of archive state; (5) when auto-archive was disabled but the print was dispatched by BamBuddy (queue/reprint), the on_print_start callback discarded the expected print entry and returned early — the archive was never promoted to _active_prints, so at completion archive_id and ams_mapping were both None, making all tracking paths fail. Now detects expected prints before the auto-archive early-return and falls through to the normal promotion path, also injecting the stored ams_mapping into the usage tracker session.
  • File Manager Stale UI After Deleting Folders/Files — Deleting a folder, file, or bulk-deleting items in the file manager appeared to succeed (toast shown) but the UI didn't update until a page reload. The delete endpoints (delete_folder, delete_file, bulk_delete) relied on FastAPI's dependency cleanup auto-commit which runs after the response is sent — the frontend received the success response, refetched the folder/file list, but the delete hadn't been committed yet. Added explicit db.commit() before returning in all three endpoints.
  • Spool Manager Deducts Double the Filament Used (#880) — After a print completed, the built-in spool manager subtracted twice the actual filament consumption. The printer's MQTT status message contains both updated AMS remain percentages and the FINISH state, which triggered two independent deduction paths in the same event loop cycle: the AMS weight sync (absolute SET from remain%) and the usage tracker (additive delta from 3MF data). The AMS weight sync now skips updates while a print session is active, letting the usage tracker handle deductions precisely via 3MF slicer data.
  • Thumbnails Broken After Backend Restart — Archive and library thumbnails returned 401 Unauthorized after a backend restart because stream tokens are stored in memory and lost on restart. The frontend now detects failed token-protected image loads and automatically refreshes the stream token, so thumbnails recover without a page reload.
  • SpoolBuddy Kiosk Screen Blanks on Boot — The touchscreen display would blank immediately after the RPi booted, requiring a touch to wake. Added consoleblank=0 to the kernel cmdline to disable Linux console blanking during the Plymouth-to-labwc transition, and changed the wlr-randr anti-blank loop to fire immediately instead of sleeping 60 seconds first.
  • Queue Widget Ignores Plate-Clear Setting (#752) — The "Clear Plate & Start Next" button on printer cards appeared even when "Require plate-clear confirmation" was disabled in Settings → Queue. The backend correctly auto-dispatched without waiting, but the frontend widget always showed the prompt. The widget now respects the setting and shows a passive queue link instead when plate-clear confirmation is disabled.
  • Ghost Jobs From SQLite Lock on Print Completion (#897) — When a print finished, the queue status update (printingcompleted) could fail silently if the SQLite database was locked by another writer (e.g. the runtime tracker). The failed commit left the job permanently stuck in printing status — a "ghost job" that caused the UI to show false double-assignments when the next job started. The critical queue status commit now retries up to 3 times with backoff on SQLite lock errors (PostgreSQL is unaffected — it uses row-level locking). Additionally, the runtime tracker was holding a single long transaction across all printers; it now commits per-printer to minimize lock hold time.
  • Multi-Plug Automation Only Works for First Plug (#903) — When multiple smart plugs were assigned to the same printer (e.g. a TUYA printer plug and a particle filter plug via Home Assistant), only the first plug's automation worked. The auto-on at print start, auto-off at print completion, and queue auto-off all queried for a single plug instead of iterating all plugs linked to the printer. All automation paths now control every assigned plug. Also fixed the queue auto-off path which was hardcoded to Tasmota instead of using the correct service for the plug type (HA, MQTT, REST).
  • SpoolBuddy Inventory Not Updating on Spool Changes — Adding, editing, deleting, archiving, or restoring a spool in the internal inventory did not update SpoolBuddy's frontend views until the next manual refresh or 30-second poll. The spool CRUD endpoints did not emit websocket events, and the SpoolBuddy Dashboard had no polling fallback. All inventory mutation endpoints now broadcast an inventory_changed websocket event, and the frontend invalidates the spool cache on receipt — so SpoolBuddy (and all other tabs) reflect changes instantly.
  • AMS Slot Changes Fail Until Reconnect (#887) — After a keep-alive timeout, paho-mqtt auto-reconnects but the new session can be half-broken: the printer continues sending status updates but silently ignores commands. The developer mode probe detected this (no response, leaving developer_mode as null), but had no timeout or recovery — one unanswered probe permanently blocked retries. Added a 10-second probe timeout with one retry; after two consecutive unanswered probes, Bambuddy force-closes the socket to trigger a clean reconnect with a fresh session. Additionally, the developer mode probe was firing on every auto-reconnect, which destabilized some firmware MQTT brokers (A1/P1 series) — causing a reconnect → probe → disconnect feedback loop. The probe result is now cached across reconnects and only runs once on the first connection, with a 5-second delay after connect to let the session stabilize.
  • WebSocket Crash on Printers Without fun Field (#873) — Connecting to printers that don't send the MQTT fun field (A1, P1 series, X1Plus firmware) caused a repeating 'str' object has no attribute 'get' crash in the WebSocket handler, showing the printer as offline with missing AMS and SD card info. The developer mode probe introduced in 0.2.3b1 published an MQTT message inside _update_state() between overwriting raw_data with the full MQTT dict (where vt_tray is a raw dict) and restoring the previously normalized list — the publish() call released the GIL, letting the event loop read the un-normalized dict and iterate over string keys instead of spool dicts. Fixed by normalizing vt_tray dict→list in the MQTT data before assignment, and moving preserved field restoration before the probe. Added defensive normalization in printer_state_to_dict as a belt-and-suspenders guard.

Don't miss a new bambuddy release

NewReleases is sending notifications on new releases.