Commit Graph
253 Commits
Author SHA1 Message Date
MartinNYHC 67f91d94de v0.2.2.2 (#830)
v0.2.2.2 (#830)
2026-03-27 09:27:47 +01:00
maziggy d750e8f0e0 Added Spoolbuddy frontend/backend tests 2026-03-22 12:55:35 +01:00
maziggy 750accb17d Fix queue print command not reaching printer on reconnect (#778)
When targeting a specific printer, the scheduler's power-on-wait loop
  created new MQTT clients on each attempt. Each new client re-tried the
  request topic subscription, which some brokers (e.g. A1) reject by
  disconnecting. This caused a 170s thrash loop leaving the connection
  fragile, so the eventual print command silently failed to reach the
  printer.

  Cache request topic support per serial number at the class level so
  new client instances inherit the knowledge and skip the subscription.
2026-03-22 08:17:53 +01:00
maziggy 488f66310f [Fix] Preserve AMS spool assignments across printer restart (#765)
When a printer shuts down it sends a final MQTT message with
  tray_exist_bits=0 and power_on_flag=false. The tray_exist_bits
  clearing code processed this all-zero value, wiping every AMS
  slot's filament data. On reconnect, the auto-unlink check saw
  empty tray data (no color, no type) and deleted all spool
  assignments as "fingerprint mismatch".

  Fix: skip tray_exist_bits slot clearing when power_on_flag is
  false. Defaults to true when absent for backwards compatibility.

  Adds 3 regression tests covering shutdown preservation, genuine
  removal still working, and missing power_on_flag fallback.
2026-03-20 16:28:45 +01:00
maziggy dc4d77b93a [Feature] Redesign bug report debug log capture flow
Replace fixed 30-second debug log collection with an interactive
  3-step flow: start logging, reproduce the issue, stop & submit.
  Users now control timing instead of racing a countdown.

  Backend: split _collect_debug_logs() into POST /start-logging and
  POST /stop-logging endpoints; add debug_logs field to submit request.
  Frontend: 3-step progress indicator with elapsed timer, pulsing
  active state, and 5-minute auto-stop. Updated all 7 locale files.
2026-03-20 14:18:24 +01:00
maziggy e82362ac65 [Feature] Add spool rotation option for AMS drying
Add a "Rotate spool during drying" checkbox to the manual drying popover
  for AMS 2 Pro and AMS-HT units. The firmware-level rotate_tray field was
  already sent (hardcoded to false) — this makes it user-configurable.
  The checkbox defaults to unchecked and resets each time the popover opens.
  Firmware silently disables rotation if filament is currently loaded.
2026-03-20 12:14:44 +01:00
maziggy 35ce075486 [Fix] Suppress spurious "waiting for filament" notification when printers are busy (#753)
When all matching printers were busy and a job was queued with ASAP
  timing, the scheduler immediately fired a "Job Waiting for Filament"
  notification even though the job was just waiting for a printer to
  finish — no user action required.

  Added _is_busy_only() check to skip the waiting notification when the
  only reason is "Busy". Notifications still fire for actionable reasons
  (missing filament, offline, wrong color). Also renamed the default
  notification template title to "Queue Job Waiting" and updated
  descriptions across all 7 locales.
2026-03-20 11:34:23 +01:00
maziggy 332a7c6ac8 [Fix] Virtual Printer proxy: transparent TCP for X1C/X1 compatibility (#757)
The closed-source bambu_networking DLL validates TLS connection parameters
  and rejects connections where the certificate doesn't match the printer's
  real BBL CA certificate. The TLS-terminating proxy presented Bambuddy's
  own certificate, causing X1C/X1 prints to silently fail after verify_job.

  Switch to transparent TCP proxying for FTP, FileTransfer, Camera, and FTP
  data — only MQTT remains TLS-terminated (required for IP rewriting). The
  slicer now gets end-to-end TLS directly with the printer's real certificate.

  Changes:
  - SlicerProxyManager uses TCPProxy for FTP (990), FileTransfer (6000),
    Camera (322), and pre-listens on FTP data ports (50000-50100)
  - Only MQTT (8883) uses TLSProxy for IP rewriting
  - Remove debug logging from MQTT and FTP proxy code
  - Fix install.sh missing AmbientCapabilities=CAP_NET_BIND_SERVICE
  - Update module docstring, migration docs, README proxy description
  - Add tests verifying transparent proxy architecture
2026-03-19 15:43:11 +01:00
maziggy 1b1f58fc88 [Fix] Virtual Printer proxy mode fails on isolated networks (#757)
When the slicer and printer are on different VLANs, Bambu Studio could
  not send prints through the proxy because the printer's real IP leaked
  through MQTT payloads, the bind protocol forwarded the real printer's
  identity, file transfer and camera ports were not proxied, and FTP
  data connections raced the TLS handshake on zero-byte uploads.

  - Rewrite IP addresses in MQTT PUBLISH payloads (string + integer)
    with proper packet framing and cross-chunk buffering
  - Respond to bind/detect with VP identity via BindServer
  - Add TLS proxies for port 6000 (file transfer) and 322 (RTSP camera)
  - Buffer slicer FTP data during printer connection setup
  - Advertise configured VP name in SSDP proxy
  - Add cross-subnet SSDP wildcard listener for VPN setups
  - Register UserEmailPreference model in models/__init__.py
  - Add 11 unit tests for MQTT rewrite, IP conversion, SSDP name
2026-03-19 11:10:22 +01:00
maziggy 0b2b81a34d [Fix] Virtual Printer proxy mode fails on isolated networks (#757)
When the slicer and printer are on different VLANs, Bambu Studio could
  not send prints through the proxy because the printer's real IP leaked
  through MQTT payloads, the bind protocol forwarded the real printer's
  identity, the port 6000 file transfer tunnel was not proxied, and FTP
  data connections raced the TLS handshake on zero-byte uploads.

  - Rewrite IP addresses in MQTT PUBLISH payloads (string + integer)
    with proper packet framing and cross-chunk buffering
  - Respond to bind/detect with VP identity via BindServer
  - Add TLS proxy for port 6000 (file transfer tunnel)
  - Buffer slicer FTP data during printer connection setup
  - Advertise configured VP name in SSDP proxy
  - Add cross-subnet SSDP wildcard listener for VPN setups
  - Register UserEmailPreference model in models/__init__.py
  - Add 11 unit tests for MQTT rewrite, IP conversion, SSDP name
2026-03-19 11:03:10 +01:00
maziggy dfb995bfe9 [Fix] Remove incorrect "Lubricate Carbon Rods" maintenance task (#755)
Carbon rods use plain bearings — lubricating them degrades print quality.
  Removed the lubrication task from defaults; only "Clean Carbon Rods"
  remains. Existing entries are auto-removed on next startup via
  ensure_default_types(). Updated wiki link mapping and tests.
2026-03-19 08:40:24 +01:00
maziggy 0e712c72a1 [Feature] Add quick print speed control to printer card (#256)
Add a speed control badge to the printer monitoring card controls row
  that lets users switch between Silent (50%), Standard (100%), Sport
  (124%), and Ludicrous (166%) presets during active prints. The badge
  displays a gauge icon with the current speed percentage, always visible
  but disabled when idle. Includes backend endpoint, optimistic UI
  updates, i18n for all 7 locales, and full test coverage.
2026-03-18 11:13:27 +01:00
maziggy 82d329d85c [Fix] Virtual Printer FTP routed to wrong VP with different access codes (#735)
When running multiple virtual printers with different access codes on
  separate bind IPs, FTP connections were always routed to the wrong VP.

  Root cause: the iptables REDIRECT rule (990→9990) rewrites the
  destination IP to the incoming interface's primary address. With Linux's
  weak host model (arp_filter=0), packets for secondary IPs arrive on the
  primary interface, and REDIRECT sends them all to the first VP's FTP
  server. MQTT was unaffected because port 8883 had no redirect.

  Fix: FTP server now binds directly to port 990 (standard implicit FTPS),
  eliminating the iptables redirect entirely. Requires CAP_NET_BIND_SERVICE
  (already set in the systemd service file and Docker image).

  Also removed a global asyncio set_exception_handler() in the MQTT server
  that was overwritten by each VP instance, causing spurious "Unhandled
  exception in client_connected_cb" errors on startup.

  Changes:
  - FTP_PORT: 9990 → 990 (ftp_server.py)
  - Removed set_exception_handler() from MQTT server
  - Updated Dockerfile, docker-compose.yml port mappings
  - Deprecated --redirect-990 in install script
  - Updated wiki: removed iptables instructions for all platforms
  - Added migration guide (docs/migration-vp-ftp-port.md)
  - Added unit tests for port constant and no-global-state invariant
2026-03-18 09:04:31 +01:00
maziggy dcdebef9a8 [Fix] Spool assignment UI shows wrong filament preset name (#681)
After assigning a spool to an AMS slot, the Bambuddy UI could show the
  wrong filament preset (e.g. "Bambu PLA Matte" instead of "Bambu PLA
  Silk") even though the printer was configured correctly.

  Two bugs:
  1. AssignSpoolModal (PrintersPage hover card path) never saved the slot
     preset mapping to the DB, so the display fell back to the old/stale
     mapping from a previous manual configuration.
  2. AssignToAmsModal (SpoolBuddy path) constructed the preset name from
     spool.material + spool.subtype ("PLA Silk") instead of using the
     authoritative spool.slicer_filament_name ("Bambu PLA Silk").

  Fix: the backend now saves the slot preset mapping in assign_spool()
  after successful MQTT configuration, using slicer_filament_name as the
  display name. This covers both frontend paths and ensures the correct
  name is always stored.
2026-03-18 08:12:08 +01:00
maziggy 4f617c21e1 [Fix] X1C Virtual Printer not accepting sends (#735)
X1C and X1 virtual printers used legacy SSDP model codes
  (3DPrinter-X1-Carbon, 3DPrinter-X1) that BambuStudio doesn't
  recognize, causing "incompatible printer preset" errors when
  sending prints. Changed to the correct codes (BL-P001, BL-P002)
  that real printers report via SSDP.

  Also fixed proxy mode auto-inherit storing printer display names
  (e.g. "X1C") instead of SSDP codes, by adding a resolution layer
  that maps display names to model codes.

  DB migration auto-converts existing VPs on startup.
2026-03-17 16:25:31 +01:00
maziggy a6d307d739 Post work PR #693
Add tests, docs, and ruff fixes for per-user email notifications

  - Fix missing timezone import in email_service.py (F821)
  - Fix unused lambda arg in main.py asyncio done_callback (ARG005)
  - Fix E302 blank line spacing for mark_printer_stopped_by_user
  - Fix F821/UP037 forward reference in user_email_pref model
  - Fix SettingsPage test for duplicate "Notifications" text
  - Add backend unit tests for permissions, schemas, and templates
  - Add backend integration tests for user-notifications API
  - Add frontend tests for NotificationsPage
  - Add user_email_pref model import to test conftest
  - Update CHANGELOG and README
2026-03-17 12:24:36 +01:00
Dakota G ac7cfe2930 [Fix]: Send Bambu RFID Tags to Spoolman, Allow Unlink in Manual Mode, Stop Location Clearing for Generic Spools (#719)
[Fix]: Send Bambu RFID Tags to Spoolman, Allow Unlink in Manual Mode, Stop Location Clearing for Generic Spools (#719)
2026-03-16 15:45:06 +01:00
maziggy 446da087a0 Fix webhook notifications missing camera snapshot (#679)
Webhook providers did not include image data (e.g. camera snapshots
  from first layer complete notifications) even though other providers
  like Telegram, Pushover, and Discord already attached them. The webhook
  payload now includes a base64-encoded "image" field when a snapshot is
  available (generic format only, excluded from Slack format).
2026-03-16 15:10:39 +01:00
maziggy 0feed83ce4 Fix P2S camera TLS compatibility via OpenSSL proxy (#661)
The Debian ffmpeg package uses GnuTLS, whose hardened defaults reject
  TLS renegotiation and legacy ciphers that some Bambu printer firmwares
  (notably P2S) rely on — causing RTSP sessions to drop after a few
  seconds.

  Add a local TLS termination proxy (Python ssl/OpenSSL) that handles
  the TLS connection to the printer and exposes a plain RTSP port to
  ffmpeg. The proxy rewrites RTSP request-line URLs (rtsp://proxy →
  rtsps://printer) while preserving Authorization headers so Digest
  auth hashes remain valid.

  Also:
  - Reduce RTSP reconnect delay from 1.0s to 0.2s
  - Add ffmpeg fast-start flags (-probesize 32, -analyzeduration 0,
    -fflags nobuffer, -flags low_delay)
  - Fix external camera double rate-limiting causing choppy streams
  - Apply TLS proxy to external camera rtsps:// URLs and snapshot capture
  - Update orphan ffmpeg cleanup to match rtsp:// (proxied) URLs
  - Add unit tests for RTSP URL rewriting and proxy lifecycle
2026-03-15 11:52:32 +01:00
Dakota G 30b34bc255 [Fix]: Changes SMTP testing to use saved settings in the database (#710)
[Fix]: Changes SMTP testing to use saved settings in the database (#710)
2026-03-15 09:13:47 +01:00
maziggy 14855ba8f4 Add ambient drying mode and fix block mode humidity auto-stop (#292)
Ambient drying: automatically dry filament on idle printers when
  humidity exceeds threshold, regardless of queue state. Separate toggle
  from queue auto-drying — both can run simultaneously. Uses the same
  presets, humidity threshold, and power constraint detection.

  Fix: block mode (wait for drying) previously skipped the humidity
  auto-stop check for already-drying printers, causing drying to
  continue indefinitely. Now only prevents starting new drying.
2026-03-14 15:06:07 +01:00
maziggy cffba4a911 Add queue auto-drying, configurable drying presets, and AMS PSU detection (#292)
Queue auto-drying: scheduler automatically starts drying on idle printers
  with scheduled queue prints when AMS humidity exceeds the configured
  threshold. Uses conservative parameters (lowest temp, longest duration)
  for mixed filaments. Drying stops when humidity drops below threshold
  (30-minute minimum prevents oscillation), when scheduled items are
  removed, or when the feature is disabled. Optional "block queue" mode
  delays the next print until drying completes.

  Configurable presets: temperature and duration per filament type,
  editable in Settings → Print Queue, used by both manual drying popover
  and queue auto-drying. Separate presets for AMS 2 Pro (n3f) and AMS-HT
  (n3s) reflecting different heating capabilities.

  PSU detection: drying button disabled with tooltip when dry_sf_reason
  indicates insufficient power. Parses drying status bits and dry_sf_reason
  from AMS info hex string via MQTT.

  Backend: print_scheduler.py (+316 lines), bambu_mqtt.py, printer_manager,
  schemas, settings route. Frontend: PrintersPage drying presets prop,
  SettingsPage drying config UI, i18n (7 locales). Tests: 27 new tests in
  test_scheduler_auto_drying.py covering conservative params, presets,
  state sync, stop logic, minimum drying time, and auto-stop regressions.
2026-03-14 14:21:36 +01:00
maziggy ecc9ec11f1 Fix HA switch badge toggle and multi-plug crash
Non-script HA entities (switch/light/input_boolean) on the printer card
  always sent turn_on when clicked, which is a no-op when the switch is
  already on. Now sends toggle for non-script entities so the badge click
  actually changes the switch state. Script entities still use turn_on.

  Also fix SmartPlugManager._get_plug_for_printer() using
  scalar_one_or_none() which crashes with MultipleResultsFound when
  multiple plugs are assigned to the same printer (e.g., Tasmota + HA
  switch). Now fetches all plugs and returns the main non-script plug.

  Add tests for both fixes: _get_plug_for_printer multi-plug handling
  (5 tests) and canonicalFilamentType/filamentTypesCompatible/autoMatch
  PA-CF equivalence (8 tests).
2026-03-13 13:11:12 +01:00
Dakota G fb29eb4cd7 [Fix]: Properly track filament usage data in Spoolman (#686)
Properly track filament usage data in Spoolman#686
2026-03-13 11:59:44 +01:00
maziggy 0b6facc91c Add first layer complete notification with camera snapshot (#679)
Notify users when the first layer finishes printing so they can check
  adhesion remotely. Triggers once per print when layer 2 begins
  (layer_num >= 2, capped at <= 5 to handle reconnects). Includes a
  camera snapshot attachment. Adds the on_first_layer_complete toggle
  to all notification providers, with backend/frontend/i18n support
  across all 7 locales.
2026-03-13 10:53:21 +01:00
maziggy f21e502b8f Add remote AMS drying controls (#292)
Start, monitor, and stop drying sessions for AMS 2 Pro (n3f) and
  AMS-HT (n3s) directly from the Printers page. Flame icon in AMS card
  header opens a popover with filament-based temperature/duration presets
  from BambuStudio. Live countdown status bar shows time remaining.

  Backend: cache module_type from MQTT get_version, expose dry_time and
  module_type in both WebSocket and REST paths, add supports_drying()
  with firmware gating, add server-side guard on start_drying endpoint.

  Frontend: drying button, popover with filament select + temp/duration
  sliders, status bar, start/stop mutations. i18n for all 7 locales.

  Supported: X1/X1C (fw 01.09+), P1P/P1S (fw 01.08+), H2D (fw 01.02.30+),
  H2D Pro, X1E. Not supported: P2S, A1, A1 Mini, H2S, H2C.
2026-03-12 16:46:10 +01:00
maziggy f1eb375964 Fix cloud profiles shared across all users (#665)
Cloud credentials were stored globally — one Bambu Cloud account per
  Bambuddy instance. When auth was enabled, any user logging into Cloud
  overwrote everyone else's credentials. Credentials are now stored
  per-user: each user gets their own independent Cloud login.

  Also fixed cloud data endpoints (settings, fields, preset CRUD)
  requiring settings:read/settings:update permissions instead of
  cloud:auth — users who had "Cloud Auth" enabled but "Settings"
  disabled couldn't load profiles after logging in.
2026-03-12 13:02:13 +01:00
Dakota G be2ddbee5d [Fix]: Update location when linking/unlinking to/from Spoolman (#669)
* Enhance link spool functionality with additional printer and AMS details

* Refactor linkSpool function to accept detailed context object for improved spooling integration

* Enhance LinkSpoolModal to include amsName in props and linkSpool mutation for improved functionality

* Add amsName prop to PrinterCard for enhanced spool linking functionality

* Updates LinkSpoolModal test to work with recent spool location update changes

* Adds clear_location to unlink testing

* Refactor LinkSpoolRequest to remove ams_name and update location generation logic for improved clarity

* Remove amsName from LinkSpoolModal and PrinterCard for cleaner API integration

* Remove amsName from LinkSpoolModal test props and update linkSpool mock response for improved clarity
2026-03-11 09:38:14 +01:00
Dakota GandMartinNYHC 971984f91d [Fix]: Non-Bambu Lab Spools can now be fully linked/unlinked to Spoolman (#653)
* Expanded link logic to accept a generic spool tag (spool_tag, tray_uuid, or tag_uid) and validate 16/32-char hex values, including rejection of all-zero tags. Added a new unlink endpoint that clears Spoolman extra.tag for a given spool ID.

* Updated the link validation expectation to match the new 16-or-32-hex rule. Added an integration test for the new unlink endpoint to verify extra.tag is cleared and success is returned.

* Updated the link API call to send spool_tag instead of tray_uuid. Added a new unlinkSpool API helper that calls the new backend unlink route.

* Switched modal data source from inventory spools to Spoolman unlinked spools so the list matches the backend response you shared. Updated the link action to call Spoolman link directly and use trayUuid or tagUid as the slot tag.

* Refactored Spoolman card behavior so actions render correctly across linked/unlinked cases, and added support for an Unlink from Spoolman button under Open in Spoolman. Final UI rule now hides Unlink for Bambu Lab filament and shows it only for non-Bambu linked spools.

* Added fallback slot-tag generation so untagged slots can still be linked/unlinked reliably and linked spool lookups work consistently across AMS, AMS-HT, and external trays. Wired a new unlink mutation and passed per-slot unlink callbacks into the hover card, with query invalidation for linked/unlinked spool caches after unlink.

* Added/updated the noTrayUuid message to reflect that either tray UUID or tag UID is required when no slot tag is available. This keeps error text aligned with the new tag fallback and modal behavior.

* Added noTrayUuid message in the other languages. The translation was done using Google Translate.

* Updated LinkSpoolModal tests to use Spoolman API instead of inventory API, with new UnlinkedSpool data structure and Select Spool UI text.

* Adds hashSerialToHex32, uses new function in getFallbackSpoolTag and updates all uses. This ensures we're generating a fallback spool tag using the printers serial number rather than the database ID for consistency.

* Removes 'import json' from unlink_spool and moves to the top of the file.

* Removes hasUnlinkedSpools and related references since it's no longer used

* Removes noTrayUuid from translations and references in components.

* Adds confirmation dialog before fully unlinking spool from Spoolman

* Adds unlinkConfrimTitle and unlinkConfirmMessage. All languages other than English were done using Google Translate

* Fixes unlink toast to use dedicated unlinkSuccess and unlinkFailed keys.

* Changes tag priority on spoolTag, fixes type error by adding non-null assertion to spoolTag

* Switches around tag_uid and tray_uuid on const trayTag

---------

Co-authored-by: MartinNYHC <mz@v8w.de>
2026-03-10 14:06:09 +01:00
maziggy f28421d1ae Add Home Assistant as notification provider (#656)
Sends persistent notifications to the HA dashboard using the existing
  HA connection from Settings. Zero config — just select "Home Assistant"
  as provider type. Users can forward notifications to mobile via HA
  automations.
2026-03-10 10:10:14 +01:00
maziggy 68d2230cab Fix H2D AMS units displayed on wrong nozzle (#659)
Three interrelated bugs in AMS info field parsing caused AMS units
  to appear on the wrong nozzle on H2D dual-nozzle printers:

  1. Info field parsed as decimal instead of hex (BambuStudio uses
     std::stoull with base 16)
  2. Extruder ID extracted as 1-bit instead of 4-bit field (bits 8-11)
  3. Partial MQTT updates replaced the full extruder map instead of
     merging into it
2026-03-10 08:18:23 +01:00
maziggy b3c37072b2 Add auto-dispatch toggle for virtual printer queue mode (#587)
Virtual printers in Queue mode now have an "Auto-dispatch" setting.
  When enabled (default), prints start automatically — preserving current
  behavior. When disabled, prints are added with manual_start so they
  wait for manual dispatch from the queue UI.
2026-03-07 11:41:01 +01:00
maziggy a7ddc483b3 Add bulk delete for spool and color catalog entries (#646)
Checkbox selection + "Delete Selected" button in Settings > Filament
  for both Spool Catalog and Color Catalog. Adds POST bulk-delete
  endpoints and translations for all 7 locales.
2026-03-07 10:13:40 +01:00
maziggy d55585a73f Fix P2S showing carbon rod maintenance tasks (#640)
P2S uses hardened steel rods, not carbon fiber. Move P2S from
  carbon rod classification to new steel_rod category with its own
  "Lubricate Steel Rods" / "Clean Steel Rods" maintenance tasks.
2026-03-07 09:45:14 +01:00
maziggy 09c3c24111 Add ETA variable to print notification templates (#638)
Add {eta} template variable showing wall-clock completion time
  (e.g. "15:53" or "3:53 PM") to print_start, print_progress, and
  queue_job_started notifications. Respects the user's time_format
  setting (12h/24h). The existing {estimated_time} variable continues
  to show duration ("1h 23m").
2026-03-07 09:34:01 +01:00
maziggy f66bd26f6e Add inventory:view_assignments permission so admins can grant users
visibility into AMS spool assignments on printer cards without exposing
  the full Inventory page (#635). The list_assignments endpoint now
  requires this new permission instead of inventory:read. All default
  groups (Administrators, Operators, Viewers) include it for backward
  compatibility.

  Closes #634
2026-03-07 09:17:26 +01:00
maziggy 46097a9ed4 Fix archived files counted as printed in project statistics (#630)
Files added to a project from the archive (status="archived") were
  incorrectly counted in completed_prints and parts_progress stats.
  Only status="completed" (actually printed) now counts toward completion.
2026-03-06 13:32:19 +01:00
maziggy 940810cba3 Show filament subtypes in all mapping dropdowns (#624)
All filament mapping dropdowns (single-printer, multi-printer, and
  "Print to Any" model-based) showed only the base material type (e.g.
  "PLA") without distinguishing subtypes like "PLA Basic" vs "PLA Matte",
  making entries with different subtypes but same color look identical.

  Backend: Add tray_sub_brands to available-filaments response and include
  it in the dedup key so different subtypes of the same color appear as
  separate entries.

  Frontend: Show tray_sub_brands in FilamentMapping, FilamentOverride, and
  PrinterSelector dropdowns, falling back to base type when unset. Add
  traySubBrands field to LoadedFilament interface.
2026-03-06 08:35:06 +01:00
maziggy becc4669b1 Fix greenlet_spawn error in spool auto-assign
Two lazy-load bugs caused greenlet_spawn errors in the RFID auto-assign
  flow:

  1. create_spool_from_tray set spool.k_profiles=[] AFTER db.flush(),
     but assigning to a relationship on a persistent object triggers a
     lazy load (SQLAlchemy loads the current collection before replacing).
     Moved initialization to BEFORE db.add().

  2. spool.assignments was never initialized or eagerly loaded, so
     db.add(SpoolAssignment) triggered a back_populates lazy load
     outside the async greenlet. Added assignments=[] in create and
     selectinload(Spool.assignments) in get_spool_by_tag.

  Also added exc_info=True to error handlers for full tracebacks, and
  19 new tests including greenlet regression tests that reproduce the
  exact failure.
2026-03-05 12:40:53 +01:00
maziggy ed462c5cca Add tests, docs, and lint fix for AMS Info Card feature (#570)
- Add 12 backend integration tests for AMS labels API (GET/PUT/DELETE,
    serial resolution, synthetic key fallback, whitespace handling, validation)
  - Add 10 frontend tests for FilamentSlotCircle component (rendering,
    border styles, background colors, text contrast inversion)
  - Fix ruff W293 trailing whitespace in inventory.py from contributor fix
  - Add ams_label model import to test conftest.py
  - Update CHANGELOG, README, website features page, and wiki AMS docs
2026-03-05 08:46:39 +01:00
maziggy 058f74a7da Add in-app bug reporting with relay, debug log collection, and privacy controls
Floating bug report button submits issues via bambuddy.cool relay (no GitHub
  token needed locally). Collects 30s debug logs with printer push_all, sanitizes
  all sensitive data, uploads logs as files to GitHub. Screenshot upload/paste/drag
  with JPEG compression. Translated into all 7 languages. Includes 21 tests.
2026-03-04 13:33:19 +01:00
maziggy acae51b938 Fix spurious 0300_0002 error notification via HMS array path (#583)
The previous fix only filtered status codes (< 0x4000) from the
  print_error field. Firmware can also send the same false positive
  through the hms array in MQTT, which had no such filter. Apply the
  same < 0x4000 check to the HMS parser so status/phase indicators
  are skipped regardless of which MQTT field carries them.
2026-03-04 09:26:51 +01:00
maziggy 6b92a99dd8 Improve FTP upload progress and widen print modal
FTP upload: reduce chunk size from 1MB to 64KB for smooth progress bar
  updates (~1s intervals instead of 20+ second gaps). Skip voidresp() for
  all printer models — H2D delays the 226 response by 30+ seconds after
  data transfer, causing a hang at 100%. Add transfer speed and TLS
  handshake timing to logs for diagnosing slow connections.

  Print/Schedule modal: widen from max-w-lg (512px) to max-w-2xl (672px)
  to accommodate long filament profile names like "PLA Support for PETG
  PETG Basic @Bambu Lab H2D 0.4 nozzle".
2026-03-03 14:14:26 +01:00
maziggy 330d77198a Fix AMS slot showing wrong material for "Support for" profiles
Profiles like "PLA Support for PETG PETG Basic @Bambu Lab H2D" have
  filament_type PETG, but both the frontend and backend name parsers
  found "PLA" first (iterating material types in order). The MQTT command
  sent tray_type=PLA and tray_info_idx=GFL99 (PLA generic), so the
  slicer displayed PLA instead of PETG.

  - Frontend parsePresetName(): detect "X Support for Y" pattern, extract
    material after "Support for"
  - Frontend ConfigureAmsSlotModal: prefer corrected parsed material over
    stored localPreset.filament_type for tray_type, tray_info_idx, and
    temperature fallback
  - Backend _parse_material_from_name(): same "Support for" handling for
    future profile imports
  - Backend assign_spool: prioritize spool.material over lp.filament_type
    for generic filament ID lookup
2026-03-03 13:34:03 +01:00
97f6250a0b Add customizable low stock threshold, add low stock filter (#531)
* feat(queue): show spool grams left in filament slot mapping

* Bumped version

* Add SpoolBuddy AMS slot config, external slots, and dashboard redesign

- AMS page: external spool slots (Ext/Ext-L/Ext-R), click-to-configure
  modal on all slots, temperature/humidity threshold-colored indicators,
  nozzle L/R badges for dual-nozzle printers, compact AMS-HT layout
- Dashboard: two-column layout with device status + printers list (left)
  and current spool card (right), state-colored scale/NFC icons, dashed
  border card styling
- Daemon: suppress redundant scale reports (±2g threshold + stability
  state change detection) to prevent weight display bouncing
- TopBar: auto-select online printers only, SpoolBuddy logo

* Fix SpoolBuddy daemon crash when read_tag module is missing

NFCReader.__init__ imported read_tag and instantiated PN5180() outside
the try/except block, so a missing module crashed the entire daemon.
Moved the import inside the existing try/except so the daemon gracefully
skips NFC polling — matching the scale reader's existing behavior.

* Fix SpoolBuddy daemon failing to import hardware drivers

The daemon imports read_tag and scale_diag as bare modules, but they
live in spoolbuddy/scripts/ which isn't on sys.path when systemd runs
the daemon. Added scripts/ to sys.path at startup, resolved relative
to the module file. Also moved the read_tag import inside NFCReader's
try/except (was crashing the daemon instead of skipping gracefully)
and demoted hardware-not-available messages from ERROR to INFO.

* Increase scale moving average window to reduce weight bouncing

5 samples at 100ms (500ms window) wasn't enough to smooth NAU7802 ADC
noise — the averaged value still varied by >2g between 1s report
intervals, and the stability state kept flipping, triggering a report
every cycle. Increased to 20 samples (2s window) so noise is smoothed
before reaching the reporting layer.

* Remove stability flipping as scale report trigger

When ADC noise kept the spread hovering around the 2g stability
threshold, the stable flag toggled every cycle, forcing a report with
a slightly different weight each time. Now only actual weight changes
of >=2g trigger reports. The stable flag is still included in each
report for consumers that need it.

* Fix formatting of option elements in FilamentMapping

* Make low stock threshold editable

* Add new filter for low spools

* Update bug report template to require additional fields

* Added toast for invalid imputs with locales, updated inputb field restrictions

* Minor Spoolbuddy frontend improvements

* Updated test_backend.sh

* Updated Spoolbuddy install script to strip down Raspbian

* Updated Spoolbuddy install script

* Add API key auth support to /auth/me for SpoolBuddy kiosk

When Bambuddy auth is enabled, the SpoolBuddy kiosk gets redirected to
the login page because ProtectedRoute requires a user from GET /auth/me,
which only handled JWT tokens. The kiosk daemon already has an API key
but couldn't use it to satisfy the frontend auth check.

- Backend: /auth/me now accepts API keys (Bearer bb_xxx or X-API-Key)
  and returns a synthetic admin UserResponse with all permissions
- Frontend: AuthContext reads ?token= from URL on first load, stores in
  localStorage, and strips from URL (prevents history/referrer leakage)
- Install script: kiosk URL now includes ?token=${API_KEY}
- Tests: 3 new integration tests (Bearer API key, X-API-Key header,
  invalid key rejection)

* SpoolBuddy touch-friendly UI overhaul for 1024x600 kiosk display

Enlarge all interactive elements across 9 SpoolBuddy components to meet
44px minimum tap targets on the RPi touchscreen. Increase nav icons
(20→24px), labels (10→12px), bar heights, section headers, printer
buttons, spool visualizations, fill bars, and status indicators.
Compact the dashboard stats bar and remove the printers card. Add
fullScreen prop to ConfigureAmsSlotModal with two-column layout
(filament list left, K-profile + color right) to eliminate scrolling.

* Minor changes, CSS fixes

* Refactor usageFilter state to remove 'lowstock' option for clarity

* Move var saving to API, add test coverage

* fix: threshold validation and cleanup

* Change test input from '150' to '0'

---------

Co-authored-by: tridev <c.tripod@gmx.ch>
Co-authored-by: MartinNYHC <mz@v8w.de>
2026-03-03 10:04:13 +01:00
maziggy f943420ea2 Add SpoolBuddy NFC tag writing with OpenTag3D format
Write NTAG213/215/216 tags for third-party spools via the SpoolBuddy
  kiosk UI. New "Write" page with three workflows: existing spool, new
  spool creation, and tag replacement. Backend encodes 133-byte OpenTag3D
  NDEF payloads (material, color, brand, weight, temp). Daemon writes
  page-by-page via PN5180 NTAG WRITE command with read-back verification.
  Write commands flow through heartbeat polling with WebSocket status
  updates. Includes 39 new tests and translations for all 6 languages.
2026-03-02 13:56:15 +01:00
maziggy a5016432df Fix SpoolBuddy tag_type for linked spools + add inventory weight check column
SpoolBuddy's "Link to Spool" used the generic updateSpool API which only
  set tag_uid, leaving tag_type and data_origin empty. Now uses linkTagToSpool
  with tag_type='generic' and data_origin='nfc_link'.

  Added a "Weight Check" inventory column (hidden by default) that compares
  each spool's last scale measurement against calculated gross weight with
  ±50g tolerance. Shows green check for match, yellow warning + sync button
  for mismatch. Backend stores last_scale_weight and last_weighed_at on each
  spool when weight is synced via SpoolBuddy. Includes edge case handling
  when scale weight < core weight. i18n keys added for all 6 locales.
2026-03-02 08:29:22 +01:00
MartinNYHC 449dd24f62 Merge branch '0.2.2b1' into statistic-timeframe 2026-03-01 15:15:37 +01:00
maziggy c2326b4fcb Add SpoolBuddy backend + frontend test coverage
21 backend integration tests for all 12 SpoolBuddy API endpoints
  (device register/re-register/list, heartbeat status/commands/404/
  offline broadcast, NFC tag match/unmatch/removal, scale reading/
  weight calculation/missing spool, calibration tare/set-tare/
  set-factor/zero-delta/get) and 20 frontend component tests for
  WeightDisplay, SpoolInfoCard, UnknownTagCard, and TagDetectedModal.
2026-03-01 15:08:38 +01:00
AneoPsy 168c00f47d feat(stats): add /archives/slim endpoint and fix dashboard bugs
- Add lightweight GET /archives/slim endpoint with column-level SELECT
  (13 fields vs 46), skipping duplicate detection for ~70-80% payload
  reduction on the stats dashboard
- Add ArchiveSlim Pydantic schema and TypeScript type
- Switch StatsPage and FilamentTrends to use ArchiveSlim
- Fix critical bug in failure_analysis.py: use effective_days for week
  count, separate non-date filters, build fresh week_filter per loop
- Fix busiestDay timezone bug: parse YYYY-MM-DD with split() + local
  Date constructor instead of new Date() which creates UTC midnight
- Fix success streak ordering: sort by completed_at || created_at
  instead of created_at alone
- Add 6 integration tests for /archives/slim endpoint
2026-03-01 03:11:28 -10:00