github maziggy/bambuddy v0.2.4b1-daily.20260419
Daily Beta Build v0.2.4b1-daily.20260419

pre-release5 hours ago

Note

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

Fixed

  • Printer Card Controls Row Overflows in Chrome — At Medium card size on a wide viewport, the printer-card controls row (fan badges, airduct mode, print speed, bed jog, then Stop / Pause on the right) visibly overlapped in Chrome while rendering fine in Firefox and Safari. The controls-row layout had a max-[550px]:flex-wrap rule on the left badge group that only fires below 550 viewport pixels, so on a wide viewport with a narrow card the left group never wrapped — and since its badges don't truncate, Chrome painted the overflowing speed/bed-jog badges on top of the right-pinned Stop/Pause buttons. German locales made it obvious ("Pausieren" is 9 characters). The left group now uses unconditional flex-wrap, so when badges don't all fit on one line they wrap inside the left cell instead of colliding with the right cell; the parent row also wraps gap-y so Stop/Pause drops to a new line in the worst case. Pre-existing (commit 4ff3e2a6, Feb 2026), surfaced while testing #939.
  • MQTT Smart Plug Subscription Lost After Every Restart (#1010) — Users integrating a Shelly (or any other) plug through an external MQTT broker (e.g. ioBroker, Zigbee2MQTT, Home Assistant's MQTT broker) saw the plug's power / state / energy readings go dark after every Bambuddy restart, and the only fix was to open Settings → Smart Plugs, rename the topic to a dummy value, save, rename it back and save again. Root cause: the startup restore path in main.py (~line 4120) still used the legacy single-topic model (mqtt_topic plus *_path kwargs), while the Settings UI save path had been upgraded to the newer per-type model (mqtt_power_topic / mqtt_energy_topic / mqtt_state_topic each with their own paths, multipliers and mqtt_state_on_value). Plugs configured entirely with the new per-type fields got skipped at startup because the if plug.mqtt_topic: guard short-circuited — which is exactly what a Shelly-via-ioBroker setup looks like, since those publish power and state on separate topics. The "rename, save, rename back" workaround triggered the update endpoint, which was using the correct per-type code and re-established the subscription. Fix: extracted the topic-resolution + service.subscribe() call into a single subscribe_plug_to_mqtt(service, plug) helper in backend/app/services/mqtt_smart_plug.py that preserves legacy fallback, and routed the startup restore, create, and update routes all through it so future schema changes can't cause the three paths to drift again. Regression tests cover: per-type topics restored without a legacy topic set, legacy single-topic backward compat, per-type multipliers overriding legacy, per-type winning when both are set, the empty-config skip case, and topic-list de-duplication. Thanks to saint-hh for the clear repro steps.
  • Large 3MF Uploads Archived as Corrupted ZIPs (#1032) — On bare-metal Raspberry Pi installs (armv7l / Python 3.11 / Bookworm), 3MF files larger than a few MB arrived complete via the virtual-printer FTP server but the copy into data/archives/ ended up not being a valid ZIP. The archive row was still written, the printer card looked fine, and the problem only surfaced later when opening the archive in the UI, where GET /archives/{id}/plates logged Failed to parse plates from archive N: File is not a zip file and the thumbnail / plate / filament panels came up blank. Two things conspired: shutil.copy2 takes the Linux sendfile() fast path on Python ≥ 3.8, and a partial-return from that syscall silently truncated the destination for the upload sizes users hit; and ThreeMFParser.parse() had a bare except: pass around its zipfile.ZipFile open, so the archive pipeline kept going with empty metadata and left the bad file on disk. The copy is now an explicit chunked read/write with fsync() — no sendfile involved — with a post-condition zipfile.is_zipfile() check that refuses to create the archive row (and cleans up the archive directory) when the source was a valid ZIP and the destination isn't, logging both sizes at ERROR. The parser's silent catch now logs at WARNING so corrupted 3MFs are visible in support bundles instead of disappearing into empty metadata. Regression tests cover small / multi-chunk copies, ZIP roundtrips, the post-copy is_zipfile sentinel on a truncated file, and the new parser WARNING. Thanks to saint-hh for the detailed diagnosis.
  • Thumbnails Blank Until Reload After Sign-In — On auth-enabled instances, signing out and back in left the File Manager (and occasionally the Archives page) full of broken thumbnails until the page was manually reloaded. Thumbnail URLs are gated by a short-lived camera-stream token that <img> tags can't send via Authorization headers, so the token is appended as ?token=… at render time. Two race conditions conspired to break this: (1) the token query was keyed only on ['camera-stream-token'] and fired while the user was still on the login page, 401'd, and stayed cached — after sign-in nothing invalidated it; (2) when the token did eventually arrive, the global variable holding it was not reactive, so any File Manager / Archives page that had already rendered kept serving image URLs with no token. The token query now includes the user id in its key and is gated on !!user, so a new login always triggers a fresh fetch; and when the token transitions from null to a value, useStreamTokenSync walks the DOM once and updates src on every already-rendered <img>/<video> pointing at /api/v1/ without the current token, reloading them in place.
  • P2S Firmware Check Shows Stale "Latest" Version (#1030) — On P2S (and X2D) the Firmware Info modal reported 01.01.01.00 as the newest available release even though 01.02.00.00 had shipped on the Bambu Lab wiki weeks earlier, so the "update available" badge never appeared. Two silent regex mismatches in the wiki scraper caused _fetch_all_versions_from_wiki() to return an empty list: (1) the section-heading anchor parser required a dash between the version bytes and the release date (id="h-01020000-20260409"), but P2S and X2D publish anchors without the dash (id="h-0102000020260409"); (2) the text-based fallback only accepted ASCII parens around the date, while P2S, X2D, A1 and A1-mini headings render dates in full-width (YYYYMMDD) (U+FF08/U+FF09). When both paths failed, the code silently fell back to the Bambu Lab download page, which still lagged at 01.01.01.00. The anchor regex now accepts an optional dash and the fallback accepts both paren styles; added regression tests for the no-dash anchor and full-width paren shapes. Thanks to Minebuddy for reporting.
  • Library File Print-Usage Tracking (#1008) — LibraryFile.print_count and last_printed_at are now updated on every successful queued print completion. Previously both fields were defined on the model and displayed in the File Manager, but nothing ever wrote to them — every file in every library showed as never printed. Now counts increment cumulatively and last_printed_at stamps the completion timestamp (UTC). Failed, cancelled and user-aborted prints are intentionally excluded, so the fields represent "successful usage" rather than "attempted usage." This unblocks sorting the File Manager by last-printed date and is a prerequisite for the scheduled-purge feature requested in #1008. Thanks to cadtoolbox for the report.

Improved

  • File Manager: Collapse Folders by Default (#996) — Added a Collapse toggle next to Wrap in the File Manager sidebar header. When enabled, the folder tree opens with only top-level folders visible on every page load; disabling it restores the previous fully-expanded default. Toggling the preference also immediately re-collapses/re-expands the current tree — no reload required. Persisted to localStorage under library-collapse-folders, matching the existing library-* preference pattern. Thanks to AshieTashi for the request.

Changed

  • Docker runtime image on Debian Trixie — The production Docker image now builds on python:3.13-slim-trixie instead of the Bookworm-based python:3.13-slim. Picks up ffmpeg 5 → 7 (HEVC/AV1 improvements for camera capture), OpenSSL 3.0 → 3.3, and two more years of APT package freshness. Frontend-builder stays on Bookworm until the Node.js image team publishes Trixie variants — users never see that stage.

Don't miss a new bambuddy release

NewReleases is sending notifications on new releases.