- Extract SkipObjectsModal from PrintersPage into reusable component
- Add chamber light toggle and skip objects buttons to EmbeddedCameraViewer
and CameraPage header bars
- Add printerStatus query to camera views (React Query deduplicates with
existing PrintersPage query)
- Fix camera/stop 401 when auth enabled: replace sendBeacon with
fetch + keepalive + auth headers in both camera components
- Add camera.chamberLight i18n key (en, de, ja)
- Add AuthProvider to CameraPage test wrapper
- Changed the 401 handling in request() to only clear the auth token when the error message indicates the token is actually invalid
- Previously: ANY 401 response cleared the token (could cause cascading failures)
- Now: Only clears on specific messages like "Token has expired", "Could not validate credentials", etc.
- "Authentication required" (which might be a timing issue) no longer clears the token
Closes#257
- SSDP proxy for cross-network setups: select slicer network interface for automatic printer discovery via SSDP relay
- FTP proxy now listens on privileged port 990 (matching Bambu Studio expectations) instead of 9990
- For systemd: requires `AmbientCapabilities=CAP_NET_BIND_SERVICE` capability
- Automatic directory permission checking at startup with clear error messages for Docker/bare metal
When multiple AMS trays have the same filament type and color, Bambuddy
now uses the tray_info_idx attribute from the 3MF file to identify the
exact spool selected during slicing. This ensures the correct tray is
used rather than just picking the first match.
Matching priority: tray_info_idx > exact color > similar color > type-only
Closes#245
The ams_mapping2 format was incorrectly using the tray_id (254/255) as
the slot_id for external spools. The printer expects slot_id to be the
actual slot index (0 for main nozzle, 1 for deputy nozzle), not the
tray_id value.
Before: {"ams_id": 255, "slot_id": 254} <- invalid slot index
After: {"ams_id": 255, "slot_id": 0} <- correct slot index
This caused prints using external spool to fail immediately with error
code 07FF_8007.
Closes#213
Introduces a new "Proxy Mode" for the Virtual Printer that enables
remote printing from anywhere in the world without VPN, port forwarding,
or Bambu Cloud dependency.
Bambuddy acts as a TLS relay between a remote slicer (Bambu Studio/
OrcaSlicer) and the local Bambu Lab printer:
Remote Slicer → Internet → Bambuddy Server → Local Network → Printer
The slicer connects to Bambuddy using the real printer's serial number
and access code. Bambuddy authenticates and relays all FTP (file transfer)
and MQTT (commands/status) traffic with end-to-end TLS encryption.
- No port forwarding required - printer stays safely on local network
- No VPN needed - connect from coffee shops, hotels, work, anywhere
- No Bambu Cloud dependency - fully self-hosted solution
- End-to-end TLS encryption on FTP (port 9990) and MQTT (port 8883)
- Works with Bambu Studio and OrcaSlicer
- Uses real printer credentials for authentication
- Automatic printer selection from connected printers
- Add SlicerProxyManager class for TLS relay (tcp_proxy.py)
- TLS termination with auto-generated certificates
- Concurrent FTP and MQTT proxy servers
- Connection lifecycle management with proper cleanup
- Extend VirtualPrinterManager with proxy mode support
- New 'proxy' mode alongside archive/review/queue modes
- Target printer selection and credential management
- Add proxy configuration endpoints to settings API
- Add permission checks for proxy endpoints
- Add Proxy Mode card to Virtual Printer settings
- Target printer dropdown for proxy destination
- Real-time proxy status display (ports, target, running state)
- Full i18n support (English, German)
- Add network architecture diagram
- Add proxy mode section to README
- Add comprehensive guide to wiki
- Add prominent feature section to website
- Backend unit tests for SlicerProxyManager
- Backend unit tests for proxy mode configuration
- Frontend tests for proxy mode UI components
Closes#207#170
Several frontend components were using raw fetch() instead of the API
client, causing 401 Unauthorized errors when authentication is enabled.
Changes:
- SpoolmanSettings: Use api.getSpoolmanSettings/updateSpoolmanSettings
- ProjectsPage: Use api.importProjectFile for ZIP imports
- ProjectDetailPage: Use api.exportProjectZip for exports
- CameraPage/EmbeddedCameraViewer: Use api.getCameraStatus
Added to API client:
- getSpoolmanSettings()
- updateSpoolmanSettings()
- importProjectFile()
- exportProjectZip()
- getCameraStatus()
Added tests for auth token handling in client.test.ts
Fixed VirtualPrinterSettings test expectations to match i18n strings
Closes#231
When a spool is already linked in Spoolman, the FilamentHoverCard now shows
"Open in Spoolman" button instead of "Link to Spoolman". This allows users
to quickly navigate to the spool's page in Spoolman for editing.
Changes:
- Add GET /api/v1/spoolman/spools/linked endpoint returning tag->spool_id map
- FilamentHoverCard shows "Open in Spoolman" when linkedSpoolId is set
- "Link to Spoolman" only shows when spool is not linked
- Fix unlinked spools detection to strip JSON quotes from empty tags
- Add toast notifications for link success/failure
- Invalidate linked-spools query after linking
- Add backend tests for linked spools endpoint
- Add frontend tests for LinkSpoolModal
Closes#210
The ams_mapping2 format was incorrectly using the tray_id (254/255) as
the slot_id for external spools. The printer expects slot_id to be the
actual slot index (0 for main nozzle, 1 for deputy nozzle), not the
tray_id value.
Before: {"ams_id": 255, "slot_id": 254} <- invalid slot index
After: {"ams_id": 255, "slot_id": 0} <- correct slot index
This caused prints using external spool to fail immediately with error
code 07FF_8007.
Closes#213
- Add ?fps=N parameter to control camera frame rate (1-30, default 15)
- Add ?camera=false parameter for status-only overlay without camera feed
- Increase default camera FPS from 10 to 15 across all camera views
- Add comprehensive tests for new overlay parameters
Resolves user request on Issue #164 for higher FPS and status-only option.
Implement a full permissions system replacing simple admin/user roles:
Backend:
- Add Group model with many-to-many user relationship
- Add 50+ granular permissions (resource:action pattern)
- Create default groups: Administrators, Operators, Viewers
- Add permission-checking dependencies for route protection
- Add groups API endpoints (CRUD, user assignment)
- Add change password endpoint for users
- Update backup/restore to include groups
- Migrate existing users to groups on startup
Frontend:
- Add GroupsPage for managing groups and permissions
- Add permission helpers to AuthContext (hasPermission, hasAnyPermission)
- Add PermissionRoute component for protected routes
- Disable buttons/features based on permissions (with tooltips)
- Add change password modal in sidebar for all users
- Add forgot password info modal on login page
- Show user groups in UsersPage with group assignment
Testing:
- Add integration tests for groups API
- Add tests for user-group assignments
- Add tests for change password endpoint
- Seed default groups in test fixtures
Closes#28#161
Implement centralized tag management for print archives:
- GET /archives/tags endpoint to list all tags with usage counts
- PUT /archives/tags/{name} endpoint to rename tags across archives
- DELETE /archives/tags/{name} endpoint to delete tags from archives
- TagManagementModal component with search, sort, rename, and delete
- Gear icon button next to tag filter dropdown on Archives page
- Fix tag autocompletion in EditArchiveModal using dedicated getTags API
Closes#183
- Add separate MQTT topics for power, energy, and state monitoring
- mqtt_power_topic, mqtt_power_path, mqtt_power_multiplier
- mqtt_energy_topic, mqtt_energy_path, mqtt_energy_multiplier
- mqtt_state_topic, mqtt_state_path, mqtt_state_on_value
- Support different MQTT topics per data type (e.g., Zigbee2MQTT with
separate power/energy/state topics)
- Individual multipliers for power and energy (e.g., mW→W, Wh→kWh)
- Configurable ON value for state monitoring (e.g., "ON", "true", "1")
- Maintain backward compatibility with legacy mqtt_topic/mqtt_multiplier
- Database migration auto-copies legacy fields to new fields
- Update backup/restore to handle new MQTT fields
- Add backend tests for new MQTT configurations
- Update frontend form with organized Power/Energy/State sections
Closes#173
Add a dedicated overlay page at /overlay/:printerId that combines
camera feed with real-time print status for live streaming use cases.
Features:
- Camera feed as fullscreen background
- Status overlay at bottom with gradient for readability
- Real-time updates via WebSocket with polling fallback
- Customizable via query params (?size=large&show=progress,eta)
Closes#164
Add support for MQTT-based smart plugs that subscribe to external MQTT
topics and extract power/energy data from JSON payloads. This enables
integration with Zigbee2MQTT, Shelly, Tasmota discovery, and other
MQTT-enabled energy monitoring devices.
Features:
- New "mqtt" plug type alongside tasmota and homeassistant
- Subscribe to any MQTT topic with configurable JSON paths
- Extract power, energy, and state values using dot notation
- Optional multiplier for unit conversion (mW to W, etc.)
- Monitor-only mode (no on/off control) with teal color scheme
- Reuses existing MQTT broker settings from network configuration
- Energy data included in statistics and per-print tracking
- Full backup/restore support for MQTT plug configurations
Closes#173
Add new setting "Check printer firmware" in Settings → General → Updates
that allows users to disable automatic firmware update checks from
Bambu Lab servers.
Closes#169
- Queue now shows correct plate thumbnail based on selected plate_id
(previously always showed plate 1 regardless of selection)
- Archive cards now support plate browsing for multi-plate 3MF files:
- Left/right arrows to cycle through plates on hover
- Dot indicators at bottom show current plate (clickable)
- Lazy-loads plate data only when user hovers
- Added getArchivePlateThumbnail and getLibraryFilePlateThumbnail API methods
Closes#166
Model-based queue assignment:
- Extract printer_model from sliced 3MF files during upload
- Display sliced-for model in archive view
- New queue mode: assign to "Any [Model]" instead of specific printer
- Scheduler auto-assigns to first idle printer of matching model
- Filament validation: only assign to printers with required filament types loaded
- Waiting reason display shows why jobs are waiting (e.g., "Waiting for filament: Printer1 (needs PLA)")
- "Waiting" status badge (purple) distinguishes from regular "Pending"
Queue notifications (7 new events):
- Job Added: When a job is added to queue
- Job Assigned: When a model-based job is assigned to a printer
- Job Started: When a queue job starts printing
- Job Waiting: When a job is waiting for filament (enabled by default)
- Job Skipped: When a job is skipped due to previous failure (enabled by default)
- Job Failed: When a job fails to start (enabled by default)
- Queue Complete: When all queued jobs finish
Backend changes:
- New columns: print_queue.target_model, print_queue.required_filament_types, print_queue.waiting_reason
- New columns: notification_providers.on_queue_job_* (7 event triggers)
- Notification templates for all queue events
- Scheduler validates filament compatibility before model-based assignment
- Queue API extracts filament types from 3MF when adding model-based items
- Local backup/restore includes queue notification settings
Frontend changes:
- TypeScript interfaces updated for new fields
- Queue page shows waiting reason and "Waiting" badge
- Notification settings includes "Print Queue" section with 7 toggles
Closes#162
New feature to automatically backup K-profiles, cloud profiles, and app
settings to a GitHub repository with scheduled or on-demand execution.
Features:
- Configure GitHub repo URL and Personal Access Token
- Schedule backups hourly, daily, or weekly (background scheduler)
- Manual backup trigger with real-time progress tracking
- Skip unchanged commits (only creates commit when data changes)
- Backup history log with status and commit links
- Requires Bambu Cloud login for full profile access
- New Settings → Backup & Restore tab consolidating all backup options
- GitHub backup config included in local backup/restore (except PAT)
Backend:
- New models: GitHubBackupConfig, GitHubBackupLog
- New service: GitHubBackupService with scheduler and GitHub API client
- New routes: /github-backup/* for config, status, logs, and triggers
- Updated settings.py to include github_backup in backup/restore
Frontend:
- New GitHubBackupSettings.tsx component with auto-save
- Updated SettingsPage with Backup tab and status indicator
- Added API types and methods to client.ts
Tests:
- Backend integration tests for all GitHub backup API endpoints
- Frontend API type and endpoint tests
- Add "Plate Detection" option to backup modal for exporting empty plate
reference images (requires Printers to be selected)
- Add parents=True to mkdir calls in config.py to create full directory
tree on first run (fixes startup crash when data dir doesn't exist)
- Update BackupModal test to use exact match for "Printers" text
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
- 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
Features:
- ZIP file support in File Manager (Issue #121): Upload ZIP files to
automatically extract contents with option to preserve folder structure
- Delete operation loading indicator: Shows progress during folder/file
deletion operations
Fixed:
- Print time stats using actual elapsed time instead of slicer estimates
(Issue #137)
- Skip objects modal overflow with scrollable list for many objects
(Issue #134)
Removed:
- Duplicate badge feature from File Manager (per user request)
Tests:
- Added ZIP extraction backend tests (5 tests)
- Added ConfirmModal loading state frontend tests (5 tests)
Fixes:
- Fixed is_auth_enabled() returning None instead of False when setting doesn't exist (in both auth.py and routes/auth.py)
- Fixed get_current_user() crashing when credentials is None
- Added missing async_session patch in conftest.py for auth tests
Backup/Restore - Added Users Support
- Added include_users parameter to backup export
- Users are exported with username, role, and is_active (passwords excluded for security)
- Restore creates users with temporary passwords that must be changed
Backend Tests - 16 New Auth Tests
- test_auth_api.py with tests for:
- Auth status endpoint
- Auth setup (enable/disable)
- Login flow (success, invalid credentials, auth disabled)
- /me endpoint with/without token
- User management (list, create, update, delete)
- Auth disable
Frontend Tests - 6 New Login Tests
- LoginPage.test.tsx with tests for:
- Form rendering
- Input validation
- Login submission
- Loading states
Documentation Updates
- CHANGELOG.md/README.md: Added authentication feature description
- Website (features.html): Added new "Optional Authentication" section
- Wiki: Created authentication.md with full documentation
- Wiki index: Added authentication to features list