392 Commits
Author SHA1 Message Date
maziggy 9ee4bd51e4 Sync 2026-02-28 14:59:04 +01:00
maziggy 90b9523998 Updated commit message (now includes the test fix):
Fix camera button permissions & ffmpeg process leak (#550)

  Camera button on printer card was clickable without camera:view
  permission. ffmpeg processes (~240MB each) accumulated after closing
  camera streams because: (1) stop endpoint called terminate() without
  wait()/kill(), (2) HTTP disconnect detection only ran between frames
  so was blocked when the generator was stuck on stdout read, and
  (3) no mechanism caught processes orphaned by generator abandonment
  or app restarts.

  - Add camera:view permission check + tooltip to camera button
  - Fix stop endpoint: terminate() → wait(2s) → kill() → wait()
  - Add background disconnect monitor (polls every 2s, kills ffmpeg
    directly on disconnect)
  - Add periodic /proc scan (every 60s) that SIGKILLs any ffmpeg
    with rtsps://bblp: not in an active stream
  - Add noCamera i18n key to all 6 locales
  - Fix camera API test mocks for async wait() and pid attribute
2026-02-28 14:38:45 +01:00
maziggy 240eeb4f5d Add H2C dual nozzle variant O1C2 model support (#489)
The H2C dual nozzle variant reports model code O1C2 via MQTT, but only
  O1C was recognized. This caused the camera to use the wrong protocol
  (chamber image on port 6000 instead of RTSP on port 322), producing a
  reconnect loop. Added O1C2 to all model ID maps across 8 files.
2026-02-28 14:38:11 +01:00
maziggy d3bae07edf Fix queue badge showing on printers without matching filament (#486)
The purple queue counter badge in the printer card header used the raw
unfiltered queue item count, so it appeared on ALL printers of the same
model when a job was scheduled for "any [model]" — even printers without
the matching filament color. The PrinterQueueWidget below it (which
shows "Clear Plate & Start") already filtered by filament type + color.

Apply the same filament compatibility filter (type check + color override
check) to the badge count so it only shows on printers that can actually
run the queued jobs.
2026-02-28 14:36:12 +01:00
maziggy ad6108c8a7 Fix "Clear Plate" button shown on printers without matching filament color (#486)
When a print was queued to "any printer" with a filament color override
(e.g., white PETG), the "Clear Plate & Start Next" button appeared on
printers that had the right type but wrong color. The backend scheduler
already rejected color mismatches, but the frontend only checked filament
types. Now passes loaded type+color pairs from AMS status to the widget
and filters against filament_overrides, mirroring the backend's
_count_override_color_matches() logic.
2026-02-27 08:03:21 +01:00
maziggy 20c291d678 Fix "Clear Plate & Next" shown on printers without correct filament (#527)
The "Clear Plate & Start Next" button appeared on ALL printers of a
model when a job was queued via "Queue to Any X", even printers without
the required filament loaded. Clicking it started a print that fails.

PrinterQueueWidget now filters queue items by filament compatibility —
each item's required_filament_types must all be present in the printer's
loaded filaments (AMS + external spools). If no compatible items exist,
the widget is hidden entirely. Matching is type-only (not color) and
case-insensitive, consistent with the backend scheduler. When filament
data is unavailable, no filtering is applied (graceful degradation).
2026-02-26 08:57:39 +01:00
maziggy 1973a5bead Fix virtual printer queue mode not assigning printer (#518), settings text fields resetting mid-typing
Virtual printer "print_queue" mode created queue items with no printer
assignment. Now sets target_model from the VP's SSDP model code (e.g.
P1S, X1C) for "Any Printer" scheduling, or uses target_printer_id if
configured.

Settings page auto-save onSuccess overwrote localSettings with the
server response, discarding characters typed during the save request.
Removed the stale state overwrite so in-progress input is preserved.
2026-02-26 08:06:56 +01:00
maziggy ed36eafbec Fix timestamps off by timezone offset in non-UTC containers (#504)
All backend timestamps used datetime.now() (server local time) or the
deprecated datetime.utcnow(). The frontend's parseUTCDate() assumes
timestamps without timezone indicators are UTC and appends 'Z', so
stored timestamps were off by the timezone offset when the container's
timezone wasn't UTC.

Backend: replaced datetime.now() and datetime.utcnow() with
datetime.now(timezone.utc) across 16 files (~80 call sites) for all
database fields and DB comparisons. Cosmetic timestamps (filenames,
user-facing local time formatting) intentionally left as local time.

Frontend: replaced 13 new Date(backendTimestamp) calls with
parseUTCDate() across 8 files to correctly interpret UTC timestamps.
2026-02-24 08:18:02 +01:00
maziggy 04ac6bd36e Fix power-off option not gated by printers:control permission (#500)
The "Power off printer when done" checkbox in the print modal and the
auto power off tri-state toggle in the bulk edit modal were accessible
to all users regardless of permissions. Users without printers:control
can now no longer enable auto power off — controls are disabled and
visually dimmed.
2026-02-24 07:46:12 +01:00
maziggy 24c4363620 Fix filament fill level display bugs on printer card (#496)
Three related fixes in PrintersPage.tsx:

1. External spool (vt_tray) fill level was missing the AMS remain
   fallback — only checked Spoolman/inventory, ignoring valid AMS data.
   Now uses the same fallback chain as regular and AMS-HT slots.

2. When fill was unknown (null), slot visual showed a full-width gray
   bar ("full") while the hover card showed "—" ("empty"). Removed the
   misleading gray fallback bar from all three slot types so both views
   consistently show "unknown".

3. Fill source priority always preferred AMS remain over Spoolman and
   inventory, even when those sources were more accurate (e.g. spools
   with usage tracking or migrated from Spoolman). Reversed priority to
   Spoolman → Inventory → AMS remain. Fixed fillSource label to reflect
   the actual data source (was always 'ams' even when using fallback).
2026-02-23 13:23:59 +01:00
maziggy 5cb1ca3ae2 Spoolbuddy frontend work 2026-02-23 13:02:46 +01:00
maziggy 8e6a959eef Redact IP addresses from support bundle debug logs 2026-02-23 09:24:53 +01:00
maziggy 5164152088 Fix external spool mapping inverted on H2C (#492)
On H2C/H2D dual-nozzle printers, tray_now=254 is sent generically for both
external spools. The direct ID comparison always matched Ext-L (id=254),
never Ext-R (id=255). Now uses active_extruder to disambiguate: extruder
1 (left) → Ext-L, extruder 0 (right) → Ext-R.
2026-02-23 08:57:35 +01:00
maziggy 6da12a8ad2 Fix wrong documentation link for "Lubricate Carbon Rods" on P2S (#490)
The maintenance page linked P2S "Lubricate Carbon Rods" to the
belt-tension wiki page instead of the XYZ axis lubrication page.
2026-02-23 08:30:28 +01:00
maziggy 3c72f7cb22 Show inventory sidebar item for both Spoolman and internal inventory
Previously the Inventory sidebar item was hidden when Spoolman was
enabled. Now it always shows — when Spoolman is active, /inventory
embeds the Spoolman web UI in the content area via iframe; when
disabled, it renders the internal inventory page as before.
2026-02-23 08:23:35 +01:00
maziggy d5c9f2b9ea Moved Spoolbuddy frontend to Bambuddy 2026-02-23 07:58:00 +01:00
maziggy 9381edf0cb Removed new Spoolbuddy frontend 2026-02-22 18:01:01 +01:00
maziggy aeca15b585 Add SpoolBuddy integration as optional filament management add-on
SpoolBuddy turns a Raspberry Pi 4B with a PN5180 NFC reader and
NAU7802 scale into a filament management station that integrates
with Bambuddy via REST API and WebSocket.

Backend: SpoolBuddyDevice model, 10 REST endpoints (/spoolbuddy/*),
6 WebSocket broadcast types, background offline-detection watchdog.

RPi daemon: asyncio service with concurrent NFC polling (300ms,
MIFARE Classic + Bambu HKDF key derivation), scale reading (10 SPS,
5-sample moving average, stability detection), and 10s heartbeat
with exponential backoff reconnect.

Frontend: kiosk-optimized 1024x600 UI at /spoolbuddy with Dashboard
(live weight + NFC spool detection), AMS Overview, Inventory,
Printers, and Settings pages. useSpoolBuddyState reducer hook
driven by WebSocket CustomEvents.

i18n: all 6 locales (en, de, fr, it, ja, pt-BR).
2026-02-22 15:27:54 +01:00
maziggy e450c3b728 Add visual spool grouping and optional brand/subtype in quick-add (#480)
Group toggle in inventory toolbar collapses identical unused/unassigned
spools into expandable rows/cards with count badges. Grouping key uses
material, subtype, brand, color, and label weight. Brand and subtype
fields now appear in quick-add mode as optional (no asterisk, no
validation). Quantity field restricted to quick-add mode only.
2026-02-22 10:05:03 +01:00
maziggy 16fa84bc16 Add bulk spool addition and stock spools
Add Quick Add mode to the spool form for simplified entry (material +
color + weight only), and a quantity field (1-100) for creating multiple
identical spools at once. Stock spools (no slicer profile) are computed
rather than stored — any spool without slicer_filament shows an amber
"Stock" badge. New filter chips (All/Stock/Configured) on the inventory
page. Backend bulk endpoint creates N spools in one transaction.

Backend:
- SpoolBulkCreate schema with quantity validation (1-100)
- POST /inventory/spools/bulk endpoint

Frontend:
- Quick Add toggle in SpoolFormModal (create mode only)
- Quantity field in FilamentSection (both modes)
- bulkCreateSpools API method and bulkCreateMutation
- Stock column (hidden by default) and stock filter chips
- Inline error rendering moved into FilamentSection
- CellCtx extended with t() for translatable cell content

Tests:
- 13 backend tests (schema validation + endpoint logic)
- 10 frontend tests (validateForm quickAdd + UI behavior)

i18n: 6 locales (en, de, fr, it, ja, pt-BR)
Docs: CHANGELOG, README, website features, wiki inventory
2026-02-21 10:39:18 +01:00
maziggy 839be41133 Fix support bundle leaking personal data (#473)
The log sanitizer only used regex patterns, missing arbitrary user-chosen
strings (printer names, usernames). Tasmota smart plug credentials were
logged verbatim in URLs by httpx.

- Make _sanitize_log_content() database-aware: query Printer names/serials,
  User usernames, and Bambu Cloud email for exact-string replacement
  (longest-first, skip <3 chars to prevent over-redaction)
- Fix serial regex leaking first 3 chars (remove capture group partial
  redaction), add case-insensitive flag
- Move Tasmota credentials from URL-embedded (http://user:pass@host) to
  httpx auth= parameter so they never appear in logs
- Add URL credentials regex as defense-in-depth for user:pass@ in logs
- Add 'username' and 'path' to settings sensitive_keys filter (catches
  smtp_username, slicer_binary_path in support-info.json)
2026-02-21 08:17:59 +01:00
maziggy 1404242e0c Fix cost tracking issues 2026-02-20 16:31:16 +01:00
MartinNYHC 965000c3ca Merge branch '0.2.1b2' into feature/cost_tracker 2026-02-20 16:26:01 +01:00
Wesley Reuel Marques SilvaandMartinNYHC ceb2de7164 Adding the energy cost from 2 to 3 decimal precision (#416)
* Adding the energy cost from 2 to 3 decimal precision

* Complying with pr

* Complying with PR

* Complying with PR

* Fix energy cost display precision in ProjectDetailPage

* Change energy cost formatting to two decimal places

* Change decimal precision for energy cost display

---------

Co-authored-by: MartinNYHC <mz@v8w.de>
2026-02-20 16:23:00 +01:00
Keybored 85645ce184 Merge branch '0.2.1b2' into feature/cost_tracker 2026-02-20 15:44:34 +01:00
maziggy 40403ae584 Fix inventory date format and AMS-HT slot labels (#463)
Two bugs in the inventory page:

1. Dates always displayed as DD/MM/YY regardless of the user's date
   format setting. The page had a local formatDate() hardcoding en-GB
   locale. Replaced with the shared formatDateOnly() from utils/date.ts.

2. AMS-HT slot locations showed accented characters (e.g., "Á1") instead
   of proper labels (e.g., "HT-A"). The code used String.fromCharCode(65
   + ams_id), which produces garbled chars for AMS-HT IDs (128+). Now
   uses the shared formatSlotLabel() from utils/amsHelpers.ts.
2026-02-20 15:22:44 +01:00
Matteo Parenti 9f19e8a2ff Add currency symbol, hide projected cost for no costs configured, add cost rounding to decimal point, fixed isExternal logic 2026-02-20 11:36:26 +01:00
Matteo Parenti 071c2c702a Refactor cost calculation logic to utilize pre-fetched spool usage costs and remove redundant imports; update InventoryPage to adjust cost display format 2026-02-19 18:22:07 +01:00
Matteo Parenti 8043bb18ba Refactor cost calculation logic to prioritize spool usage history and update schema validation for cost_per_kg 2026-02-19 16:55:25 +01:00
MartinNYHC c72366c9d3 Merge branch '0.2.1' into feature/cost_tracker 2026-02-19 16:30:28 +01:00
Keybored 0e50285860 Merge branch '0.2.1b' into feature/cost_tracker 2026-02-19 16:25:27 +01:00
maziggy 2f51bec40d feat: add "Include beta updates" setting to filter prerelease notifications
Users on the Docker `latest` tag were seeing update notifications for beta
releases (e.g. v0.2.1b) they couldn't install. The update checker now fetches
/releases instead of /releases/latest and filters by parse_version() prerelease
detection. A new toggle in Settings (default: off) lets users opt in to beta
notifications.
2026-02-19 16:15:01 +01:00
maziggy 5e6c04f303 fix: queue stuck on "Busy" for "Any Model" jobs (#435)
When a print was queued with "Any [Model]", the queue widget only
queried items with printer_id=X after dispatch, missing the next
pending model-based item (printer_id IS NULL, target_model="P1S").
The "Clear Plate & Start Next" button never appeared, leaving the
scheduler stuck reporting "Busy".

Add optional target_model query parameter to GET /queue/. When
combined with printer_id, uses OR logic to also return unassigned
items whose target_model matches. The frontend now passes the
printer's model through PrinterQueueWidget to this query.
2026-02-19 14:22:28 +01:00
Matteo Parenti 04ffca204f Add cost tracking for spools and usage history 2026-02-19 14:13:18 +01:00
maziggy 7b39026429 fix: resolve PFUS preset IDs causing slicer slot resets + fill level for new spools
BambuStudio actively resets AMS slots configured with unrecognized PFUS*
(user-local) preset IDs. Replace PFUS* with generic Bambu filament IDs
(e.g. GFL99 for PLA) in both the slot configure and inventory assignment
endpoints. When the slot already has a recognized cloud-synced preset for
the same material, reuse it to preserve K-profile calibration.

Also fix fill level bar not showing for brand new spools (weight_used=0)
by changing the condition from weight_used > 0 to weight_used != null.
2026-02-19 12:54:15 +01:00
maziggy d24e7cdf84 feat: multiple virtual printers with dedicated bind IPs + dual bind/detect ports (#445)
Multiple Virtual Printers:
- Each VP gets a dedicated bind IP with independent FTP, MQTT, SSDP, and Bind services
- New VirtualPrinter DB model, CRUD API (/api/virtual-printers), React UI
- VirtualPrinterList, VirtualPrinterCard, VirtualPrinterAddDialog components
- Per-instance TLS certificates (shared CA), 11 printer models, all 4 modes
- Auto-incremented serial suffixes, network interface override per VP

Dual Bind/Detect Ports (#445):
- Listen on both ports 3000 and 3002 for slicer bind/detect handshake
- Different BambuStudio/OrcaSlicer versions use different ports
- Applies to BindServer (server mode) and SlicerProxyManager (proxy mode)
- Updated Dockerfile, docker-compose.yml, firewall rules in wiki

Also:
- Rewrote VP test suite for new multi-instance architecture (75 tests)
- Rewritten "How it works" section with 3-step workflow explanation
- Updated all 5 locales (en, de, ja, fr, it)
- Updated wiki and website for multi-VP + dual ports
- New multi-VP screenshot
2026-02-19 11:22:28 +01:00
maziggy cb3363733e fix: remove dead PAUSED printer state checks (#447)
The printer only sends PAUSE via MQTT gcode_state, never PAUSED.
Removed all unreachable PAUSED comparisons from frontend (4 files)
and backend (2 files).
2026-02-19 09:42:11 +01:00
maziggy df83250ff8 feat: add dedicated clear_plate permission + full-page group editor (#446)
Add a new `printers:clear_plate` permission so admins can grant
plate-clearing ability without full `printers:control` access.
Existing groups with `printers:control` automatically receive the
new permission on startup via migration.

Replace the cramped permission modal in Settings with a dedicated
full-page group editor (`/groups/new`, `/groups/:id/edit`) featuring
search filtering, select all/clear all, category-level toggles,
and a responsive 2-column permission grid. Remove dead GroupsPage
code that was never routed.

- Backend: new Permission enum, category, defaults, endpoint guard, migration
- Frontend: GroupEditPage, updated routes, removed modal from SettingsPage
- Tests: 10 backend + 10 frontend tests for new permission and editor
- Docs: updated wiki (auth, printer-control, API), website, changelog
- i18n: added group editor keys to all 6 locale files (en/de/ja/fr/pt-BR/it)
2026-02-19 09:11:42 +01:00
MartinNYHC bb4902ad53 Merge branch '0.2.1b' into add-H2D-Pro-png 2026-02-18 17:16:12 +01:00
MartinNYHC 1d636c9a16 Merge branch '0.2.1b' into refactor-all-pages 2026-02-18 16:54:55 +01:00
maziggy a903816b8a fix(slicer): token-based auth for Open in Slicer downloads (#433)
Slicer protocol handlers (bambustudio://, orcaslicer://) launch the
slicer app which fetches files via HTTP but cannot send auth headers.
The global auth middleware returned 401, causing "importing failed."

Add short-lived, single-use download tokens: the frontend fetches a
token via authenticated POST, then builds a /dl/{token}/{filename} URL
the slicer can access without auth headers. Tokens are validated
server-side (5-min expiry, single-use). Applies to archive files,
source 3MFs, and library files.

Also fix platform-specific URL formats to match slicer source code:
- macOS: bambustudioopen:// with encodeURIComponent
- Windows/Linux: bambustudio://open?file= (was wrongly using macOS scheme on Linux)
- OrcaSlicer: orcaslicer://open?file=
2026-02-18 16:37:35 +01:00
MartinNYHC 1c068d2a2f Merge branch '0.2.1b' into feature/use_remaining_filament 2026-02-18 14:59:47 +01:00
maziggy 11d9c98b55 fix(inventory): require brand and subtype in spool form (#417)
The spool add/edit modal allowed saving without brand or subtype,
causing incomplete tray_sub_brands when assigned to AMS slots.
BambuStudio then failed to recognize the filament profile.

Brand and Subtype are now mandatory with validation errors on submit.
2026-02-18 14:59:03 +01:00
AneoPsy 00b02ee620 Fix conflict 2026-02-18 03:32:24 -10:00
AneoPsy b931eeb3fd Merge remote-tracking branch 'upstream/0.2.1b' into refactor-all-pages 2026-02-18 03:25:56 -10:00
tridev 5794f0ffe7 Add H2D Pro printer image and mapping 2026-02-18 14:08:11 +01:00
AneoPsy d9dd15dbff fix(ui): storage size formatting, overdue queue items, and i18n fixes
- Add formatStorageSize helper in FileManagerModal to display storage
  in GB/MB instead of raw bytes
- Show "Overdue" label for queue items whose scheduled time has passed
  by more than 1 minute
- Fix missing "in" prefix for English inDays translation
- Fix swapped justNow/now translations in Italian locale
- Fix whitespace formatting for waiting key across all locales
- Add trailing newline to date.ts and date.test.ts
2026-02-18 02:45:43 -10:00
MartinNYHC 626a345596 Merge branch '0.2.1b' into feature/use_remaining_filament 2026-02-18 13:42:56 +01:00
AneoPsy 6c308ecbd2 feat(queue): improve mobile responsiveness for QueuePage
- Summary cards: 2-col mobile grid with responsive padding, icons, and text sizing; 5th card spans full width on 2-col layout
- Filters: flex-wrap with scaled text/padding; selects share width on mobile; clear history button goes full-width
- Section headers (Pending/History): flex-wrap so sort controls wrap below title; drag hint hidden on mobile; responsive icon and text sizes
- Bulk action toolbar: flex-wrap with tighter gaps/padding; vertical divider hidden on mobile; scaled button text and icons
- SortableQueueItem: top-aligned on mobile; smaller thumbnail (10→14 at sm); metadata row wraps with truncated printer name; username hidden on mobile; badges scale down; status badge and actions stack vertically on mobile; tighter button padding
2026-02-18 02:08:42 -10:00
MartinNYHC f38aced463 Merge branch '0.2.1b' into refactor-all-pages 2026-02-18 11:32:19 +01:00