Track and display who performs key actions in Bambuddy:
- Archives: who uploaded each archive file
- Library: who uploaded each file in File Manager
- Queue: who added each print job to the queue
- Printers: who started the current print (reprint tracking)
Backend changes:
- Add created_by_id column to print_archives, library_files, print_queue tables
- Add database migrations for new columns (auto-run on startup)
- Update archive, library, and queue routes to capture current user
- Add current-print-user endpoint for printer reprint tracking
- Track reprint user in PrinterManager in-memory state
- Fix file uploads not sending auth headers (FormData requires explicit headers)
Frontend changes:
- Display username on archive cards, library files, queue items
- Show "Started by" on printer cards during active prints
- Add auth headers to all 12 FormData upload functions
- Update TypeScript types for user tracking fields
Tests:
- Add unit tests for PrinterManager user tracking methods (7 tests)
- Add integration tests for current-print-user endpoint (3 tests)
- Add integration tests for library file user tracking (3 tests)
Works when authentication is enabled; gracefully hidden when disabled.
Closes#206
When using "Any [Model]" queue assignment, the scheduler now computes
AMS mapping after a printer is assigned, instead of requiring it upfront.
This fixes H2D Pro (and other printers) failing at filament loading when
queued via model-based assignment. The issue was that no AMS mapping was
sent to the printer because the specific printer wasn't known at queue time.
Closes#192
- Implemented batch STL thumbnail generation API endpoint.
- Added Pydantic schemas for batch thumbnail requests and responses.
- Created service for generating thumbnails from STL files using trimesh and matplotlib.
- Updated file upload and ZIP extraction endpoints to include thumbnail generation option.
- Enhanced frontend to support STL thumbnail generation during file uploads and ZIP extractions.
- Added integration and unit tests for the new thumbnail generation features.
- Updated requirements to include necessary libraries for STL processing.
- Add trimesh and matplotlib dependencies for software-based 3D rendering
- Create stl_thumbnail service with generate_stl_thumbnail() function
- Handle mesh simplification for large files (>100k vertices)
- Auto-generate thumbnails during STL file upload and ZIP extraction
- Add POST /library/files/{id}/regenerate-thumbnail endpoint
- Add POST /library/generate-stl-thumbnails batch endpoint
- Add "Generate Thumbnails" button to file manager toolbar
- Add "Regenerate Thumbnail" option to file context menu
- Add unit and integration tests for new functionality
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Some A1/A1 Mini firmware versions incorrectly report stg_cur=0 (which
maps to "Printing") even when the printer is idle. This is a known
firmware bug also observed in the Home Assistant Bambu Lab integration.
- Add A1_MODELS constant listing affected model variants
- Add has_stg_cur_idle_bug() helper to identify affected models
- Update get_derived_status_name() to check gcode_state before stg_cur
for A1 models: if IDLE + stg_cur=0, return None to show "Idle"
- Fix only applies when all conditions match (A1 model + IDLE + stg_cur=0)
- Non-A1 printers and A1 printers without the bug are unaffected
Closes#168
- Add USB camera type to external camera service
- Auto-detect available V4L2 devices on Linux
- New API endpoint: GET /api/v1/printers/usb-cameras
- Use ffmpeg for USB camera capture and streaming
- Add "USB Camera (V4L2)" option in Settings UI
- Debounce camera URL input to avoid saving on every keystroke
Closes#143
Automatically detect if objects are on the build plate before printing
and pause the print immediately if detected.
Features:
- Per-printer toggle to enable/disable plate detection
- Multi-reference calibration: store up to 5 reference images per printer
for different plate types (textured, smooth, high-temp, etc.)
- Automatic print pause when objects detected at print start
- Push notification and WebSocket alert when print is paused
- ROI (Region of Interest) calibration UI with sliders to adjust
detection area
- Reference management: view thumbnails, add labels, delete references
- Works with both built-in and external cameras
- Uses buffered camera frames when stream is active (no blocking)
- Split button UI: main button opens modal, chevron toggles on/off
- Green visual indicator when plate detection is enabled
- Included in backup/restore
When spools were removed from AMS slots, Bambuddy continued showing them
as loaded. Fixed for both old and new AMS models:
- Old AMS: Allow empty values to overwrite slot data during merge
(tray_type, tray_color, tag_uid, etc. were being skipped)
- New AMS (AMS 2 Pro): Parse tray_exist_bits bitmask to detect empty
slots and clear their data accordingly
Added 3 unit tests for AMS data merging behavior.
Closes#147
Add support for external network cameras (MJPEG, RTSP, HTTP snapshot)
that replace a printer's built-in camera when configured.
Features:
- Live streaming on printers page (replaces built-in camera)
- Finish photo capture from external camera on print complete
- Layer-based timelapse: captures frame on each layer change,
stitches to MP4 video on print completion
Backend changes:
- Add external_camera_url, external_camera_type, external_camera_enabled
fields to Printer model with database migration
- New external_camera.py service: MJPEG/RTSP/snapshot frame capture,
connection testing, MJPEG stream generation
- New layer_timelapse.py service: TimelapseSession management,
layer-by-layer frame capture, ffmpeg video stitching
- Add on_layer_change callback to MQTT client and printer manager
- Update camera routes with external camera streaming and tracking
- Update print lifecycle hooks for timelapse start/stitch/cancel
- Add external camera fields to backup/restore
- Rate limiting for external camera streams (prevents browser freeze)
Frontend changes:
- Add external camera configuration UI in Settings > Camera
- Per-printer enable toggle, URL input, type selector, test button
- Toast notification on save
Closes#143
- Add "Recalculate Costs" button to Dashboard that updates all archive
costs using current filament prices (Issue #120)
- Track reprints and add cost to existing archive total on completion,
so statistics accurately reflect total filament expenditure
Closes#120
Root Cause: The generic webhook sent a JSON payload with custom field names plus timestamp and source fields. Mattermost/Slack webhooks only accept {"text": "..."}
format and reject unknown fields with HTTP 400.
Users just need to select "Slack / Mattermost" from the Payload Format dropdown when configuring their Mattermost webhook.
Closes#133
Root Cause: P2S (and other newer models) may report their model as internal codes (e.g., "N7" for P2S) rather than display names in MQTT/SSDP responses. The camera code
only checked for display names like "P2S", causing it to incorrectly use the chamber image protocol (for A1/P1) instead of RTSP.
Internal Code Mapping:
BL-P001 → X1/X1C (RTSP)
C13 → X1E (RTSP)
O1D → H2D (RTSP)
O1C → H2C (RTSP)
O1S → H2S (RTSP)
O1E → H2D Pro (RTSP)
N7 → P2S (RTSP)
C11 → P1P (Chamber)
C12 → P1S (Chamber)
N2S → A1 (Chamber)
N1 → A1 Mini (Chamber)
Closes#127
- Add {finish_photo_url} template variable for print_complete, print_failed,
print_stopped events
- Photo capture now completes before notification is sent (ensures image exists)
- Add External URL setting in Settings → Network (auto-detects from browser)
- Full URL constructed using external_url setting for external services
- Fix Telegram Markdown parsing error when messages contain URLs
- Add backend schema for external_url setting
- Add unit test for finish_photo_url variable passing
Manually configure AMS slots for third-party or generic filaments:
1. Hover over an AMS slot on the printer card
2. Click the menu button (:material-dots-vertical:) that appears
3. Select **Configure Slot**
4. Choose a filament preset from your Bambu Studio cloud presets
5. Select a matching K profile (pressure advance calibration)
6. Optionally set a custom color using the color picker
7. Click **Configure Slot** to apply
**Color Picker Features:**
- Enter custom hex codes or color names (e.g., "brown", "FF8800")
- Live preview of selected color
- Expandable color picker in Configure AMS Slot modal:
- 8 basic colors shown by default
- 24 additional colors available via expand button
- Tests for ConfigureAmsSlotModal component
- Tests for AMS change callback
- Updated README with AMS slot configuration feature
- Wiki documentation for Configure AMS Slot feature
- Multi plate issue where plate names showed incorrect. #93
- Items from Queue end up as "source" files in archive. #107
- Added env variable support to change network port. #108
Docs -> https://wiki.bambuddy.cool/getting-started/docker/?h=port#custom-port
When reprinting a multi-plate 3MF file exported with "All sliced file",
the system now asks which plate to print and only maps filaments for
that specific plate.
Backend changes:
- Add GET /archives/{id}/plates endpoint to list available plates
with thumbnails, print times, and per-plate filament requirements
- Add GET /archives/{id}/plate-thumbnail/{index} for plate thumbnails
- Update GET /archives/{id}/filament-requirements to accept plate_id
query parameter for filtering filaments by plate
- Add plate_id field to ReprintRequest schema
- Update POST /archives/{id}/reprint to use plate_id from request body
instead of auto-detecting (maintains backward compatibility)
Frontend changes:
- Add getArchivePlates API method
- Update getArchiveFilamentRequirements to accept optional plateId
- Update reprintArchive to accept plate_id in options
- Add plate selection UI to ReprintModal when multi-plate 3MF detected
- Show plate thumbnails, names, and filament counts in selection grid
- Require plate selection before printing multi-plate files
- Filter filament requirements to show only selected plate's filaments
Tests:
- Add unit tests for multi-plate slice_info.config parsing
- Add unit tests for plate detection from gcode files
- Add integration tests for new plate endpoints
When exporting individual plates from a multi-plate 3MF in Bambu Studio,
all uploaded archives showed plate 1's name and thumbnail regardless of
which plate was actually exported.
Root cause: The 3MF parser used an incorrect XPath lookup (plate_idx
attribute) and didn't extract the plate index from slice_info.config
metadata.
Changes:
- Extract plate index from <metadata key="index" value="N"/> in
slice_info.config
- Remove incorrect plate[@plate_idx='N'] XPath lookup that doesn't
work for single-plate exports
- Set self.plate_number from extracted index so _extract_thumbnail()
uses the correct plate thumbnail (e.g., plate_5.png instead of
plate_1.png)
- Append " - Plate N" to print_name when plate index > 1 to
distinguish multi-plate exports
- Add 7 unit tests for plate index extraction and print_name
enhancement
Track individual parts/objects separately from print plates in projects.
Useful for multi-part builds like Voron where 25 plates produce 150 parts.
Backend:
- Add target_parts_count field to Project model
- Calculate parts_progress_percent and remaining_parts in stats
- Auto-detect quantity from 3MF printable objects when archiving
- Sum archive quantities for completed_count (parts)
- Use archive_count for plates progress
Frontend:
- Add "Target Parts" input in project create/edit modal
- Show separate progress bars for plates vs parts
- Stats footer displays both plates and parts count
- Header badge shows parts progress when target set
Scripts:
- Add update_archive_quantities.py to migrate existing archives
Tests:
- Add 5 integration tests for parts tracking
- Add 3 unit tests for 3MF object extraction
Closes#85
Fix Applied:
1. Added supports_chamber_temp() helper function that returns True only for X1/X1C/X1E, P2S, and H2 series
2. Modified printer_state_to_dict() to filter out chamber, chamber_target, chamber_heating from temperatures for unsupported models
3. Added model caching in PrinterManager so we can look up the model without a database query
4. Updated all callers (main.py, websocket.py) to pass the model
The chamber temperature widget will now simply not appear for P1S/P1P/A1/A1Mini printers since the temperatures.chamber field won't be sent to the frontend.
- Correct SSDP model codes: C11=P1P, C12=P1S, N7=P2S, C13=X1E
- Fix serial prefixes based on actual Bambu serial format
- Add confirmation modal for pending upload discard
- Sort model dropdown alphabetically, remove internal codes
- Add "Setup Required" warning with link to wiki documentation
- Update wiki with certificate installation and platform setup guides
Features:
- Configurable printer model for virtual printer emulation
- Supports X1 series (X1C, X1, X1E), P series (P1S, P1P, P2S),
A1 series (A1, A1 Mini), and H2 series (H2D, H2C, H2S)
- Dropdown in Settings > Virtual Printer to select model
- Model affects SSDP discovery and slicer compatibility
- Model change restarts virtual printer services automatically
Backend:
- Added VIRTUAL_PRINTER_MODELS mapping in manager.py
- Added virtual_printer_model setting in database
- New GET /api/v1/settings/virtual-printer/models endpoint
- Updated PUT /api/v1/settings/virtual-printer to accept model
Frontend:
- Added model dropdown to VirtualPrinterSettings component
- Status display shows selected model name
- Model change disabled while virtual printer is running
Tests:
- Added 3 unit tests for model configuration
- Updated frontend test mocks for getModels API
- New APIBrowser component with full OpenAPI schema integration
- Fetches and parses /openapi.json automatically
- Groups endpoints by API tags (printers, archives, settings, etc.)
- Expandable endpoint sections with color-coded method badges
- Path parameter, query parameter, and JSON body editors
- Auto-populates request body with schema examples
- Live API request execution with response display
- Response shows status code, timing, and formatted JSON
- Copy response button with clipboard fallback
- Search to filter endpoints across all categories
- Expand All / Collapse All buttons
- Link to Swagger UI (/docs)
- Two-column layout for API Keys tab
- Left: API key management + webhook documentation
- Right: API Browser with dedicated test key input
- Parameter validation
- Shows warning for missing required parameters
- Validates before sending requests to avoid 422 errors
- UX improvements
- "Use in API Browser" button on newly created keys
- Responsive layout (stacked on mobile, side-by-side on xl+)
- Virtual printer appears in Bambu Studio/Orca Slicer via SSDP discovery
- Secure TLS/MQTT communication with auto-generated certificates
- Queue mode (pending uploads) or auto-start mode
- Configurable access code for authentication
- Docker support with network_mode: host and certificate persistence
- Fix backup/restore for virtual printer settings (auto-save no longer overwrites)
1. "Unknown Status (255)" bug
File: backend/app/services/printer_manager.py:291-293
Problem: A1/P1 printers send stg_cur=255 when idle (unlike X1 which uses -1). The code treated 255 as a valid stage number and returned "Unknown stage (255)".
Fix: Changed the condition from if state.stg_cur >= 0: to if 0 <= state.stg_cur < 255: so that 255 is now treated as "no calibration stage" (same as -1).
2. AMS humidity/temp displaced on mobile
File: frontend/src/pages/PrintersPage.tsx:1164-1212
Problem: The AMS row used a rigid horizontal flex layout that didn't adapt to narrow mobile screens, causing humidity/temperature indicators to be displaced.
Fix:
- Added flex-wrap to allow wrapping on very narrow screens
- Added ml-auto to humidity/temp section to keep it right-aligned
- Added max-w-[60px] sm:max-w-none to truncate long filament names on mobile
- Changed gap from fixed gap-3 to responsive gap-2 sm:gap-3
Tests Added
4 new unit tests for get_derived_status_name:
- test_stg_cur_255_returns_none - Verifies A1/P1 idle state
- test_stg_cur_negative_one_returns_none_when_idle - Verifies X1 idle state
- test_valid_stage_returns_name - Verifies valid stages work
- test_stg_cur_zero_returns_printing - Verifies printing state
All 382 tests pass.
Problem: xcam data was parsed BEFORE _was_running was set to True, so timelapse detection failed when both arrived in the same message.
Fix: Added timelapse detection at two critical points:
# Lines 1375-1381: When entering RUNNING state
if self.state.state == "RUNNING" and current_file:
if not self._was_running:
if self.state.timelapse:
self._timelapse_during_print = True
logger.info(f"[{self.serial_number}] Timelapse detected when entering RUNNING state")
# Lines 1391-1399: When print start detected
if self.state.timelapse:
self._timelapse_during_print = True
logger.info(f"[{self.serial_number}] Timelapse detected at print start")
2. Callback Error Handling (main.py + printer_manager.py)
Problem: The on_print_complete callback was hanging silently - no logs after "Found archive".
Fixes:
- Added try/except wrapper around "Update archive status" section (line 749-767)
- Added [CALLBACK] log messages at start and end of callback
- Added exception handler to _schedule_async in printer_manager.py to log any exceptions from async callbacks
3. New Integration Tests (test_bambu_mqtt.py)
Added TestRealisticMessageFlow class with 5 new tests that simulate real MQTT message sequences:
1. test_timelapse_detected_at_print_start_in_same_message - The critical race condition test
2. test_timelapse_not_detected_when_disabled
3. test_timelapse_detected_when_enabled_after_print_start
4. test_print_complete_includes_timelapse_flag_full_flow - Full lifecycle test
5. test_print_failed_includes_timelapse_flag
These tests process messages through _process_message() with proper {"print": {...}} wrapping, matching real MQTT flow.
Files Modified:
- backend/app/services/bambu_mqtt.py - Timelapse race condition fix
- backend/app/main.py - Error handling + logging for on_print_complete
- backend/app/services/printer_manager.py - Exception capture in _schedule_async
- backend/tests/unit/services/test_bambu_mqtt.py - New integration tests
Next Steps
You should restart the application to apply these changes. The next print will show:
- [CALLBACK] on_print_complete started for printer X
- [ARCHIVE] Updating archive X status...
- [ENERGY], [PHOTO], [AUTO-OFF] logs (if those features trigger)
- [CALLBACK] on_print_complete finished for printer X, archive X
Expanded the useWebSocket.test.ts from minimal coverage to 20 comprehensive tests covering:
WebSocket Mock Tests (6 tests)
- Creates WebSocket with correct URL
- Starts in CONNECTING state
- Transitions to OPEN state
- Can receive messages
- Can close connection
- Tracks all instances
Hook Connection Tests (2 tests)
- Connects to WebSocket on mount
- Reports connected state when WebSocket opens
Message Handling Tests (9 tests)
- Updates printer status in query cache on printer_status message
- Preserves wifi_signal when new value is null
- Invalidates archives on print_complete message
- Invalidates archives on archive_created message
- Invalidates archives on archive_updated message (new handler for timelapse auto-assignment)
- Ignores pong messages without error
- Handles malformed JSON gracefully
- Handles unknown message types gracefully
sendMessage Tests (2 tests)
- Sends JSON message when connected
- Does not send when disconnected
Reconnection Tests (2 tests)
- Reconnects after connection closes
- Cleans up on unmount
Key Fixes
- Fixed MSW (Mock Service Worker) conflict by:
a. Adding addEventListener/removeEventListener to MockWebSocket class
b. Updating MSW setup to bypass WebSocket requests
c. Properly managing WebSocket mock lifecycle in each test
Test Results:
- Frontend: 137 tests passed (9 test files)
- Backend: 346 tests passed
Backend:
- pytest configuration with async support and coverage
- Unit tests for notification service (23 tests)
- Unit tests for smart plug manager (12 tests)
- Unit tests for archive service (16 tests)
- Integration tests for API endpoints
- Fix: notifications now send immediately (digest is summary only)
Frontend:
- Vitest configuration with jsdom and coverage
- MSW for API mocking
- Component tests for Toggle, Button, Card, ConfirmModal (77 tests)
- Test utilities with custom render wrapper
CI/CD:
- GitHub Actions workflow for automated testing
- Backend lint, unit tests, integration tests
- Frontend lint, type-check, unit tests, build