CSS invert() filter was applied to all custom uploaded icons in dark
mode, causing full-color logos to render with wrong colors. Removed
the invert filter from custom icon <img> tags in Layout.tsx and
AddExternalLinkModal.tsx. Preset Lucide icons are unaffected.
The Add Printer dialog previously required users to manually enter their
network subnet for scanning (defaulting to 192.168.1.0/24). Now the
backend detects available network interfaces and returns their subnets
via the /discovery/info endpoint. The frontend auto-selects the first
detected subnet and shows a dropdown when multiple subnets are available,
falling back to a text input if none are detected.
Restructured ja.ts from a divergent format (different nesting, 12
structural conflicts, 48 namespaces) to match EN/DE structure exactly
(41 namespaces, 0 conflicts). Translated all 2,083 EN keys into
Japanese — previously 1,366 keys were missing and silently falling
back to English via i18next fallbackLng.
AMS Lite units (A1 series) have no weight sensor and always report 0%
fill level. When a spool is linked to Spoolman with weight data, use
Spoolman's remaining weight as a fallback. External spools also show
fill level from Spoolman data instead of always showing unknown.
Backend: Enrich GET /spoolman/spools/linked response with
remaining_weight and filament_weight alongside spool ID.
Frontend: Add getSpoolmanFillLevel() helper. Update regular AMS, HT
AMS, and external spool fill computations to use Spoolman fallback
when AMS reports 0%. Show "(Spoolman)" indicator in hover card when
fill data comes from Spoolman.
- Add translation keys for environment-managed labels
- Replace hardcoded English text with i18n function calls
- Add translations for English, German, and Japanese
- Keys: environmentManagedLabel, autoEnabledViaEnv, urlFromEnvReadOnly, tokenFromEnvReadOnly
Addresses PR feedback on #283
- Add HA_URL and HA_TOKEN environment variables for automatic HA
integration configuration in HA add-on deployments
- Environment variables always override database settings with
non-negotiable precedence; database values preserved for fallback
- Auto-enable integration when both env vars are set; partial config
(one env var) uses database enable state without auto-enabling
- Add centralized get_homeassistant_settings() function following
Spoolman pattern; replace direct database queries across codebase
- Add ha_url_from_env, ha_token_from_env, ha_env_managed fields to
AppSettings schema to inform frontend about configuration source
- UI shows read-only fields with lock icons and "(Environment Managed)"
labels when env-controlled; toggle shows auto-enable badge
- Add comprehensive test coverage: 9 integration + 8 unit tests
Closes#283
- 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
Users with local DNS can now add printers using hostnames like
printer.local or my-printer.home.lan. Updated backend schema
validation, database column width, frontend form patterns/placeholders,
and i18n labels across all locales. Added integration tests for
hostname and FQDN creation plus invalid hostname rejection.
filament_used_grams already represents the total for the entire print
job. The daily, weekly, and filament-type charts were multiplying it
by quantity, e.g. a 26-object print using 126g was counted as 3,276g.
Removed the erroneous `* qty` from three aggregations in
FilamentTrends.tsx. Monthly comparison and summary cards were already
correct.
Fixes#229
Simplify always-true authEnabled ternary and localSettings truthiness
checks in SettingsPage.tsx. Remove commented-out auth re-setup guard
and its dead _existing_setting/_user_count queries from auth.py.
Add clarifying comments to firmware_check.py api_key logs (model
identifier, not a secret).
Remove vestigial _debug_logging_enabled and _debug_logging_enabled_at
globals from support.py (written but never read; DB is queried directly).
Simplify hue classification in PrintersPage.tsx and colors.ts by removing
always-true h < 345 checks and dead 'Unknown' fallbacks. Narrow
getWifiStrength param type to remove always-false null guard.
- Replace number inputs with select dropdowns for retry attempts,
retry delay, and connection timeout to avoid auto-save race conditions
- Move connection timeout inside the FTP retry toggle section
- Add ftp_timeout to backend settings schema and integer parsing list
so the value actually persists (was silently dropped before)
Closes#275
Implement accurate per-filament usage tracking for Spoolman integration,
similar to OpenSpoolman v0.3.0. This replaces the previous single-spool
reporting with multi-material aware tracking.
Features:
- Parse G-code from 3MF files at print start to build per-layer,
per-filament cumulative extrusion maps
- Store tracking data in new `active_print_spoolman` database table
(survives server restarts for long prints)
- Report accurate partial usage when prints fail/cancel based on
actual layer progress and G-code data
- Add "Disable AMS Weight Sync" setting to prevent AMS percentage-based
weight estimates from overwriting Spoolman's granular tracking
- Add "Report Partial Usage for Failed Prints" toggle (only shown when
weight sync is disabled)
- Use Spoolman's filament density instead of defaults for mm-to-grams
conversion
- Prefer tray_uuid over tag_uid for spool identification
Camera streams on macOS Safari were failing with "FetchEvent.respondWith
received an error: Load failed" because the Service Worker was intercepting
MJPEG streaming responses. Safari has known issues handling continuous
streaming responses through Service Workers.
- Add exclusion for /camera/stream and /camera/snapshot URLs in SW fetch handler
- Bump cache version to v24 to force SW update on clients
The camera components already have robust error handling with reconnect logic,
so bypassing the SW for these endpoints is safe and improves performance.
The plate detection alert popup (shown when objects are detected on
build plate and print is paused) was visible to all users. Now it
only shows to users who have the printers:control permission.
- Added hasPermission('printers:control') check before showing alert
- When auth disabled: all users see it (backward compatible)
- When auth enabled: only users with printers:control permission see it
Addresses #244
Date input for scheduled prints was swapping month and day for European
users because:
1. EU format only accepted "/" separator, not "." which is common in
European locales (e.g., "5.2.2026" for Feb 5th)
2. System format fell back to new Date() which interprets ambiguous
dates in US format
Changes:
- Added splitDateParts() helper to accept /, ., and - separators
- Updated parseDateInput() to use proper locale detection for system
format instead of relying on Date constructor
- All explicit formats (us, eu, iso) now accept any of the three
separators
Closes#233
The FilamentHoverCard positioning logic now accounts for the fixed 56px
header when calculating available space above the trigger element.
Previously, when hovering over AMS slots near the top of the page, the
hover card would appear above the slot but go behind the navigation bar.
Now it correctly detects there isn't enough usable space and flips to
show below the slot instead.
Closes#259
- 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
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
- 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
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
Header action buttons were overflowing outside the screen on iPhone/mobile
devices because the header containers used fixed horizontal layouts.
Changed both pages to use the responsive pattern from PrintersPage:
- Headers stack vertically on mobile (flex-col), horizontal on sm+ (sm:flex-row)
- Button containers use flex-wrap to allow wrapping on narrow screens
- Added gap-4 between title and buttons when stacked
Closes#255
When editing a queue item, the scheduled time was being displayed in UTC
instead of the user's local timezone. This caused confusion where:
- User selects April 2, 2:00 PM local time
- After saving, it appears shifted by their timezone offset
- Month/day could appear swapped due to the timezone difference
The fix converts the UTC time from the server to local time when
populating the datetime-local input, using toDateTimeLocalValue()
instead of toISOString().slice(0, 16).
Closes#233
The queue was showing "Printing" even when the printer was paused.
Now fetches real-time printer state for active print jobs and displays
"Paused" with a yellow badge when the printer state is PAUSE/PAUSED.
Changes:
- Add printerState prop to StatusBadge and SortableQueueItem components
- Fetch printer statuses for printers with active jobs using useQueries
- Show pause icon and yellow badge when printing but printer is paused
- Add "paused" translation key for queue status (en, de, ja)
Closes#249
The filament_used_grams field already contains the total filament for
the entire print job (all items combined). The code was incorrectly
multiplying this value by quantity, causing inflated filament totals.
Example: A print with 26 objects using 126g total was being calculated
as 126g * 26 = 3,276g instead of the correct 126g.
Fixes:
- backend/app/api/routes/archives.py: Archive stats endpoint
- backend/app/api/routes/metrics.py: Prometheus metrics endpoint
- frontend/src/components/FilamentTrends.tsx: Trends chart calculations
Closes#229
- Added query to fetch library file details in PrintModal
- Updated backend FileResponse schema to include metadata fields (print_name, print_time_seconds, filament_used_grams, sliced_for_model)
- Updated backend get_file endpoint to extract and return metadata fields
- Updated frontend LibraryFile interface to include metadata fields
- Now slicedForModel is properly extracted from both archives and library files
Co-authored-by: cadtoolbox <12723486+cadtoolbox@users.noreply.github.com>