New feature: Publish BamBuddy events to external MQTT brokers for integration
with Home Assistant, Node-RED, and other automation platforms.
Backend changes:
- New MQTTRelayService (backend/app/services/mqtt_relay.py) with paho-mqtt
- MQTT settings added to AppSettings schema (enabled, broker, port, auth, TLS)
- New /settings/mqtt/status endpoint for connection status
- Event hooks in main.py, print_queue.py, print_scheduler.py, maintenance.py, smart_plugs.py
- PrinterInfo class and get_printer() method added to PrinterManager
- MQTT reconfiguration added to backup/restore flow
- Printer status throttled to 1 update/sec to avoid flooding
Frontend changes:
- New "Network" tab in Settings (between Filament and API Keys)
- FTP Retry settings moved from General to Network tab
- MQTT configuration card with broker, port, TLS toggle, auth fields
- Port auto-populates when TLS toggled (1883 ↔ 8883)
- Connection status indicator (green/red dot) in tab and card header
- Real-time status polling when on Network tab
Published topics:
- bambuddy/status - Online/offline
- bambuddy/printers/{serial}/status - Printer state (throttled)
- bambuddy/printers/{serial}/print/* - Print lifecycle
- bambuddy/printers/{serial}/ams/changed - AMS changes
- bambuddy/queue/* - Queue events
- bambuddy/maintenance/* - Maintenance alerts
- bambuddy/smart_plugs/* - Plug state/energy
- bambuddy/archive/* - Archive events
Tests:
- Added MQTT settings and status endpoint tests
Closes#78
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.
- Moved BAMBU_HEX_COLORS mapping and getColorName()/hexToColorName() functions to a shared location
- Exported functions for use across components
- Updated modals to use shared colors:
- ReprintModal.tsx - removed ~100 lines of duplicate color code, now imports from utils/colors
- AddToQueueModal.tsx - same cleanup
- EditQueueItemModal.tsx - same cleanup
- Added AMS mapping to EditQueueItemModal:
- Added state for showFilamentMapping, isRefreshing, manualMappings
- Added queries for filament requirements and printer status
- Added loadedFilaments, filamentComparison, amsMapping memos
- Added collapsible filament mapping UI section (same as other modals)
- Initializes manualMappings from existing item.ams_mapping
- Submits ams_mapping when saving changes
- Backend changes:
- Added ams_mapping field to PrintQueueItemUpdate schema
- Updated update_queue_item route to serialize ams_mapping to JSON
- Frontend API client:
- Added ams_mapping to PrintQueueItemUpdate interface
- Changed "Print" to "Reprint" on archive card button (ArchivesPage.tsx:690)
- Bumped service worker to v22
- Comprehensive hex-based color mapping (~200 Bambu colors from CSV)
- Fixed tooltips to use Bambu color lookup
- Widened modals (max-w-md → max-w-lg)
- Adjusted grid layout to fit long color names
- Service worker bumped to v21
Pending changes in bambuddy repo:
- CHANGELOG.md, README.md
- backend/app/api/routes/print_queue.py
- backend/tests/integration/test_print_queue_api.py
- frontend components (ReprintModal, AddToQueueModal, EditQueueItemModal)
- sw.js (v21)
- ReprintModal: Dropdown to override auto-matched AMS slots
- AddToQueueModal: Collapsible filament mapping section
- Backend: Store ams_mapping in print queue, apply when print starts
- Color names in dropdowns (decoded from Bambu codes or derived from hex)
- Blue ring indicator for manually selected vs auto-matched slots
- Status indicators: green (match), yellow (type only), orange (not found)
Closes#76
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add time format utilities to date.ts (applyTimeFormat, formatDateTime,
formatTimeOnly, TimeFormat type)
- PrintersPage: Pass timeFormat to formatETA for printer card ETA display
- ArchivesPage: Add timeFormat prop to ArchiveCard for archive timestamps
- AMSHistoryModal: Apply timeFormat to chart labels, axis ticks, and tooltip
- ProjectDetailPage: Use formatDateTime for timeline dates
- QueuePage: Pass timeFormat to formatRelativeTime for scheduled prints
- SystemInfoPage: Use formatDateTime for boot time display
- NotificationLogViewer: Apply timeFormat to notification timestamps
- Bump service worker cache version to v17
Closes#75
- Add size-aware rendering to Dashboard component, passing widget size
(1/4, 1/2, full) to component render functions
- PrintCalendar: Dynamic cell sizing using ResizeObserver to fill
available width, shows 3/6/12 months based on widget size
- SuccessRateWidget: Per-printer breakdown at larger sizes
- TimeAccuracyWidget: Per-printer breakdown at larger sizes
- FilamentTypesWidget: Grid layout at larger sizes
- FailureAnalysisWidget: More failure reasons at larger sizes
- Bump service worker cache version
- New BatchProjectModal component for assigning archives to projects
- "Project" button in selection toolbar (next to Tags)
- Select a project to assign all selected archives at once
- "Remove from project" option to clear assignments in bulk
- Proper query invalidation for Projects page and Project Detail page
Closes#70
- Add light toggle button next to camera button at bottom of card
- Custom ChamberLight SVG icon with on/off states (yellow fill + rays when on)
- Backend endpoint: POST /printers/{id}/chamber-light?on=true|false
- Optimistic UI update for instant feedback
- Works on all Bambu Lab printers (X1, P1, A1, H2D)
- H2D dual chamber lights controlled together
Closes#67
Previously only ran tests/unit/, now runs tests/ to match
test_backend.sh workflow (513 tests instead of 239).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Multi-color prints store comma-separated values in filament_color (e.g.,
"#FFFFFF,#43403D") and filament_type (e.g., "PLA, PLA-S"). The project
cards were displaying these raw strings instead of splitting them into
individual badges.
- Split comma-separated colors into individual color swatches
- Split comma-separated materials into individual text badges
- Deduplicate both to avoid showing "PLA" multiple times
Problem: The backend stores timestamps in UTC, but when sending them to the frontend without timezone indicators, JavaScript interprets them inconsistently. Users saw UTC times displayed directly instead of converted to their local timezone (e.g., America/New_York).
Solution implemented:
1. Created /frontend/src/utils/date.ts with utilities:
- parseUTCDate(dateStr) - Parses backend timestamps as UTC by appending 'Z' to strings without timezone indicators
- formatDate(dateStr, options) - Formats UTC timestamps to local date/time
- formatDateOnly(dateStr, options) - Formats UTC timestamps to local date-only
2. Updated 15 frontend files to use the new utilities:
- ArchivesPage.tsx - Archive cards and list view dates
- PrintersPage.tsx - Last print date
- SettingsPage.tsx - API key last used date
- QueuePage.tsx - Scheduled print times
- ProjectDetailPage.tsx - Due dates and timeline
- ProfilesPage.tsx - Relative time display
- CalendarView.tsx - Calendar grouping by local date
- NotificationLogViewer.tsx - Log timestamps
- NotificationProviderCard.tsx - Last success date
- AMSHistoryModal.tsx - Chart data timestamps
- FilamentTrends.tsx - Usage data grouping
- PrinterQueueWidget.tsx - Queue item dates
The previous fix only skipped SSL session reuse for A1 printers but
still wrapped the data channel in SSL. VREmma's testing (issue #31)
showed that A1 printers need the data channel to not be SSL-wrapped
at all - they timeout waiting for transfer completion responses.
The fix:
- X1C/P1S: SSL with session reuse on data channel (required by vsFTPd)
- A1/A1 Mini: No SSL on data channel (control channel remains encrypted)
This matches VREmma's working fix (c723f25) which set ftplib._SSLSocket
to None, but implemented properly within the ImplicitFTP_TLS class.
Fixes#31
Thanks VREmma!
Resolves FTP transfer failures on A1/A1 Mini printers caused by SSL
session reuse incompatibility. Also adds configurable FTP timeout
setting for slow WiFi connections.
Changes:
- Add SSL session reuse bypass for A1/A1 Mini printers (auto-detected)
- Add printer_model parameter to FTP functions for model detection
- Add configurable FTP timeout (10-120s, default 30s) in Settings
- Update all FTP callers: archiving, reprint, timelapse, firmware upload
Technical details:
- A1/A1 Mini printers don't support vsFTPd's SSL session reuse
- X1C/P1S continue to use session reuse as required by their FTP server
- ImplicitFTP_TLS now accepts skip_session_reuse flag
- BambuFTPClient auto-detects A1/A1 Mini and sets flag accordingly
Added:
- Archive list view: edit/delete buttons and context menu with full feature parity
- Archive object count display on cards (extracted from 3MF metadata)
- Cross-view archive highlighting: click in calendar/project to highlight in card view
- Context menu button (⋮) on cards and list rows for easy access
- Spoolman: clear location when spools are removed from AMS
Fixed:
- QR code endpoint 500 error (added qrcode[pil] dependency)
Previously, when syncing to Spoolman, the location field was set to the
printer/AMS slot but was never cleared when the spool was removed from
the AMS.
Now during sync, the system tracks which tray UUIDs are currently in the
AMS and clears the location for any spools that were previously at this
printer but are no longer present.
Changes:
- Add clear_location parameter to update_spool() method
- Add find_spools_by_location_prefix() to find spools at a printer
- Add clear_location_for_removed_spools() to clear stale locations
- Update sync_printer_ams and sync_all_printers endpoints to clear
locations for removed spools after syncing
CameraPage no longer receives WebSocket messages - it was creating a second WebSocket connection that would also try to process print_complete events.
- Improved stall detection:
Now continues checking even when in error state.
Also triggers reconnect if the stream process died (!status.active)
Added console logging to help debug: Stream issue detected: stalled=X, active=X, reconnecting...
Features:
- Add print options UI to reprint modal (bed leveling, flow calibration,
vibration calibration, first layer inspection, timelapse)
- Collapsible "Print Options" section with toggle switches
- Default values: bed leveling=on, vibration_cali=on, others=off
Fixes:
- Fix AMS mapping format to match Bambu Studio exactly
- Use slot_id from 3MF to position tray IDs correctly
- Fill unused slots with -1 placeholder
- Add ams_mapping2 with detailed {ams_id, slot_id} pairs
- Fix print command format for proper printer recognition
- Add auto_bed_leveling, cfg, extrude_cali_flag, nozzle_offset_cali
- Use American spelling "bed_leveling" (not British "bed_levelling")
- Match sequence_id format from official apps
- Prevent duplicate tray assignment in filament matching
This resolves the "stuck at filament change" issue on multi-color reprints
affecting X1C and other multi-AMS printer configurations.
The delete_archive() function in backend/app/services/archive.py now has these safety checks:
1. Empty path check: Refuses to delete files if file_path is empty/whitespace
2. Path containment check: Verifies archive_dir is inside settings.archive_dir
3. Depth check: Ensures we're at least 1 level deep inside archive directory
4. Logging: All security refusals are logged with SECURITY prefix
5. Database record still deleted: Even if file deletion is refused, the orphan DB record is cleaned up
Before the fix:
file_path = settings.base_dir / archive.file_path # If empty: /opt/bambuddy
archive_dir = file_path.parent # = /opt
shutil.rmtree(archive_dir) # DELETES /opt!
Features:
- Add wiki_url field to MaintenanceType for custom type documentation links
- Add printer_model to MaintenanceStatus for model-specific URL mapping
- Display external link icon next to maintenance item names
- Map system maintenance types to Bambu Lab wiki pages by printer model:
- Lubricate Linear Rails, Clean Nozzle/Hotend, Check Belt Tension
- Clean Carbon Rods (X1/P1 only), Clean Build Plate, Check PTFE Tube
- HEPA/Carbon Filter, Left Nozzle Rail (H2 series)
- Add Documentation Link input to custom type create/edit forms
Bug fix:
- Fix 500 error when assigning maintenance type to printer (lazy loading)
Database:
- Add migration for wiki_url column on maintenance_types table
- Add /api/v1/support/debug-logging endpoints to toggle debug log level
- Add /api/v1/support/bundle endpoint to generate ZIP with system info and logs
- Debug logging state persists across restarts via Settings database
- Add debug logging indicator banner in Layout with real-time duration timer
- Add Support & Troubleshooting section to System Information page
- Privacy protection:
- Filter sensitive settings (emails, keys, tokens, URLs, configs)
- Sanitize paths to remove usernames
- Remove hostname from collected data
- Replace IP addresses with [IP] and emails with [EMAIL] in logs
- Add privacy info panel explaining what data is/isn't collected
- Require debug logging to be enabled before downloading support bundle
Enables checking and uploading firmware updates for printers operating
in LAN-only mode without Bambu Cloud connectivity.
Features:
- Automatic firmware version checking against Bambu Lab servers
- Orange "Update" badge on printer cards when updates available
- Firmware update modal with version info and release notes
- One-click firmware upload to printer SD card via FTP
- Real-time upload progress (actual bytes transferred)
- Step-by-step instructions for triggering update from printer
- Local firmware caching for faster re-uploads
- Supports all Bambu Lab printer models
New files:
- backend/app/services/firmware_check.py - Version checking service
- backend/app/services/firmware_update.py - Upload orchestration
- backend/app/api/routes/firmware.py - REST API endpoints
Also includes:
- FTP upload progress callback support
- 10-minute upload timeout protection
- Firmware cache directory in .gitignore