github maziggy/bambuddy v0.2.3b4-daily.20260414
Daily Beta Build v0.2.3b4-daily.20260414

pre-release7 hours ago

Note

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

  • Move Build Plate from Printer Card (#791) — The printer card controls row now has a Z-jog badge between the speed control and the stop/pause buttons. Click the up/down arrows to move the build plate; click the middle label to switch the step size (1 / 10 / 50 mm). When the printer is not homed (typical right after a print finishes), the first jog opens a Bambu Studio-style warning modal with Home Z, Move anyway (bypasses soft endstops for this move), or Cancel. After the first "Move anyway" in a session, subsequent jogs skip the dialog. Disabled while a print is running. Backed by new POST /printers/{id}/bed-jog and POST /printers/{id}/home-axes endpoints, both gated behind printers:control. Thanks to cadtoolbox for the request.
  • Printer Card Status Badges & Quick Controls — The Printers page printer card now exposes new at-a-glance controls inspired by the Home Assistant Bambu Lab integration:
    • Enclosure Door badge in the top status row (DoorOpen/DoorClosed icons, green when closed, yellow when open). Detection uses the right MQTT field per printer family — home_flag bit 23 on X1/X1C/X1E and the top-level stat hex string bit 23 on P1/P2/H2 — and falls through the existing WebSocket push (status-change dedup key now includes door state, so toggling the door alone triggers a live badge update without waiting for the 30 s REST poll).
    • Airduct Mode badge beside the print speed control (Snowflake/Flame icons, sky for Cooling and orange for Heating). One-click dropdown switches the printer between cooling and heating via the existing set_airduct MQTT command. Gated to P2S/H2D/H2C/H2S.
    • Force Refresh menu entry in the printer card kebab menu (RotateCw icon) that re-requests a full pushall MQTT status report from the printer without forcing a reconnect.
  • AI Print-Failure Detection via self-hosted Obico ML API (#172) — New Settings → Failure Detection tab wires Bambuddy to a self-hosted Obico ml_api container (no Obico account, no cloud, no WebSocket). While a print is running, the detection service periodically hands the printer's camera snapshot URL to the ML API, which returns YOLO failure-detection scores. Scores are smoothed over time using Obico's own EWM + short/long rolling-mean math (30-frame warmup, alpha = 2/13, short window ≈ 5 min at 10s/frame, long window ≈ 20 h) so a single noisy frame cannot trigger an action. Sensitivity (Low / Medium / High) scales the LOW/HIGH thresholds; when the smoothed score crosses HIGH, the configured action runs exactly once per print: Notify only, Pause print (MQTT pause command), or Pause and cut power (pause + turn off any smart plug linked to that printer). A per-printer toggle lets you monitor all connected printers or just a subset. The Status card shows whether the service is running, the active thresholds, each monitored print's current verdict (safe / warning / failure), and a live rolling detection history. Requires that the External URL setting (General tab) points to a hostname/IP reachable from the ML API container, since the ML API fetches snapshots by URL.

Improved

  • Firmware Update Modal Shows All Announced Versions (#568) — The firmware update dialog now lists every version announced on Bambu Lab's wiki release history, not just the single newest one. Each row shows whether an offline firmware file is actually available for that version — rows marked Usable (green) can be installed, rows marked Unavailable (gray) are announced but have no downloadable package yet (common for hot-fix releases like 01.01.03.00 which Bambu only ships as OTA). The currently installed version is highlighted with a blue Installed badge. Selecting any usable row swaps the release-notes block at the top to that version's notes and enables the Install button for it — including older-than-current versions, so you can roll back to a previous firmware without having to hand-flash a file. The wiki scraper was tightened to only extract version numbers from heading anchors (e.g. id="h-01030000-20260303") so incidental version mentions in release-note prose — like an AMS firmware reference in an H2D changelog — no longer get mistaken for H2D firmware releases. Thanks to Cornelicorn for the request.
  • Spoolbuddy Device Controls in Settings (#962) — Each Spoolbuddy device card in Settings → Spoolbuddy now exposes five one-click actions alongside the existing Unregister button: Update (trigger daemon software update), Restart Browser (kiosk UI), Restart Daemon, Reboot (device), and Shutdown. Each action shows a confirmation dialog before queueing the command; buttons are disabled when the device is offline. Uses the existing /spoolbuddy/devices/{id}/update and /spoolbuddy/devices/{id}/system/command endpoints — no new backend work needed. Thanks to TravisWilder for the request.
  • Support Bundle Covers All Settings & SpoolBuddy — The support bundle / bug-report payload now dumps every row in the Settings table instead of filtering by a hard-coded allowlist: sensitive keys (tokens, passwords, URLs, paths, emails, etc.) have their values replaced with [REDACTED] but the key itself is kept, so new config flags automatically show up in future bundles without a code change. Also adds an integrations.spoolbuddy section listing registered SpoolBuddy devices (firmware version, NFC/scale hardware, calibration, online state, uptime) — anonymized, no hostnames/IPs/device IDs.
  • Settings Search Finds More Cards — The cross-tab search field at the top of Settings now finds Sidebar Links, Spoolman, Spool Catalog, Color Catalog, all four Failure Detection sections, Advanced Email Authentication, SMTP Test, Authenticator App (TOTP), Email OTP, 2FA Linked Accounts, Single Sign-On (OIDC), LDAP Server Configuration, and the four Backup sub-cards (GitHub, History, Local, Scheduled). Powered by a new module-level registry (frontend/src/lib/settingsSearch.ts) so future settings register themselves next to their component instead of being forgotten in a central array.

Changed

  • Plate-Clear Confirmation Disabled by Default — New installs ship with Settings → Workflow → "Require Plate-Clear Confirmation" off. Multiple new users reported queued prints appearing to not start because the prompt was waiting for acknowledgement; opt in from Workflow if you want the confirmation gate.

Fixed

  • Obico ML API Got 401 When Fetching Snapshot with Auth Enabled (#172) — The Obico failure-detection service handed the ML API container a snapshot URL (/api/v1/printers/{id}/camera/snapshot) for it to GET directly, but when Bambuddy authentication was enabled the endpoint returned 401 and the ML API surfaced "Failed to get image" (visible as a 400 from the ML API back to Bambuddy). The detection service now appends a short-lived camera-stream token to the snapshot URL — the same token scheme already used by <img>-based camera consumers, which the snapshot endpoint already accepts. The token is cached on the service and refreshed before its 60-minute expiry, so no extra per-call DB churn. When auth is disabled the token is simply ignored. Thanks to fblix for reporting.
  • Direct Print from Library Not Attributed to User — Clicking the Print button on a library file dispatched the job with no created_by_id, so the resulting archive had no owner and the print didn't show up in per-user statistics. The Queue and Reprint paths already forwarded the authenticated user; the library POST /files/{file_id}/print endpoint now does the same, reading the user from the JWT and passing it through to the dispatcher so direct prints are attributed like queued and reprinted ones.
  • Add/Edit Printer Modal Clipped on Short Viewports (#964) — On short or zoomed-in browser windows, the Add Printer and Edit Printer dialogs exceeded the viewport height with no scroll, hiding the lower fields (Access Code, Model, Location) and the Save button. Users had to zoom the browser out to complete the form. The modal overlay now scrolls and the card caps at calc(100vh - 2rem) with internal overflow so every field stays reachable regardless of viewport height. Thanks to MartinNYHC for reporting.
  • AMS Drying Silently Does Nothing (#971) — Clicking Start Drying on a supported printer (e.g. P1S with AMS 2 Pro) could publish the MQTT command successfully but leave the AMS idle with no UI feedback. Two issues: (1) the firmware rejects the command when dry_sf_reason reports a blocking state (most commonly code 8 — AMS 2 Pro external power adapter not plugged in — but also "AMS busy", "already drying", etc.), and Bambuddy parsed that array but never surfaced it to the user; (2) the payload sent filament: "", which some firmwares treat as an invalid-field refusal. The /drying/start endpoint now inspects the live dry_sf_reason for the target AMS unit and returns a descriptive 409 (e.g. "Plug in the external AMS power adapter to start drying") instead of silently publishing, and backfills an empty filament from the first loaded tray's type (defaulting to PLA) so the printer never rejects the command for a missing field. Thanks to MartinNYHC for reporting.
  • Webhook Tokens Leaked into Logs When Debug Logging Enabled (Security) — Turning on Settings → Support → Debug Logging elevated the httpx and httpcore loggers to DEBUG, which caused httpx to log the full URL of every outbound HTTP request. For Discord notifications and generic webhook notifications, the URL is the secret — the bearer token is embedded in the path — so any user who enabled debug logging (typically to capture logs for a bug report) was writing their Discord webhook token to bambuddy.log and then pasting it into GitHub issues or support bundles. httpx/httpcore are now pinned to WARNING regardless of the debug toggle; paho.mqtt still honours debug. If you enabled debug logging while notifications were sending, rotate any exposed Discord/webhook URLs — the token is in the path, so the whole URL must be regenerated in the provider's UI.
  • Queue Item Stuck in "Printing" When Start Command is Dropped (#967) — If the physical printer dropped or ignored the MQTT project_file start command (same half-broken-session shape as #887/#936), the queue item was permanently orphaned in the printing status at 100% because the scheduler optimistically flipped the DB row to printing right after the publish succeeded locally and had no watchdog to revert it. Recovery required manually editing the SQLite print_queue table. A new watchdog now captures the printer's pre-dispatch state and polls for up to 45 s after start_print() returns; if the printer never transitions, the item is reverted to pending so the scheduler picks it up again, and the MQTT session is force-reconnected so the retry lands without a printer reboot. Thanks to stringham for reporting.
  • Queued Prints Require Printer Reboot to Start (#936) — On some printers, a queued print would be uploaded via FTP and the project_file MQTT command would be sent, but the printer never transitioned out of FINISH/IDLE and required a power cycle to unstick — after which it often started a previously cancelled print rather than the intended one. Root cause is a half-broken MQTT session (same shape as #887): the printer keeps publishing telemetry so Bambuddy reports it as connected, but our publishes on the command topic never reach the firmware. Existing recovery only triggered via the developer-mode probe path, which skips printers that already have a known developer_mode value. The print-dispatch verifier now treats an unacknowledged project_file (state unchanged after 15 s) as the same "commands not reaching printer" signal and forces a fresh MQTT session so the next dispatch can land without a printer reboot. The existing dev-mode probe path is refactored to share the same helper.
  • Clear Plate Confirmation Bypassed on Power Cycle (#961) — With Auto Off enabled and another job queued, the smart plug would cut power when a print finished and immediately re-power when the scheduler saw the queue, at which point the printer booted fresh into IDLE and the next job auto-dispatched without the "Clear Plate & Start Next" confirmation. Root cause: the plate-cleared gate lived only in the in-memory PrinterManager._plate_cleared set, and the scheduler's idle check treated IDLE as always-idle regardless of whether a previous finish had been acknowledged — so the gate was lost across both Bambuddy restarts and the IDLE-on-boot state transition. The gate is now an awaiting_plate_clear column on the printers table, set by on_print_complete when a print finishes or fails, cleared by the /printers/{id}/clear-plate endpoint and by the scheduler when it dispatches the next job, and rehydrated from the DB into PrinterManager on startup. _is_printer_idle now short-circuits to not-idle whenever require_plate_clear is on and the printer is awaiting ack, regardless of the currently reported state — so the prompt survives Auto Off cycles, Bambuddy restarts, and the printer booting back into IDLE. The clear-plate endpoint no longer requires the printer to currently report FINISH/FAILED (it accepts the ack whenever the awaiting flag is set), and the Printers page widget prompts based on the flag rather than the reported state. Thanks to miaopas for reporting.
  • Insecure Temp File Creation in Backup Export — The manual backup download endpoint used tempfile.mktemp(), which is vulnerable to a symlink race condition (CWE-377). Replaced with tempfile.mkstemp() which atomically creates the file, eliminating the TOCTOU window.
  • Spoolman Iframe Blocked After 0.2.3b4 Security Headers — The Spoolman page (Inventory → Spoolman iframe) failed to load when Spoolman was served from the same host as Bambuddy via a reverse proxy. The security-headers middleware added in 0.2.3b4 set X-Frame-Options: DENY on every response, which blocked even same-origin iframing. Relaxed to SAMEORIGIN so Spoolman (and any other same-origin tool behind the same reverse proxy) can be embedded again, while still preventing cross-origin clickjacking.
  • SD Card Badge Removed — After four rounds of fixes the printer-card SD status badge still flipped red on H2D when unrelated activity happened on the network (e.g. powering on an A1 caused every H2D to go red simultaneously). The underlying problem is that Bambu firmware SD-state signaling is not reliably derivable from MQTT: the legacy top-level sdcard field is only sent on some pushes with inconsistent typing, and home_flag bits 8-9 are cleared on heartbeat pushes even when a card is inserted, with no reliable way to distinguish heartbeats from full status reports. The badge has been removed entirely from the Printers page card and the Printer Info modal. Underlying state.sdcard parsing is retained (simplified to a plain truthy read of the sdcard field only, no more home_flag derivation, no heartbeat latches) because the firmware-update precondition check still needs to know whether a card is inserted before starting an update. Thanks to MartinNYHC for the extensive reporting across all four rounds. Previously, this entry described the H2D badge flap and its three attempted fixes — kept here for history: The original bug toggled between "inserted" (green) and "not inserted" (red) every few seconds on H2D. Root cause: the MQTT parser used a strict identity check (data["sdcard"] is True) on the top-level sdcard field, but real firmware ships that field inconsistently — bool on some models, int 1, or a string enum like "HAS_SDCARD_NORMAL" on others — so any message carrying a non-bool value flipped the state to False. Fixed by deriving the badge from home_flag bits 8–9 (HAS_SDCARD_NORMAL / HAS_SDCARD_ABNORMAL) when present — the canonical firmware source, same as door and store-to-SD parsing — and falling back to a truthy check on the top-level field for firmwares that only send that. Follow-up: the badge was still flapping because Bambu firmwares send partial MQTT pushes that carry the legacy sdcard field alone (without home_flag), and the fallback was re-engaging on every such push. The parser now latches home_flag as the canonical source for the session once seen, so partial pushes carrying only sdcard can no longer flip the badge; the latch resets on reconnect so a firmware change still re-learns. Second follow-up: on H2D the badge still showed red on initial Printers-page navigation and flipped to green on reload, because H2D also sends heartbeat-style home_flag pushes where bits 8–9 are clear even when a card is inserted. Downgrades from true→false now require three consecutive clear reads (upgrades false→true still apply immediately), so a single heartbeat no longer turns the badge red. Third follow-up: the three-strike counter still lost the race on idle printers — once an A1 or other printer connecting nearby triggered a burst of MQTT activity, idle H2Ds could accumulate ≥3 heartbeat pushes before the next full status report and all flip to red simultaneously. Reworked the derivation: the legacy top-level sdcard field is now authoritative when present (truthy check covers bool/int/string firmware variants), home_flag bits 8–9 are only consulted on full push_status reports (identified by the presence of multiple state markers like gcode_state, mc_percent, nozzle_temper, print_type, stg_cur, or ams), and bare heartbeat pushes carrying home_flag alone no longer affect SD state at all. Thanks to MartinNYHC for reporting.
  • CSP Blocked Sidebar Iframes, Service-Worker Registration, and Google Fonts — The strict Content-Security-Policy header added in 0.2.3b4 broke three things at once: (1) custom sidebar links pointing at external HTTPS URLs (e.g. a Grafana/telemetry dashboard) rendered in ExternalLinkPage were blocked because no frame-src was declared and iframes fell back to default-src 'self'; (2) the inline service-worker registration <script> at the bottom of index.html was blocked by script-src 'self', silently preventing the PWA service worker from installing; (3) the import of Google Fonts' Inter from index.css was blocked by style-src and font-src. Fixed by adding frame-src 'self' https: for user-configured HTTPS iframe targets, moving the inline SW-registration script into /sw-register.js so script-src 'self' covers it without needing 'unsafe-inline' or per-build hashes, and allowing https://fonts.googleapis.com in style-src and https://fonts.gstatic.com in font-src. frame-ancestors 'none' is preserved so Bambuddy itself still cannot be framed cross-origin.

Don't miss a new bambuddy release

NewReleases is sending notifications on new releases.