- Add plug_type field to SmartPlug model ("tasmota" or "homeassistant")
- Add ha_entity_id field for Home Assistant entity reference
- Add global HA settings (ha_url, ha_token, ha_enabled) in Settings
- Create homeassistant_service.py with REST API calls for entity control
- Update smart_plug_manager to dispatch to correct service by plug_type
- Add HA entity discovery endpoint (/ha/entities)
- Add HA connection test endpoint (/ha/test-connection)
- Add Home Assistant tab in AddSmartPlugModal with entity dropdown
- Add HA settings section in Settings → Network tab
- Filter already-configured entities from dropdown
- Update backup/restore to include plug_type and ha_entity_id
- Add frontend tests for HA plug rendering
- Add backend integration tests for HA endpoints
- Update README and CHANGELOG
Closes#91
- Add f3d_path field to PrintArchive model and ArchiveResponse schema
- Add API endpoints for F3D upload/download/delete
- Add cyan badge on archive cards when F3D file is attached
- Add context menu options: Upload/Replace F3D, Download F3D, Remove F3D
- Include F3D files in backup/restore
- Add database migration for f3d_path column
- Add API tests for F3D endpoints
- Rebuild CHANGELOG from GitHub releases
Resolves#90
Fixes:
1. frontend/src/pages/SettingsPage.tsx - Added isSavingRef to prevent concurrent saves while a mutation is in progress
2. backend/app/services/mqtt_relay.py - Added 3-second timeout for MQTT connect to prevent blocking on unreachable brokers
0.1.6b8
New Features
MQTT Publishing
Publish BamBuddy events to external MQTT brokers for integration with Home Assistant, Node-RED, and other automation platforms:
- New "Network" tab in Settings for MQTT configuration
- Configure broker, port, credentials, TLS, and topic prefix
- Real-time connection status indicator
- Topics: printer status, print lifecycle, AMS changes, queue events, maintenance alerts, smart plug states, archive events
Virtual Printer Queue Mode
New mode that archives files and adds them directly to the print queue:
- Three modes: Archive (immediate), Review (pending list), Queue (print queue)
- Queue mode creates unassigned items that can be assigned to a printer later
Unassigned Queue Items
Print queue now supports items without an assigned printer:
- "Unassigned" filter option on Queue page
- Unassigned items highlighted in orange
- Assign printer via edit modal
Sidebar Badge Indicators
Visual indicators on sidebar icons:
- Queue icon: yellow badge with pending item count
- Archive icon: blue badge with pending uploads count
- Auto-updates every 5 seconds and on window focus
Project Parts Tracking
Track individual parts/objects separately from print plates:
- "Target Parts" field alongside "Target Plates"
- Separate progress bars for plates vs parts
- Parts count auto-detected from 3MF files
Bug Fixes
- Chamber temp on A1/P1S - Fixed regression where chamber temperature appeared on printers without sensors in multi-printer setups
- Queue prints on A1 - Fixed "MicroSD Card read/write exception error" when starting prints from queue
- Spoolman sync - Fixed Bambu Lab spool detection and AMS tray data persistence
- FTP downloads - Fixed downloads failing for .3mf files without .gcode extension
- Project statistics - Fixed inconsistent display between project list and detail views
- Chamber light state - Fixed WebSocket broadcasts not including light state changes
- Backup/restore - Improved handling of nullable fields and AMS mapping data
---
The REST API endpoint GET /printers/{id}/status was returning raw
temperatures without filtering based on printer model. WebSocket
broadcasts correctly filtered chamber temp via printer_state_to_dict(),
but the REST endpoint built its own response and bypassed this filter.
When users added a second printer, the frontend would fetch initial
status via REST API, causing chamber temp to reappear on printers
that don't have a chamber sensor (A1, A1Mini, P1P, P1S).
Changes:
- Import supports_chamber_temp in printers.py
- Filter chamber/chamber_target/chamber_heating in get_printer_status()
Fixes#82
Queue prints were uploading files to /cache/ directory but the MQTT
print command referenced files by name only (ftp://{filename}), which
resolves to the root directory. The printer couldn't find the file,
causing "MicroSD Card read/write exception error".
Changes:
- Upload queue prints to root / instead of /cache/ (matches reprint)
- Add filename cleaning for .gcode.3mf double extensions
- Pre-delete existing files before upload to avoid FTP 553 errors
- Fix misleading docstring in bambu_mqtt.py
Fixes#86
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
Issue 1: Spool detection only checked tray_uuid/tag_uid, missing spools
that have tray_info_idx (Bambu preset ID like "GFG02") but incomplete
RFID data.
Issue 2: Partial MQTT updates from printer could overwrite complete tray
data, causing loss of tray_sub_brands, tray_id_name, and other fields.
Backend changes (services/spoolman.py):
- Add tray_info_idx to AMSTray dataclass
- Parse tray_info_idx from raw MQTT data
- Check tray_info_idx first in is_bambu_lab_spool() (GF* prefix)
- Fall back to tray_uuid then tag_uid for identification
- Add warning when Bambu spool detected but no unique ID for Spoolman
Backend changes (api/routes/spoolman.py):
- Pass tray_info_idx to is_bambu_lab_spool() in both sync endpoints
- Guard against empty spool_tag when adding to tracking set
Backend changes (services/bambu_mqtt.py):
- Implement deep merge at tray level for AMS MQTT updates
- Preserve existing tray fields unless new update has non-empty value
- Numeric fields (remain, k, id, cali_idx) always update
Frontend changes (pages/PrintersPage.tsx):
- Add isBambuLabSpool() helper with same detection logic as backend
- Check tray_info_idx (GF*), tray_uuid, and tag_uid
- Update all 4 vendor detection locations in AMS cards
The spool detection only checked tray_uuid and tag_uid, but some Bambu Lab
spools have RFID read issues causing these to be missing while still having
valid tray_info_idx (Bambu filament preset ID like "GFA00").
Backend changes (backend/app/services/spoolman.py):
- Add tray_info_idx to AMSTray dataclass
- Parse tray_info_idx from raw MQTT data in parse_ams_tray()
- Check tray_info_idx first in is_bambu_lab_spool() - most reliable indicator
- Bambu Lab presets start with "GF" (GFA00, GFB00, GFL00, etc.)
- Fall back to tray_uuid then tag_uid for unique spool identification
- Add warning when Bambu spool detected but no unique ID for Spoolman
Backend changes (backend/app/api/routes/spoolman.py):
- Update /sync/{printer_id} and /sync-all to pass tray_info_idx
- Guard against empty spool_tag when adding to tracking set
Frontend changes (frontend/src/pages/PrintersPage.tsx):
- Add isBambuLabSpool() helper with same detection logic as backend
- Update all 4 vendor detection locations in AMS cards to use new helper
Detection priority (same on frontend and backend):
1. tray_info_idx starts with "GF" (Bambu preset ID)
2. tray_uuid is valid 32-char hex (non-zero)
3. tag_uid is valid 16-char hex (non-zero)
The spool detection logic only checked tray_uuid (32 hex chars) to identify
Bambu Lab spools. Some spools have RFID read issues causing missing or
invalid tray_uuid while still having valid tag_uid (16 hex chars).
Changes:
- Update is_bambu_lab_spool() to accept tag_uid as fallback parameter
- Prefer tray_uuid for identification, fall back to tag_uid if invalid
- Use whichever valid identifier for Spoolman tag storage and matching
- Update both /sync/{printer_id} and /sync-all endpoints
This fixes spools being incorrectly marked as "Non-Bambu Lab spool (no RFID
tag)" when they have valid tag_uid but missing/zero tray_uuid.
Backend:
- Count print job records instead of summing quantities for stats
- Include "archived" status as successful (completed + archived)
- Include all failure states (failed, aborted, cancelled, stopped)
- Add completed_count and failed_count to ProjectListResponse
Frontend ProjectsPage:
- Show completed_count instead of total_items in progress displays
- Progress bar now shows "X / Y completed" to match percentage
- Add failed count indicator (red) when failures exist
- Footer stats show completed (green checkmark) and failed (red) separately
Frontend ProjectDetailPage:
- Replace confusing "Total Items" card with "Print Jobs" card
- Show "X successful" as main value, "Y failed" below in red
- Show "Z in progress" in yellow for unfinished prints
- Progress bar text changed from "items" to "completed"
- Add hint prop to StatCard component for tooltips
This ensures stats are consistent between:
- Project list page and detail page
- Stats cards and archive list counts
- Progress percentages and displayed fractions
Fixes#85
The cover and objects endpoints only tried downloading files with the
.gcode.3mf extension pattern, but files uploaded directly (not sliced
via Bambu Studio) are stored as plain .3mf files.
This caused FTP error 550 (file not found) when trying to display cover
images for prints started from BamBuddy archive.
Now tries both naming patterns:
- {name}.gcode.3mf (sliced via Bambu Studio)
- {name}.3mf (uploaded directly)
Fixes#79
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.
v0.1.6b7
## AMS Color Mapping (#76)
- Manual AMS slot selection in ReprintModal, AddToQueueModal, EditQueueItemModal
- Dropdown to override auto-matched AMS slots with any loaded filament
- Blue ring indicator distinguishes manual selections from auto-matches
- Status indicators: green (match), yellow (type only), orange (not found)
- Shared color utility (utils/colors.ts) with ~200 Bambu color mappings
- Widened modals (max-w-md → max-w-lg) to fit long color names
- Fixed 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
- Resolves "stuck at filament change" on multi-color reprints
## Print Options in Reprint Modal
- Bed leveling, flow calibration, vibration calibration toggles
- First layer inspection, timelapse toggles
- Collapsible "Print Options" section
- Fixed print command format for proper printer recognition
## Time Format Setting (#75)
- New date utilities (utils/date.ts): parseUTCDate, formatDate, formatDateTime
- Applied to 12 components: PrintersPage, ArchivesPage, QueuePage,
ProjectDetailPage, SystemInfoPage, AMSHistoryModal, NotificationLogViewer,
CalendarView, FilamentTrends, PrinterQueueWidget, ProfilesPage
- Fixes archive times showing in UTC instead of local timezone
## Statistics Dashboard (#72)
- Size-aware rendering passes widget size (1/4, 1/2, full) to components
- PrintCalendar: Dynamic cell sizing via ResizeObserver, 3/6/12 months
- 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
## Firmware Update Helper
- Check firmware versions against Bambu Lab servers for LAN-only printers
- Orange "Update" badge on printer cards when updates available
- Firmware modal with version info, release notes, upload progress
- One-click upload to printer SD card via FTP with progress callback
- Local firmware caching for faster re-uploads
- New services: firmware_check.py, firmware_update.py
- New routes: /api/v1/firmware/*
## FTP Reliability
- Configurable retry (1-10 attempts, 1-30s delay) in Settings > General
- Applies to: 3MF archiving, print uploads, timelapse downloads,
reprint uploads, firmware updates
- A1/A1 Mini SSL fix: skip SSL on data channel entirely (control encrypted)
- X1C/P1S: SSL with session reuse on data channel (required by vsFTPd)
- Configurable FTP timeout (10-120s, default 30s) for slow WiFi
## Bulk Operations
- Bulk project assignment from multi-select toolbar (#70)
- BatchProjectModal for assigning archives to projects
- "Remove from project" option for bulk clearing
## Chamber Light Control (#67)
- Light toggle button on printer cards (next to camera)
- Custom ChamberLight SVG icon with on/off states
- Backend: POST /printers/{id}/chamber-light?on=true|false
- H2D dual chamber lights controlled together
## Support Bundle Feature
- Debug logging toggle with real-time duration timer in Layout
- /api/v1/support/bundle generates ZIP with system info and logs
- Privacy protection: filters secrets, sanitizes paths, removes IPs/emails
- Requires debug logging enabled before download
## Archive Improvements
- List view: edit/delete buttons and context menu with full parity
- Object count display on cards (extracted from 3MF metadata)
- Cross-view highlighting: click calendar/project to highlight in cards
- Context menu button (⋮) on cards and list rows
## Maintenance Improvements (#59)
- wiki_url field for custom type documentation links
- Model-specific Bambu Lab wiki URLs for system types
- External link icon next to maintenance item names
- Fix: deleted printer now removed from maintenance
## Spoolman Integration
- Clear location when spools removed from AMS during sync
- find_spools_by_location_prefix() to find spools at a printer
- clear_location_for_removed_spools() clears stale locations
## Bug Fixes
- Browser freeze from CameraPage WebSocket (removed duplicate connection)
- Project card filament badges showing duplicates and raw color codes
- Print object label positioning in skip objects modal
- Printer hour counter not updated on backend restart
- Virtual printer excluded from discovery
- Print cover fetch in Docker environments
- Critical: Archive delete safety checks prevent deleting parent dirs
- 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
- Test 1: Build production image, verify imports & static files
- Test 2: Backend unit tests in Docker container
- Test 3: Frontend unit tests in Docker container
- Test 4: Integration tests (health, API, static files)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Match test_docker.sh workflow:
- Build Docker image
- Verify backend imports
- Verify static files exist
- Test health endpoint
- Test API endpoint
- Test static files served
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
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>
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>