- H2D sends timelapse status in ipcam.timelapse field, not xcam.timelapse
- Added parsing for timelapse from ipcam data
- Added test to prevent regression
2. Systemd service updated - /etc/systemd/system/bambuddy.service
- Now runs as claude user instead of root
- Added ExecStartPre commands with + prefix (runs as root) to:
- Create logs and archive directories if missing
- Fix ownership to claude:claude before service starts
The service restarted successfully with the permission fixes running at startup. On the next print with timelapse enabled, both the snapshot and timelapse should be captured automatically.
1. bambu_mqtt.py: Added hms_errors to the completion callback data, which includes the HMS error codes when a print fails
2. archive.py: Updated update_archive_status() to accept an optional failure_reason parameter
3. main.py: Added auto-detection of failure reasons:
- status == "aborted" → failure_reason = "User cancelled"
- status == "failed" with HMS errors → maps module codes to reasons:
- Module 0x07 (Filament) → "Filament runout"
- Module 0x0C (Motion Controller) → "Layer shift"
- Module 0x05 (Nozzle) → "Clogged nozzle"
Frontend changes:
1. ArchivesPage.tsx:
- Badge now shows "cancelled" for aborted prints, "failed" for failed prints
- "Failed Prints" collection and "Hide Failed" filter now include both failed and aborted statuses
2. EditArchiveModal.tsx: Failure reason field now shows for both failed and aborted prints
New tests added:
- test_hms_errors_included_in_failed_completion_callback
- test_aborted_status_when_cancelled
The HMS error module mapping is basic and can be expanded as you observe more failure types. The actual Bambu HMS error codes are documented in their wiki - we can add
more mappings as needed.
- frontend/src/components/TimelapseViewer.tsx:17 - Changed from 0.5 to 2
2. Archive page: hide failed prints filter with persistence
- Added hideFailed state initialized from localStorage.getItem('archiveHideFailed')
- Added localStorage persistence via useEffect
- Added "Hide Failed" toggle button (red styling when active) next to the Favorites button
- Filter is automatically bypassed when viewing the "Failed Prints" collection
- "Reset" button also clears this filter
The filter state persists across page refreshes and browser sessions via localStorage.
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
Changes to ToastContext.tsx:
- Added 'loading' toast type with a spinning Loader2 icon
- Added showPersistentToast(id, message, type) function for toasts that don't auto-dismiss
- Exposed dismissToast(id) function to allow programmatic dismissal
- Added green-themed styling for loading toasts
Changes to SettingsPage.tsx:
- When exporting a backup that includes archives, shows a persistent "Preparing backup..." toast with spinner
- The toast is automatically dismissed when the download starts or if an error occurs
- For non-archive backups (which are fast), no loading toast is shown
The user will now see clear feedback when creating a backup with print archives - a toast with a spinner appears immediately after clicking export and stays visible
until the download dialog appears.
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
Problem: At print start, the MQTT mc_remaining_time was often 0 or unavailable because the printer hadn't fully processed the gcode yet.
Solution: Modified the notification system to prioritize the print_time_seconds from the 3MF file parsing (which is always available after archive creation) over the
MQTT remaining time.
Files changed:
- backend/app/services/notification_service.py:
- Added optional archive_data parameter to on_print_start() method
- Added priority logic: archive data > MQTT remaining_time > raw_data mc_remaining_time
- backend/app/main.py:
- Created _send_print_start_notification() helper function
- Moved notification sending to AFTER archive creation (when print_time_seconds is available)
- Added fallback notification sending at early return points (auto_archive disabled, file not found, etc.)
Issue 2: Timelapse Auto-Assignment
Problem: Timelapses couldn't be auto-assigned reliably because printer dates could be off in LAN-only mode, making timestamp matching unreliable.
Solution: Track whether timelapse recording was active during the print via MQTT, and if so, auto-fetch the most recent timelapse file on print completion.
Files changed:
- backend/app/services/bambu_mqtt.py:
- Added _timelapse_during_print instance variable
- Track when timelapse is active during a print (in both data and xcam parsing)
- Reset the flag on new print start
- Include timelapse_was_active in the print complete callback data
- backend/app/main.py:
- Added timelapse auto-scan logic in on_print_complete()
- If timelapse_was_active is True and status is "completed":
- Wait 5 seconds for timelapse to finalize
- Scan printer's timelapse directory
- Find most recent file by mtime
- Verify it was modified within 30 minutes of print completion
- Download and attach to archive
- Send WebSocket update
- Header navigation link
- Installation guide link
- Documentation section with all 5 doc links
- Footer documentation link
2. Screenshots updated with new images:
- Replaced old maintenance screenshots with maintenance-1.png and maintenance-2.png
- Replaced old profile screenshots with cloud_profiles-1.png, cloud_profiles-2.png, k_profiles-1.png, k_profiles-2.png
- Replaced old settings screenshots with settings_general.png, settings_smart_plugs.png, settings_notifications.png, settings_api_keys.png
- Removed old unused screenshot files from docs/screenshots/
- Separate AMS and AMS-HT notification switches (one per device type)
- Fix notification variables not showing (duration, filament, estimated_time)
- Add fallback values for empty notification variables ("Unknown" instead of blank)
Settings:
- Fix API keys badge count only showing after visiting tab
- Move External Links card to third column above Updates
- Add Release Notes modal for viewing full notes before updating
Statistics:
- Fix filament usage trends not showing (wrong API parameters)
- Move dashboard controls (Hidden, Reset Layout) to header row
- Remove duplicate Reset Layout button
Camera:
- Fix ffmpeg processes not killed when closing webcam window
- Add /camera/stop endpoint with POST support for sendBeacon
- Track active streams and proper cleanup on disconnect
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
- Add database model for storing AMS sensor history (humidity, temperature)
- Record sensor data every 5 minutes via background task
- Add API endpoint to retrieve history with min/max/avg statistics
- Create AMSHistoryModal component with Recharts line charts
- Make humidity/temperature indicators clickable to open history
- Support time range selection (6h, 24h, 48h, 7d)
- Show threshold reference lines on charts (Good/Fair levels)
- Add configurable data retention (default 30 days) in Settings
- Auto-cleanup old data daily
- Fix dark theme styling in modal using inline styles
- Add Escape key to close modal
### Projects / Print Grouping
- Create projects to group related prints (e.g., "Voron Build" with 50 parts)
- Track progress with target count and completion percentage
- Assign archives to projects via edit modal or context menu
- Project cards show archive thumbnails with clickable links
- Color-coded project badges on archive cards
- Filter and manage projects by status (active/completed/archived)
### Full-Text Search (FTS5)
- SQLite FTS5 virtual table for efficient searching
- Search across print_name, filename, tags, notes, designer, filament_type
- Automatic index sync with triggers for INSERT/UPDATE/DELETE
### Webhooks & API Keys
- API key authentication with granular permissions
- Permissions: can_read_status, can_manage_queue, can_control_printer
- Secure key generation with prefix display only after creation
- Settings page API Keys tab for key management
- Webhook endpoints for external integrations
### Failure Analysis
- Dashboard widget showing failure rate with color coding
- Correlate failures with conditions (filament type, printer, time)
- Top failure reasons breakdown
- Weekly trend visualization
### Archive Comparison
- Select 2-5 archives to compare side-by-side
- Highlight differences in print settings (yellow)
- Success/failure correlation insights
- Modal with close via button, X, Escape, or backdrop
### CSV/Excel Export
- Export archives and statistics with current filters
- Support for both CSV and Excel (.xlsx) formats
- openpyxl dependency added
## Bug Fixes
- Fixed context menu submenu not showing (removed overflow-hidden)
- Fixed project card thumbnails using correct API endpoint
- Fixed EditArchiveModal to invalidate projects query on save
- Fixed clipboard API fallback for HTTP contexts
- Fixed archive PATCH 500 error (FTS5 index rebuild)
- Fixed FastAPI trailing slash routing for projects endpoint
## UI Improvements
- Context menu submenu with hover/click support
- Project badge on archive cards with project color
- "Go to Project" context menu item for assigned archives
- Clickable project card thumbnails linking to archives
- Reset Layout button moved to Stats page header