Commit Graph
799 Commits
Author SHA1 Message Date
maziggy d8770b2bce Fix energy costs not updating per timeframe in statistics (#695)
In "total" energy tracking mode, the stats endpoint queried smart plug
  lifetime counters which can't be filtered by date range. Energy costs
  and kWh stayed the same regardless of timeframe selection. Fall back to
  per-print archive data when date filters are active.
2026-03-14 10:18:27 +01:00
maziggy 95625aa860 Fix daily build tags falsely triggering update notification
parse_version() misclassified "0.2.2b4-daily.20260313" as a release
  because the daily suffix made the last dot-segment ("20260313") contain
  no alpha chars, bypassing prerelease detection. Strip -daily.YYYYMMDD
  suffix before parsing so daily builds compare as their base beta version.
2026-03-13 16:16:28 +01:00
maziggy 4db87505c7 Housekeeping 2026-03-13 14:35:25 +01:00
maziggy 81db4eabaf Fix smart_plugs UNIQUE constraint migration not firing on some databases (#689)
The migration that removes the UNIQUE constraint on smart_plugs.printer_id
  used an exact substring match ("printer_id INTEGER UNIQUE") to detect the
  constraint. Databases created with older SQLAlchemy versions may express
  the constraint differently (quoted column names, table-level UNIQUE clause,
  or separate UNIQUE indexes), causing the migration to silently skip.

  Users hit "IntegrityError: UNIQUE constraint failed: smart_plugs.printer_id"
  when assigning a second HA switch to a printer.

  Replace the exact string match with regex pattern matching that handles
  inline constraints, table-level UNIQUE(printer_id), quoted column names,
  and standalone UNIQUE indexes.
2026-03-13 13:36:47 +01:00
maziggy e314305623 Fix HMS notifications firing for unknown/phantom error codes
Printers send many undocumented HMS codes (e.g. 0501_0002, 0501_0004,
  0300_0001) that don't correspond to real errors — calibration status,
  firmware state, etc. The frontend already filters these out (only shows
  codes in ERROR_DESCRIPTIONS), but the backend notified for all codes
  with severity >= 2, causing spurious email/push notifications on every
  backend restart when a printer has active phantom codes.

  Flip the logic: only send notifications for HMS codes with a known
  description in the backend's HMS_ERROR_DESCRIPTIONS dictionary. Also
  fix the log message to report the actual number of notifications sent,
  not the pre-filter count.
2026-03-13 13:23:01 +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
maziggy 5a4a2260b1 Fix PA-CF/PA12-CF/PAHT-CF type matching and force color match click target (#688)
Bambu Lab firmware treats PA-CF, PA12-CF, and PAHT-CF as interchangeable,
  but the print scheduler and filament override UI used exact string matching.
  A 3MF requiring PA-CF wouldn't match PA12-CF in the AMS, leaving the
  override dropdown disabled and preventing scheduler assignment.

  Add a filament type equivalence system (both backend and frontend) so
  these PA variants are treated as compatible in scheduler assignment,
  AMS slot matching, force color match validation, and the override dropdown.

  Also fix the "Force color match" checkbox click target being too wide
  (entire row instead of just the checkbox/label) by changing flex to
  inline-flex on the label element.
2026-03-13 12:56:31 +01:00
maziggy 220717f174 Fix inventory usage tracker missing external spool mapping (#677)
When all higher-priority slot-to-tray mapping methods failed (MQTT
  mapping, print command mapping, queue mapping, color matching), the
  internal usage tracker fell back to slot_id - 1 which can never reach
  external spool IDs (254/255) or AMS-HT IDs (128+). Added position-based
  resolution using sorted available tray IDs, matching the Spoolman fix
  from PR #686.
2026-03-13 12:08:11 +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 685d04df67 Fix virtual printer proxy mode always defaulting to X1C model
When creating a virtual printer in proxy mode, the model was always set
  to X1C because the frontend hides the model dropdown and the backend
  used a hardcoded default. Now auto-inherits the model from the target
  printer in proxy mode — on create, on target printer change, and on
  mode switch to proxy.
2026-03-13 10:21:46 +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
maziggy 3aa1382987 Fix P2S camera stream disconnecting after a few seconds (#661)
The P2S firmware drops RTSP sessions after a few seconds with an I/O
  error. The backend treated this as fatal, ending the MJPEG stream and
  forcing the frontend through a full reconnection cycle. Added transparent
  auto-reconnection: when ffmpeg's RTSP connection dies, it respawns
  immediately and continues streaming MJPEG frames to the browser with
  only a brief freeze (~1s). Up to 30 reconnections before giving up.
2026-03-12 11:34:27 +01:00
maziggy fea6350462 Housekeeping 2026-03-12 10:50:18 +01:00
maziggy 374895f959 Fix ethernet badge false positive and MQTT thread crash (#585)
Three bugs: (1) home_flag bit 18 is set on all printers regardless
    of connection type, so every ethernet-capable model showed the badge
    even on WiFi. Replaced with wifi_signal heuristic — ethernet printers
    with WiFi disabled report a hardcoded -90 dBm sentinel. (2) The lazy
    import used `from app.utils.printer_models` which crashes with
    ModuleNotFoundError in paho-mqtt's background thread (correct path:
    backend.app.utils.printer_models). This killed the thread, causing
    all printers to go stale after 60s and disconnect/reconnect in a
    loop. (3) WiFi-only models excluded via model-based gating.
2026-03-11 14:35:05 +01:00
maziggy 42eab0354d Bumped version 2026-03-11 13:26:16 +01:00
maziggy 26a3b2172d Fix ethernet badge shown on WiFi-only printers (#585)
home_flag bit 18 is set on all printers regardless of hardware,
    causing the ethernet badge to appear on WiFi-only models (A1, P1P,
    etc.). The previous fix removed the feature entirely, so ethernet
    printers lost their badge too.

    Now only trusts bit 18 on models with an ethernet port (X1C, X1E,
    P1S, P2S, H2D, H2D Pro, H2C, H2S). WiFi-only models always show
    the WiFi signal badge.
2026-03-11 12:56:23 +01:00
maziggy 7eb82f58fa Updated CHANGELOG 2026-03-11 10:13:35 +01:00
maziggy c873b74fe6 Merge branch '0.2.2b3' into 0.2.3b1 2026-03-11 10:05:02 +01:00
maziggy d374e5f70b Fix debug logging endpoint 500 error after version upgrade
The GET /api/v1/support/debug-logging endpoint returned 500 when the
  database contained a timezone-aware enabled_at timestamp written by
  0.2.2b3. The duration calculation mixed offset-aware and offset-naive
  datetimes, raising TypeError. Strip tzinfo when reading the stored value.
2026-03-11 09:58:51 +01:00
maziggy 3788dd723c Added debug logging for ffmpeg process 2026-03-11 09:57:55 +01:00
maziggy f69b0413f0 Fix bed cooled notification never firing (#497)
Two bugs prevented bed cooldown notifications from working:

  1. Stale temperature data: After print completion, the printer sends
     partial MQTT updates without bed_temper, leaving the cached value
     frozen at the end-of-print temperature. The monitor polled for 30
     minutes seeing the stale value above threshold, then timed out.
     Fix: send periodic pushall commands to force fresh temperature data.

  2. Missing fields in provider create endpoint: on_bed_cooled and all 7
     queue event toggles were omitted from the NotificationProvider
     constructor, silently discarding user selections on create (update
     worked fine via dynamic setattr).

  Also added debug logging to the bed cooldown polling loop.
2026-03-11 09:57:55 +01:00
maziggy a0fee9a1b6 Fix debug logging banner showing negative timer duration
The debug logging banner displayed a negative elapsed time (e.g. "-60m -59s")
  equal to the server's UTC offset. datetime.now() stored local time without a
  timezone indicator, but the frontend's parseUTCDate() interpreted it as UTC.

  Use datetime.now(tz=timezone.utc) consistently for storing, parsing, and
  comparing the enabled_at timestamp.
2026-03-11 09:57:34 +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
maziggy 53b8cbc169 Added debug logging for ffmpeg process 2026-03-11 09:29:03 +01:00
maziggy 283eaed2de Fix bed cooled notification never firing (#497)
Two bugs prevented bed cooldown notifications from working:

  1. Stale temperature data: After print completion, the printer sends
     partial MQTT updates without bed_temper, leaving the cached value
     frozen at the end-of-print temperature. The monitor polled for 30
     minutes seeing the stale value above threshold, then timed out.
     Fix: send periodic pushall commands to force fresh temperature data.

  2. Missing fields in provider create endpoint: on_bed_cooled and all 7
     queue event toggles were omitted from the NotificationProvider
     constructor, silently discarding user selections on create (update
     worked fine via dynamic setattr).

  Also added debug logging to the bed cooldown polling loop.
2026-03-11 08:55:03 +01:00
maziggy 253828c2b5 Fix debug logging endpoint 500 error after version upgrade
The GET /api/v1/support/debug-logging endpoint returned 500 when the
  database contained a timezone-aware enabled_at timestamp written by
  0.2.2b3. The duration calculation mixed offset-aware and offset-naive
  datetimes, raising TypeError. Strip tzinfo when reading the stored value.
2026-03-10 14:13:32 +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 63208cf6f1 Fix debug logging banner showing negative timer duration
The debug logging banner displayed a negative elapsed time (e.g. "-60m -59s")
  equal to the server's UTC offset. datetime.now() stored local time without a
  timezone indicator, but the frontend's parseUTCDate() interpreted it as UTC.

  Use datetime.now(tz=timezone.utc) consistently for storing, parsing, and
  comparing the enabled_at timestamp.
2026-03-10 10:51:23 +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 688804ac07 Housekeeping 2026-03-10 08:38:29 +01:00
maziggy fa4bb92f7d Add higher FTP timeout options for large 3MF files (#660)
Large Hueforge 3MF files (~28 MB) can't be downloaded from the
  printer's FTP server within the previous 120s max timeout, especially
  during active printing. Added 180s and 300s timeout options to the
  FTP settings dropdown.
2026-03-10 08:31:44 +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 121b3d53df fix: remove incorrect ethernet badge on printer cards
home_flag bit 18 was incorrectly interpreted as "wired/ethernet
  connection", causing the ethernet badge to always show — even on
  printers without an ethernet port (e.g. A1, P1S). This hid the
  WiFi signal indicator entirely.

  Removed the wired_network field and ethernet badge UI. The WiFi
  signal badge now shows correctly whenever the printer reports
  signal strength.
2026-03-09 12:16:22 +01:00
d7401a80df Feature: Force Color Match (#625)
* Added "Force Color Match" feature to filament override

* Update settings.py

* Update settings.py

* Label updates for warnings and checkbox case

* Initial plan

* Add noMatchingMaterial i18n translations to all 7 locale files

Co-authored-by: cadtoolbox <12723486+cadtoolbox@users.noreply.github.com>

* Use {{material}} interpolation in noMatchingMaterial; populate from filament_overrides with getColorName

Co-authored-by: cadtoolbox <12723486+cadtoolbox@users.noreply.github.com>

* Updates for PR#625 comments

* Added "Force Color Match" feature to filament override

* Update settings.py

* Update settings.py

* Label updates for warnings and checkbox case

* Initial plan

* Add noMatchingMaterial i18n translations to all 7 locale files

Co-authored-by: cadtoolbox <12723486+cadtoolbox@users.noreply.github.com>

* Use {{material}} interpolation in noMatchingMaterial; populate from filament_overrides with getColorName

Co-authored-by: cadtoolbox <12723486+cadtoolbox@users.noreply.github.com>

* Updates to PrintersPage and QueuePage

* Update QueuePage.tsx

* Rebase to 0.2.2b3

* Fix compile errors with FilamentOverride

* Updates for PR#625 comments

https://github.com/maziggy/bambuddy/pull/625#pullrequestreview-3908738261

* Fix force color match default, loadedFilamentTypes bug, remove dead translations

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: cadtoolbox <12723486+cadtoolbox@users.noreply.github.com>
Co-authored-by: MartinNYHC <mz@v8w.de>
2026-03-09 11:54:02 +01:00
Neale Swinnerton ae80eaade0 feat(metrics): add bambuddy_build_info metric
Publish a gauge with version, python_version, platform, and
architecture labels at the top of the Prometheus metrics endpoint.
2026-03-07 15:40:48 +00: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 f1d5ee422c Bumped version 2026-03-07 11:11:16 +01:00
maziggy 0efb4690b9 Fix SD card error after FTP upload by waiting for 226 response (#645)
The FTP upload skipped reading the server's "Transfer complete"
  confirmation, sending the print command before the file was flushed
  to the SD card. Now waits for the 226 response with a 60s timeout.
2026-03-07 11:01:34 +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 538fe4b13b Bumped version 2026-03-06 15:51:49 +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 0faf03ecb3 Fix Python 3.10 compatibility (StrEnum requires 3.11)
enum.StrEnum was added in Python 3.11, but the documented minimum is
  3.10. Add a compatibility shim in backend/app/core/compat.py that falls
  back to (str, Enum) on older versions. Updated all 5 import sites and
  lowered pyproject.toml target-version to py310.
2026-03-05 10:44:24 +01:00
maziggy aa39f6c866 Fix Bind-TLS proxy handshake failure on OpenSSL 3.x
Bambu printers only support plain RSA key exchange ciphers
  (AES256-GCM-SHA384, AES128-GCM-SHA256), but Python's OpenSSL 3.x
  defaults exclude them in favor of forward-secrecy (ECDHE/DHE) only.
  Add the RSA ciphers to the client SSL context so the TLS proxy can
  connect to the printer's bind port (3002).
2026-03-05 10:08:31 +01:00