Commit Graph
45 Commits
Author SHA1 Message Date
maziggy 39f90616f3 Post work #2 PR #262 2026-02-04 16:12:57 +01:00
maziggy 3571cd1a42 Fix AMS auto-matching when multiple trays have same tray_info_idx
The tray_info_idx field is a filament TYPE identifier (e.g., "GFA00" for
generic PLA), not unique per spool. When multiple AMS trays are loaded
with the same filament type, the previous code used find() which always
returned the first match regardless of color.

Now checks if tray_info_idx is unique among available trays:
- If unique: use that tray as definitive match (existing behavior)
- If not unique: fall back to color matching among matching trays

Fixed in both backend (print_scheduler.py) and frontend (useFilamentMapping.ts).

Closes #245
2026-02-04 14:03:50 +01:00
maziggy 81d18cb8bd Virtual Printer Proxy Mode Improvements
- 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
2026-02-04 12:29:20 +01:00
maziggy fe17a6905f Fix AMS auto-matching to use tray_info_idx from 3MF files
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
2026-02-04 08:18:05 +01:00
maziggy 583c374f01 Add Virtual Printer Proxy Mode for remote printing
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
2026-02-03 11:02:13 +01:00
maziggy ea93535bfc Add TOTP authenticator support for Bambu Cloud login (fixes #182)
TOTP (Two-Factor Authentication):
- Detect TOTP vs email verification from Bambu API loginType response
- Use dedicated TFA endpoint on bambulab.com (not api.bambulab.com)
- Include browser-like headers to bypass Cloudflare protection
- Extract token from JSON response or cookies
- Frontend shows appropriate messages for each verification type
- Added i18n translations for TOTP UI (en, de, ja)

Closes #182
2026-02-03 07:18:13 +01:00
maziggy 81cc8412ac Add user tracking for prints, archives, library files, and queue (Issue #206)
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
2026-02-01 10:26:11 +01:00
MartinNYHC be7b3f99a2 Merge branch '0.1.6-final' into feature/192 2026-01-31 15:36:17 +01:00
maziggy 42a14f024d Fix AMS mapping for model-based queue jobs (Issue #192)
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
2026-01-31 08:39:21 +01:00
MisterBeardy c291e3a0a8 feat: Add STL thumbnail generation functionality
- 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.
2026-01-30 09:37:30 -05:00
MartinNYHC 221f9ffcc3 Revert "Feature/stl thumbnail" 2026-01-29 15:52:46 +01:00
MartinNYHC c4b3b69914 Merge branch '0.1.6-final' into feature/stl-thumbnail 2026-01-29 15:49:27 +01:00
MisterBeardyandClaude Opus 4.5 375d5238d0 Add STL thumbnail generation support
- 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>
2026-01-29 15:06:01 +01:00
maziggy c123fa08c0 Fix A1/A1 Mini showing Printing instead of Idle (Issue #168)
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
2026-01-29 07:23:53 +01:00
maziggy b9495877fc Add HMS error notifications with translations and plate detection fixes
New Features:
- HMS error notifications with human-readable messages (853 error codes)
- Plate not empty notification category (separate toggle in settings)
- Module-friendly names: Print/Task, AMS/Filament, Nozzle/Extruder, etc.
- Backup/restore now includes plate calibration reference images

Fixes:
- Plate calibration images now persist after restart in Docker
- Telegram notifications no longer fail on error codes with underscores
- Plate detection combo button: main toggles detection, chevron opens modal

Tests:
- Added HMS error code tests (10 tests)
- Implemented Dashboard, FileManagerModal, UploadModal tests (previously skipped)
- Added notification service tests for HMS errors and plate detection
- Fixed AuthContext unmount memory leak in tests
2026-01-27 08:48:57 +01:00
maziggy 9d6164ab1c Add USB camera support (V4L2)
- 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
2026-01-27 06:40:14 +01:00
maziggy 888891fdc6 Add build plate empty detection feature
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
2026-01-26 13:04:29 +01:00
maziggy bb7e8398bc Completely removed telemetry 2026-01-26 09:34:04 +01:00
maziggy 4266049e0c Fix empty AMS slot not recognized (Issue #147)
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
2026-01-25 07:07:36 +01:00
maziggy 691fb133b7 Add external network camera support for printers
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
2026-01-24 09:58:45 +01:00
maziggy 5672d7965a Add recalculate costs button and reprint cost tracking
- 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
2026-01-24 07:05:15 +01:00
maziggy 6c5aad1b73 Fix: Mattermost/Slack Webhook Support
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
2026-01-23 07:13:46 +01:00
maziggy 08e4797544 Fix: Internal Model Code Detection for Camera Protocol
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
2026-01-23 07:09:22 +01:00
maziggy 0354218657 Add finish photo URL to notification templates (Issue #126)
- 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
2026-01-22 10:42:20 +01:00
maziggy 494da46b09 **Configure AMS Slot**
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
2026-01-20 11:57:09 +01:00
maziggy af0dad11ec Add multi-plate 3MF plate selection for reprinting (Issue #93)
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
2026-01-19 13:29:37 +01:00
maziggy 3a2ec8056c Fix multi-plate 3MF metadata extraction (Issue #92)
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
2026-01-19 13:29:37 +01:00
maziggy 693466eafc Add project parts tracking separate from plates
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
2026-01-16 07:33:44 +01:00
maziggy b39aa492cd - Fixed chamber temperature badge on printer card for printers without chammber temperature sensor
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.
2026-01-12 15:15:53 +01:00
maziggyandClaude Opus 4.5 d1d4152551 Fix backend code formatting for CI
- Update ruff pre-commit hook to v0.14.11
- Apply ruff format to pass CI checks

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-11 07:30:22 +01:00
maziggy d8cecb0695 Add FTP retry for unreliable WiFi connections
Added configurable retry logic for all FTP operations to handle
  unreliable WiFi on P1S, X1C, and other Bambu Lab printers.

  Features:
  - Enable/disable retry in Settings > General > FTP Retry
  - Configurable retry count (1-10 attempts, default: 3)
  - Configurable retry delay (1-30 seconds, default: 2s)
  - Applies to: 3MF archiving, print uploads, timelapse downloads,
    reprint uploads, and firmware updates
2026-01-09 08:52:45 +01:00
maziggy d241c5e4db Fixed backend tests for virtual printer 2026-01-04 15:17:34 +01:00
maziggy bb37a8c8a8 Fix virtual printer model codes and serial prefixes
- 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
2026-01-04 14:05:08 +01:00
maziggy 81c8dd7d0c Add virtual printer model selection
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
2026-01-04 09:39:06 +01:00
maziggy 83cbac04b7 - Add interactive API Browser to Settings > API Keys
- 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+)
2026-01-02 15:00:21 +01:00
maziggy 88e84ca45a - Add Virtual Printer feature - emulate Bambu printer on network
- 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)
2025-12-29 15:52:48 +01:00
maziggy e9193276a6 Summary of Fixes
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.
2025-12-27 15:53:37 +01:00
maziggy a66500b605 Fixed bug in mock_state 2025-12-27 15:46:13 +01:00
maziggy 88bd020dc9 Improved Docker support; Added Docker test suite 2025-12-14 10:16:33 +01:00
maziggy c317ff1085 1. Pre-commit Hook Configuration (.pre-commit-config.yaml)
- Ruff linter and formatter - Fast Python linter with auto-fix
  - Standard hooks - trailing whitespace, end-of-file, YAML/JSON checks, large file detection, merge conflict detection, debug statements, private key detection
  - Custom hook - Runs import shadowing tests before commit

  2. Ruff Configuration (pyproject.toml)

  - Python 3.11+ target
  - 120 character line length
  - Checks: pycodestyle, Pyflakes, isort, flake8-bugbear, comprehensions, pyupgrade, unused arguments, simplify
  - Sensible ignores for FastAPI patterns (Depends, unused route args)

  3. New Test Files

  backend/tests/unit/test_code_quality.py (5 tests)
  - Import shadowing detection using AST analysis
  - Catches the exact bug that broke archive creation
  - Tests all Python files in main, services, and routes

  backend/tests/unit/test_log_error_detection.py (13 tests)
  - MQTT message processing (status, xcam, AMS, HMS)
  - Print lifecycle (start to complete, failure handling)
  - Service imports verification
  - Edge cases (empty messages, unknown fields, null values)

  backend/tests/integration/test_print_lifecycle.py (6 tests)
  - Print start callback logic
  - Print complete callback logic
  - Timelapse tracking (same-message detection, completion callback)
  - Callback error handling
  - Import shadowing verification
2025-12-13 09:57:04 +01:00
maziggy ae55884858 1. ArchiveService import shadowing bug (main.py:978) - Local import was shadowing module-level import, causing "cannot access local variable" error
2. Timelapse race condition (bambu_mqtt.py) - xcam data was parsed before _was_running was set, so timelapse wasn't detected at print start
  3. Added exception handling (printer_manager.py) - _schedule_async now logs exceptions instead of swallowing them silently
  4. Added debug logging (main.py) - [CALLBACK] logs at key decision points to help debug future issues
  5. Added code quality tests (test_code_quality.py) - Static analysis to catch import shadowing bugs automatically
2025-12-13 09:39:14 +01:00
maziggy 3fe49f6af5 1. Timelapse Race Condition Fix (bambu_mqtt.py)
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
2025-12-13 09:16:58 +01:00
maziggy a14dcbc034 Frontend WebSocket Tests Summary
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
2025-12-12 15:52:35 +01:00
maziggy f7cde95bbb Tests Added Summary:
Backend Tests (New Files)

  1. backend/tests/integration/test_camera_api.py - 13 tests
    - Camera stop endpoint (GET and POST methods)
    - Active stream termination
    - Printer-specific stream stopping
    - Camera test endpoint
    - Camera snapshot endpoint
    - Camera stream validation
  2. backend/tests/integration/test_system_api.py - 16 tests
    - System info endpoint structure
    - App, database, storage, memory, CPU sections
    - Helper functions (format_bytes, format_uptime)
    - Archive statistics
    - Printer connection info
  3. backend/tests/unit/services/test_telemetry.py - 16 tests
    - Installation ID creation/retrieval
    - Telemetry enabled/disabled checks
    - Telemetry URL configuration
    - Heartbeat sending and rate limiting
    - Exception handling
  4. backend/tests/unit/services/test_notification_service.py (updated) - Added TestNotificationVariableFallbacks class with 9 tests
    - Duration formatting with None values
    - Print complete fallback values
    - Estimated time and remaining time fallbacks
    - Filename fallback to "Unknown"

  Frontend Tests (New Files)

  5. frontend/src/__tests__/pages/SystemInfoPage.test.tsx - 14 tests
    - Loading and error states
    - Application, database, storage, memory, CPU sections
    - Connected printers display
    - Disk usage warning/danger colors
    - Refresh button
  6. frontend/src/__tests__/components/AMSHistoryModal.test.tsx - 21 tests
    - Modal open/close behavior
    - Humidity/temperature mode switching
    - Time range selection
    - Statistics cards (current, avg, min, max)
    - Loading and error states
    - Trend calculation
  7. frontend/src/__tests__/components/NotificationProviderCard.test.tsx (updated) - Added NotificationProviderCard AMS toggles describe block with 11 tests
    - AMS humidity/temperature notification toggles
    - AMS-HT humidity/temperature notification toggles
    - Independence of AMS and AMS-HT toggles
    - Default values

  Total New Tests: ~100 tests covering:
  - Camera API endpoints
  - System info API
  - Anonymous telemetry service
  - Notification variable fallbacks
  - System Info page UI
  - AMS History modal UI
  - AMS/AMS-HT notification toggle settings

  Tests Added - Complete Summary:

  Backend Tests (4 new files, 1 updated)

  | File                                                       | Tests | Description                                                     |
  |------------------------------------------------------------|-------|-----------------------------------------------------------------|
  | tests/integration/test_camera_api.py                       | 13    | Camera stop (GET/POST), snapshot, stream, test endpoints        |
  | tests/integration/test_system_api.py                       | 16    | System info API, helper functions (format_bytes, format_uptime) |
  | tests/unit/services/test_telemetry.py                      | 16    | Installation ID, telemetry toggle, heartbeat sending            |
  | tests/unit/services/test_notification_service.py (updated) | +10   | Variable fallbacks for duration, filename, estimated_time       |

  Frontend Tests (2 new files, 1 updated)

  | File                                                                 | Tests | Description                                           |
  |----------------------------------------------------------------------|-------|-------------------------------------------------------|
  | src/__tests__/pages/SystemInfoPage.test.tsx                          | 14    | System info page UI, sections, loading/error states   |
  | src/__tests__/components/AMSHistoryModal.test.tsx                    | 21    | AMS history modal, mode switching, time ranges, stats |
  | src/__tests__/components/NotificationProviderCard.test.tsx (updated) | +11   | AMS/AMS-HT notification toggle independence           |

  Total: 101 new tests
  - Backend: 335 tests total (all passing)
  - Frontend: 124 tests total (all passing)
2025-12-12 11:15:59 +01:00
maziggy ff53e62ef8 Add comprehensive automated testing infrastructure
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
2025-12-11 10:03:40 +01:00