- Sanitize project notes with DOMPurify before rendering via
dangerouslySetInnerHTML (ProjectDetailPage.tsx)
- Replace hand-rolled HTML sanitizer with DOMPurify in ProjectPageModal
to prevent attribute injection via crafted 3MF href values
- Block /api/v1/auth/setup when auth is already enabled to prevent
unauthenticated clients from disabling authentication remotely
The Debian ffmpeg package uses GnuTLS, whose hardened defaults reject
TLS renegotiation and legacy ciphers that some Bambu printer firmwares
(notably P2S) rely on — causing RTSP sessions to drop after a few
seconds.
Add a local TLS termination proxy (Python ssl/OpenSSL) that handles
the TLS connection to the printer and exposes a plain RTSP port to
ffmpeg. The proxy rewrites RTSP request-line URLs (rtsp://proxy →
rtsps://printer) while preserving Authorization headers so Digest
auth hashes remain valid.
Also:
- Reduce RTSP reconnect delay from 1.0s to 0.2s
- Add ffmpeg fast-start flags (-probesize 32, -analyzeduration 0,
-fflags nobuffer, -flags low_delay)
- Fix external camera double rate-limiting causing choppy streams
- Apply TLS proxy to external camera rtsps:// URLs and snapshot capture
- Update orphan ffmpeg cleanup to match rtsp:// (proxied) URLs
- Add unit tests for RTSP URL rewriting and proxy lifecycle
Printer File Manager Doesn't Auto-Refresh ([#704](https://github.com/maziggy/bambuddy/issues/704)) — The printer file manager (SD card browser) only fetched the file list once when opened. Files uploaded from BambuStudio/OrcaSlicer while the modal was open wouldn't appear until the user clicked the refresh button or reopened the modal. Now auto-refreshes every 30 seconds while open. Reported by @shadowjig.
Database Connection Pool Exhaustion Under Load ([#704](https://github.com/maziggy/bambuddy/issues/704)) — Background tasks (print scheduler FTP uploads, camera captures, notification sends, timelapse stitching) held database sessions open during slow network I/O, consuming connection pool slots for seconds at a time. With the default pool of 15 connections (size 5 + overflow 10), concurrent operations during print start/complete events could exhaust the pool, causing `QueuePool limit reached` errors and `greenlet_spawn` failures in RFID spool auto-assignment. Doubled the pool to 30 connections (size 10 + overflow 20). Reported by @shadowjig.
Ambient drying: automatically dry filament on idle printers when
humidity exceeds threshold, regardless of queue state. Separate toggle
from queue auto-drying — both can run simultaneously. Uses the same
presets, humidity threshold, and power constraint detection.
Fix: block mode (wait for drying) previously skipped the humidity
auto-stop check for already-drying printers, causing drying to
continue indefinitely. Now only prevents starting new drying.
Queue auto-drying: scheduler automatically starts drying on idle printers
with scheduled queue prints when AMS humidity exceeds the configured
threshold. Uses conservative parameters (lowest temp, longest duration)
for mixed filaments. Drying stops when humidity drops below threshold
(30-minute minimum prevents oscillation), when scheduled items are
removed, or when the feature is disabled. Optional "block queue" mode
delays the next print until drying completes.
Configurable presets: temperature and duration per filament type,
editable in Settings → Print Queue, used by both manual drying popover
and queue auto-drying. Separate presets for AMS 2 Pro (n3f) and AMS-HT
(n3s) reflecting different heating capabilities.
PSU detection: drying button disabled with tooltip when dry_sf_reason
indicates insufficient power. Parses drying status bits and dry_sf_reason
from AMS info hex string via MQTT.
Backend: print_scheduler.py (+316 lines), bambu_mqtt.py, printer_manager,
schemas, settings route. Frontend: PrintersPage drying presets prop,
SettingsPage drying config UI, i18n (7 locales). Tests: 27 new tests in
test_scheduler_auto_drying.py covering conservative params, presets,
state sync, stop logic, minimum drying time, and auto-stop regressions.
Non-script HA entities (switch/light/input_boolean) on the printer card
always sent turn_on when clicked, which is a no-op when the switch is
already on. Now sends toggle for non-script entities so the badge click
actually changes the switch state. Script entities still use turn_on.
Also fix SmartPlugManager._get_plug_for_printer() using
scalar_one_or_none() which crashes with MultipleResultsFound when
multiple plugs are assigned to the same printer (e.g., Tasmota + HA
switch). Now fetches all plugs and returns the main non-script plug.
Add tests for both fixes: _get_plug_for_printer multi-plug handling
(5 tests) and canonicalFilamentType/filamentTypesCompatible/autoMatch
PA-CF equivalence (8 tests).
Bambu Lab firmware treats PA-CF, PA12-CF, and PAHT-CF as interchangeable,
but the print scheduler and filament override UI used exact string matching.
A 3MF requiring PA-CF wouldn't match PA12-CF in the AMS, leaving the
override dropdown disabled and preventing scheduler assignment.
Add a filament type equivalence system (both backend and frontend) so
these PA variants are treated as compatible in scheduler assignment,
AMS slot matching, force color match validation, and the override dropdown.
Also fix the "Force color match" checkbox click target being too wide
(entire row instead of just the checkbox/label) by changing flex to
inline-flex on the label element.
The embedded camera viewer only handled mouse events (mousedown,
mousemove, mouseup) for window dragging and resizing. On iOS/iPadOS,
touch input doesn't trigger mouse events, so the camera window
couldn't be repositioned — touch just scrolled the page underneath.
Add touch event handlers (touchstart, touchmove, touchend, touchcancel)
alongside mouse handlers for both the header drag handle and the
bottom-right resize handle. Uses preventDefault on touchmove to
prevent page scrolling during drag.
When inventory spool assignments had stale weight_used values, the fill
level fallback chain (Spoolman → Inventory → AMS remain) used nullish
coalescing (??), which doesn't fall through on 0. A stale inventory
fill of 0% permanently shadowed the correct real-time AMS remain value.
Viewer users were unaffected because their group lacked the
inventory:view_assignments permission, so the query never fired.
Now when inventory says 0% but AMS hardware reports positive remain,
the inventory value is bypassed in favor of the live AMS data.
Notify users when the first layer finishes printing so they can check
adhesion remotely. Triggers once per print when layer 2 begins
(layer_num >= 2, capped at <= 5 to handle reconnects). Includes a
camera snapshot attachment. Adds the on_first_layer_complete toggle
to all notification providers, with backend/frontend/i18n support
across all 7 locales.
Start, monitor, and stop drying sessions for AMS 2 Pro (n3f) and
AMS-HT (n3s) directly from the Printers page. Flame icon in AMS card
header opens a popover with filament-based temperature/duration presets
from BambuStudio. Live countdown status bar shows time remaining.
Backend: cache module_type from MQTT get_version, expose dry_time and
module_type in both WebSocket and REST paths, add supports_drying()
with firmware gating, add server-side guard on start_drying endpoint.
Frontend: drying button, popover with filament select + temp/duration
sliders, status bar, start/stop mutations. i18n for all 7 locales.
Supported: X1/X1C (fw 01.09+), P1P/P1S (fw 01.08+), H2D (fw 01.02.30+),
H2D Pro, X1E. Not supported: P2S, A1, A1 Mini, H2S, H2C.
The compatible_printers filter on local presets parsed the stored JSON
array (e.g. '["BBL X1C 0.4 nozzle"]') as a semicolon-delimited string,
so matching always failed and every local preset was silently skipped.
Removed the filter entirely — user-imported profiles should be usable
on any printer.
home_flag bit 18 is set on all printers regardless of hardware,
causing the ethernet badge to appear on WiFi-only models (A1, P1P,
etc.). The previous fix removed the feature entirely, so ethernet
printers lost their badge too.
Now only trusts bit 18 on models with an ethernet port (X1C, X1E,
P1S, P2S, H2D, H2D Pro, H2C, H2S). WiFi-only models always show
the WiFi signal badge.
AMS slots now show "B3" instead of "AMS-B Slot 3" and external spool
holders show "Ext" instead of "External", keeping the table readable
at narrow widths.
* Enhance link spool functionality with additional printer and AMS details
* Refactor linkSpool function to accept detailed context object for improved spooling integration
* Enhance LinkSpoolModal to include amsName in props and linkSpool mutation for improved functionality
* Add amsName prop to PrinterCard for enhanced spool linking functionality
* Updates LinkSpoolModal test to work with recent spool location update changes
* Adds clear_location to unlink testing
* Refactor LinkSpoolRequest to remove ams_name and update location generation logic for improved clarity
* Remove amsName from LinkSpoolModal and PrinterCard for cleaner API integration
* Remove amsName from LinkSpoolModal test props and update linkSpool mock response for improved clarity
* Expanded link logic to accept a generic spool tag (spool_tag, tray_uuid, or tag_uid) and validate 16/32-char hex values, including rejection of all-zero tags. Added a new unlink endpoint that clears Spoolman extra.tag for a given spool ID.
* Updated the link validation expectation to match the new 16-or-32-hex rule. Added an integration test for the new unlink endpoint to verify extra.tag is cleared and success is returned.
* Updated the link API call to send spool_tag instead of tray_uuid. Added a new unlinkSpool API helper that calls the new backend unlink route.
* Switched modal data source from inventory spools to Spoolman unlinked spools so the list matches the backend response you shared. Updated the link action to call Spoolman link directly and use trayUuid or tagUid as the slot tag.
* Refactored Spoolman card behavior so actions render correctly across linked/unlinked cases, and added support for an Unlink from Spoolman button under Open in Spoolman. Final UI rule now hides Unlink for Bambu Lab filament and shows it only for non-Bambu linked spools.
* Added fallback slot-tag generation so untagged slots can still be linked/unlinked reliably and linked spool lookups work consistently across AMS, AMS-HT, and external trays. Wired a new unlink mutation and passed per-slot unlink callbacks into the hover card, with query invalidation for linked/unlinked spool caches after unlink.
* Added/updated the noTrayUuid message to reflect that either tray UUID or tag UID is required when no slot tag is available. This keeps error text aligned with the new tag fallback and modal behavior.
* Added noTrayUuid message in the other languages. The translation was done using Google Translate.
* Updated LinkSpoolModal tests to use Spoolman API instead of inventory API, with new UnlinkedSpool data structure and Select Spool UI text.
* Adds hashSerialToHex32, uses new function in getFallbackSpoolTag and updates all uses. This ensures we're generating a fallback spool tag using the printers serial number rather than the database ID for consistency.
* Removes 'import json' from unlink_spool and moves to the top of the file.
* Removes hasUnlinkedSpools and related references since it's no longer used
* Removes noTrayUuid from translations and references in components.
* Adds confirmation dialog before fully unlinking spool from Spoolman
* Adds unlinkConfrimTitle and unlinkConfirmMessage. All languages other than English were done using Google Translate
* Fixes unlink toast to use dedicated unlinkSuccess and unlinkFailed keys.
* Changes tag priority on spoolTag, fixes type error by adding non-null assertion to spoolTag
* Switches around tag_uid and tray_uuid on const trayTag
---------
Co-authored-by: MartinNYHC <mz@v8w.de>
Sends persistent notifications to the HA dashboard using the existing
HA connection from Settings. Zero config — just select "Home Assistant"
as provider type. Users can forward notifications to mobile via HA
automations.
The "Reprint" and "Schedule" buttons at the bottom of archive cards
overlapped when the browser was narrower than the card grid expected
(e.g. half-screen on a 2K monitor). The text labels used a viewport-
based sm: breakpoint that didn't account for actual card width.
Added overflow-hidden to the flex buttons and truncate to the text
spans so labels clip with ellipsis instead of bleeding into neighbors.
Large Hueforge 3MF files (~28 MB) can't be downloaded from the
printer's FTP server within the previous 120s max timeout, especially
during active printing. Added 180s and 300s timeout options to the
FTP settings dropdown.
- Remove Bambu Cloud authentication gate from GitHub backup settings card.
K-profiles and app settings backup work without cloud login; the Cloud
Profiles checkbox is disabled with a hint when not authenticated.
- Fix backup log timestamps showing UTC instead of local time by using
the shared parseUTCDate utility for correct timezone conversion.
home_flag bit 18 was incorrectly interpreted as "wired/ethernet
connection", causing the ethernet badge to always show — even on
printers without an ethernet port (e.g. A1, P1S). This hid the
WiFi signal indicator entirely.
Removed the wired_network field and ethernet badge UI. The WiFi
signal badge now shows correctly whenever the printer reports
signal strength.
* Added "Force Color Match" feature to filament override
* Update settings.py
* Update settings.py
* Label updates for warnings and checkbox case
* Initial plan
* Add noMatchingMaterial i18n translations to all 7 locale files
Co-authored-by: cadtoolbox <12723486+cadtoolbox@users.noreply.github.com>
* Use {{material}} interpolation in noMatchingMaterial; populate from filament_overrides with getColorName
Co-authored-by: cadtoolbox <12723486+cadtoolbox@users.noreply.github.com>
* Updates for PR#625 comments
* Added "Force Color Match" feature to filament override
* Update settings.py
* Update settings.py
* Label updates for warnings and checkbox case
* Initial plan
* Add noMatchingMaterial i18n translations to all 7 locale files
Co-authored-by: cadtoolbox <12723486+cadtoolbox@users.noreply.github.com>
* Use {{material}} interpolation in noMatchingMaterial; populate from filament_overrides with getColorName
Co-authored-by: cadtoolbox <12723486+cadtoolbox@users.noreply.github.com>
* Updates to PrintersPage and QueuePage
* Update QueuePage.tsx
* Rebase to 0.2.2b3
* Fix compile errors with FilamentOverride
* Updates for PR#625 comments
https://github.com/maziggy/bambuddy/pull/625#pullrequestreview-3908738261
* Fix force color match default, loadedFilamentTypes bug, remove dead translations
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: cadtoolbox <12723486+cadtoolbox@users.noreply.github.com>
Co-authored-by: MartinNYHC <mz@v8w.de>
Multi-plate 3MF files can now be queued in one action via a "Queue All
Plates" toggle in the plate selector (add-to-queue mode only). Each
plate becomes a separate queue entry, individually editable.
Fix: "Clear Plate & Start Next" no longer appears when all pending
queue items are staged (manual_start). The prompt only shows when
there are auto-dispatchable items the scheduler will actually start.
Virtual printers in Queue mode now have an "Auto-dispatch" setting.
When enabled (default), prints start automatically — preserving current
behavior. When disabled, prints are added with manual_start so they
wait for manual dispatch from the queue UI.
Checkbox selection + "Delete Selected" button in Settings > Filament
for both Spool Catalog and Color Catalog. Adds POST bulk-delete
endpoints and translations for all 7 locales.
P2S uses hardened steel rods, not carbon fiber. Move P2S from
carbon rod classification to new steel_rod category with its own
"Lubricate Steel Rods" / "Clean Steel Rods" maintenance tasks.
visibility into AMS spool assignments on printer cards without exposing
the full Inventory page (#635). The list_assignments endpoint now
requires this new permission instead of inventory:read. All default
groups (Administrators, Operators, Viewers) include it for backward
compatibility.
Closes#634
The print dispatch progress toast stayed visible forever after the
second print in a session. lastDispatchSummaryRef was never reset
between batches — every single-printer dispatch produced the same
summary key ("first-complete:1:0"), so subsequent completions matched
the stale ref and skipped creating the done toast.
Reset the dedup guard when the dispatch toast is dismissed and when
a new batch starts.
The print dispatch notification disappeared instantly for small files or
closed immediately when the progress bar reached 100%, giving no
confirmation that the job was submitted. The dispatch toast now stays
visible for 3 seconds showing the completion message before auto-
dismissing. For very fast uploads where no progress toast was shown,
a fresh confirmation toast is created instead.
When printing from the file manager, the print modal showed all printers
including busy ones. Selecting a busy printer resulted in a failed send.
The printer selector now fetches live status for each printer and shows
state badges (Idle, Printing, Paused, etc.). In reprint mode, non-available
printers (anything other than IDLE, FINISH, FAILED) are grayed out and
not selectable. "Select all" skips them. Queue/edit modes still allow
selecting busy printers since the job will wait.
Resize PWA icons to match their declared dimensions (192x192, 512x512,
180x180), split discouraged "any maskable" icon purpose, and add mobile
and desktop screenshots to manifest.json for Chrome's richer install UI.
Replace all hardcoded English strings with t() translation calls across
9 components: SettingsPage, SmartPlugCard, AddSmartPlugModal,
SwitchbarPopover, NotificationProviderCard, AddNotificationModal,
NotificationTemplateEditor, NotificationLogViewer, GitHubBackupSettings,
and RestoreModal. Add ~600 new translation keys to all 7 locales
(en, de, ja, fr, it, pt-BR, zh-CN).
All filament mapping dropdowns (single-printer, multi-printer, and
"Print to Any" model-based) showed only the base material type (e.g.
"PLA") without distinguishing subtypes like "PLA Basic" vs "PLA Matte",
making entries with different subtypes but same color look identical.
Backend: Add tray_sub_brands to available-filaments response and include
it in the dedup key so different subtypes of the same color appear as
separate entries.
Frontend: Show tray_sub_brands in FilamentMapping, FilamentOverride, and
PrinterSelector dropdowns, falling back to base type when unset. Add
traySubBrands field to LoadedFilament interface.
Sync all locale files to match EN's 3,054-key structure:
- it: add 485 missing keys, remove 1 stale key
- pt-BR: add 51 missing keys, remove 10 stale keys
- fr: add 47 missing keys
- ja: add 47 missing keys, remove 116 stale keys
- zh-CN: add 25 missing keys, remove 1 stale key
All 655 new keys are properly translated.
Stale keys from past refactors are cleaned up (127 total removed).
The per-printer InlineMappingEditor showed filaments from both nozzles
on H2D printers. The single-printer FilamentMapping dropdown was fixed
in 29e9593 but the multi-printer code path was missed. Added nozzle_id
filtering to both auto-match logic and dropdown options via shared
autoMatchFilament() and filterFilamentsByNozzle() functions in
amsHelpers.ts, with 10 regression tests.
Move the toast container from bottom-4 to bottom-20 so toast
notifications and upload progress stack above the bug report bubble
instead of rendering on top of each other.
- Add 12 backend integration tests for AMS labels API (GET/PUT/DELETE,
serial resolution, synthetic key fallback, whitespace handling, validation)
- Add 10 frontend tests for FilamentSlotCircle component (rendering,
border styles, background colors, text contrast inversion)
- Fix ruff W293 trailing whitespace in inventory.py from contributor fix
- Add ams_label model import to test conftest.py
- Update CHANGELOG, README, website features page, and wiki AMS docs
* AMS Labels addition to PrintersPage
* Added database reinitialization for schema migrations on database restore
* Bug fixes and AMS Label persistence updates
* Update database.py to resolve PR conflicts
* PR Comment Resolution
* Resolve conflicts in database.py for PR#570
* Updates to address PR#570 additional comments
* Optimize visibility handling for popup component
* Improve serial key handling in printers.py
Refactor serial key assignment to handle empty AMS serial gracefully.
* Implement error handling in serial number mapping
Add error handling for serial number mapping.
* Add migration to drop old ams_labels table
---------
Co-authored-by: MartinNYHC <mz@v8w.de>
* Fix AMS slot modal not scrolling to preselected filament
The scroll useEffect fired before the loading spinner was replaced
by the preset list, so the DOM element didn't exist yet. The ref
guard was then set, preventing any retry once buttons appeared.
- Move isLoading computation before the scroll effect and add it
as a dependency so the effect re-runs when loading completes
- Gate scroll on !isLoading so it only runs when buttons exist
- Only mark scrolledToRef after the element is actually found
- Use requestAnimationFrame to scroll after browser layout
- Use block:'center' so the selected item is clearly visible
Preselect filament for printer-configured AMS slots
When an AMS slot was configured directly on the printer (no
savedPresetId), the modal didn't preselect the filament even though
it was in the list. Add a third fallback that matches trayInfoIdx
against the full filteredPresets list (cloud and builtin sources).
* Restore scrolledToRef lost during merge
The useRef import, scrolledToRef declaration, and its reset were
dropped during the 0.2.2b1 merge, causing a ReferenceError in the
scroll-to-preselected-filament effect.
* Fix preset scroll loop and wire up useEffect scroll logic
- Remove inline ref callbacks with scrollIntoView on both preset
button lists (fullscreen + standard) to stop the infinite scroll
loop on Windows
- Add data-preset-id attribute so the existing useEffect/querySelector
scroll logic can actually find the elements
- Replace filteredPresets dependency with builtinFilaments in the
selection useEffect to prevent search keystrokes from overriding
manual preset selection
* Adjust scroll behavior in ConfigureAmsSlotModal
---------
Co-authored-by: MartinNYHC <mz@v8w.de>
Floating bug report button submits issues via bambuddy.cool relay (no GitHub
token needed locally). Collects 30s debug logs with printer push_all, sanitizes
all sensitive data, uploads logs as files to GitHub. Screenshot upload/paste/drag
with JPEG compression. Translated into all 7 languages. Includes 21 tests.
Parse home_flag bit 18 (0x00040000) from MQTT to detect ethernet
connections. When set, the printer card shows a green "Ethernet"
badge with a cable icon instead of WiFi signal strength in dBm.
The printer info modal also displays "Ethernet" instead of WiFi
signal details.