mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-10-20 17:50:12 +02:00
v0.2.2b3
638
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
b3a91d7314 |
Revert "v0.2.2b1 (#602)" (#603)
This reverts commit
|
||
|
|
3dd1ffb485 |
v0.2.2b1 (#602)
* 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
* Minor Spoolbuddy frontend improvements
* 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.
* Updated CI
* Fix naive-vs-aware datetime crash from 0.2.1 timezone migration
The timezone fix (
|
||
|
|
51ac1b1d35 | Bumped version | ||
|
|
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 |
||
|
|
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. |
||
|
|
5df2b82673 |
Fix A1 Mini "unknown" status from non-UTF-8 MQTT payload (#549)
Some firmware versions send MQTT payloads with non-UTF-8 bytes. UnicodeDecodeError was uncaught, silently dropping the entire message and leaving printer status as "unknown" with 0°C temps and no AMS. Fall back to decode(errors="replace") to keep JSON parseable. |
||
|
|
b1cc3462ed |
Fix naive-vs-aware datetime crash from 0.2.1 timezone migration
The timezone fix (
|
||
|
|
233e84c03a |
Fix naive-vs-aware datetime crash from 0.2.1 timezone migration
The timezone fix (
|
||
|
|
55c332d91a | Housekeeping | ||
|
|
2c8fbf3e33 |
Fix queue empty after restart by checkpointing WAL on shutdown (#523)
The SQLite WAL was never checkpointed during container shutdown, leaving uncommitted data (including schema migrations) in the -wal file. On restart, partial WAL recovery could cause inconsistent query results, making the queue appear empty until a filter was applied. Add PRAGMA wal_checkpoint(TRUNCATE) and engine.dispose() to the lifespan shutdown handler. |
||
|
|
2284a76381 |
Fix VP queue mode missing AMS mapping for printer-specific items (#529)
The print scheduler had two code paths for queue items: model-based (target_model set) and printer-specific (printer_id set). Only the model-based path computed ams_mapping before starting the print. VP queue items assigned to a specific printer went through the printer-specific path with null ams_mapping, causing the printer to default to the first AMS slot regardless of what the 3MF required. Add _compute_ams_mapping_for_printer() call to the printer-specific path, matching the existing model-based behavior. |
||
|
|
a6d326f8fa |
Fix VP queue mode sending wrong plate_id → HMS 0500_4003 (#529)
When a virtual printer auto-queued a file, PrintQueueItem was created without plate_id. The scheduler defaulted to plate_id=1, generating MQTT path "Metadata/plate_1.gcode". For multi-plate 3MF files sliced on a different plate, the printer couldn't find the gcode and returned HMS error 0500_4003. Extract plate index from the 3MF's slice_info.config before creating the queue item. |
||
|
|
37d9b4c841 |
Fix manual spool weight overwritten by AMS auto-sync (#525)
Add weight_locked flag to spools that auto-sets when weight_used is explicitly updated via the API. Both the MQTT AMS remain% auto-sync and the manual force-sync endpoint skip locked spools. Usage tracker delta tracking is unaffected. Users can re-enable AMS sync by setting weight_locked to false. |
||
|
|
fa87e24968 |
Add print metadata to queue API response (#524)
Queue endpoints now return filament_type, filament_color, layer_height, nozzle_diameter, and sliced_for_model from the archive or library file. Previously this data was only available via the archive API. |
||
|
|
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. |
||
|
|
c770f842f2 |
Fix "Queue to Any Printer" ignoring filament color override (#486)
When scheduling a print to "any printer" with a filament color override, the scheduler picked a printer with the correct filament type but wrong color. _find_idle_printer_for_model() used color matching only for ranking candidates, not filtering — a printer with 0 color matches was still selected if it had the right types. Now requires at least 1 color match when filament overrides specify colors. Printers with 0 matches are skipped and reported in the "waiting for filament" reason instead of being treated as candidates. |
||
|
|
c2b7b6a99a |
Fix inconsistent print cost calculation on reprints (#505)
Three independent code paths wrote to archive.cost with conflicting strategies, causing the same model to produce different prices on each reprint (e.g. £0.77, £1.54, £2.03). - Remove add_reprint_cost (Path 3) — redundant cost accumulation that double-counted on top of usage tracker - Fix usage tracker (Path 2) — compute cost from current session's results only, not a SUM of all historical SpoolUsageHistory rows - Remove _reprint_archives tracking set from main.py - Update test mocks to match simplified query pattern archive.cost now always reflects the cost of a single print. |
||
|
|
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. |
||
|
|
bbf539d156 | Bumped version | ||
|
|
faff453dec |
Fix bed cooled notification never triggering (#497)
The bed cooldown monitor was defined at the end of on_print_complete, after an early return that exits when no archive is found. Prints started from BambuStudio or the printer's touchscreen have no archive, so the function returned before the bed cooldown task was ever created. Moved the bed cooldown block (function def + task creation) to before the archive_id early-return so it fires for all completed prints. Also hardened the temperature dict check from truthiness to isinstance. |
||
|
|
8e6a959eef | Redact IP addresses from support bundle debug logs | ||
|
|
32b50e02d8 |
Fix external spool assignments lost on restart (#493)
External spool assignments (ams_id=255) were silently deleted on every AMS change because _find_tray_in_ams_data only searches AMS units, not vt_tray. Now looks up external assignments in the printer's vt_tray data instead, and preserves assignments when vt_tray hasn't arrived yet. |
||
|
|
b66d7fdec0 |
Add missing MQTT stage names for H2D print preparation
H2D firmware reports stg_cur=74 during print preparation, which was
not in the STAGE_NAMES lookup table (sourced from BambuStudio, which
only goes up to 66). This caused "Unknown stage (74)" to display on
the printer card. Also adds stage 77 ("Preparing AMS") which exists
in BambuStudio source but was missing from the lookup.
|
||
|
|
38af5df050 |
Add filament override for model-based queue assignment (#486)
When scheduling a print to "any printer" (model-based assignment), users can now override the 3MF's original filament choices per slot. The override dropdown shows compatible filaments loaded across all printers of the selected model, filtered by type and nozzle (H2D). The scheduler matches against overridden type/color instead of the original 3MF values, preferring printers with exact color matches. Backend: - New GET /printers/available-filaments endpoint (aggregates loaded filaments across printers of a model, includes extruder_id for dual-nozzle nozzle-aware filtering) - New filament_overrides JSON column on print_queue table - Scheduler applies overrides before AMS mapping, clears tray_info_idx on overridden slots so color matching takes priority - Printer selection prefers printers with most override color matches Frontend: - New FilamentOverride component with per-slot override dropdowns - Type-filtered options (PLA slots only show PLA) - Nozzle-aware filtering (H2D: only shows filaments on correct extruder) - Integrated into PrintModal for model-based queue mode Tests: - 11 backend unit tests (color match counting, override application) - 12 frontend tests (rendering, type/nozzle filtering, interactions) i18n: All 6 locales (en, de, fr, it, ja, pt-BR) |
||
|
|
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). |
||
|
|
7232ddb5a6 |
Fix finish photo not captured when archive has no source 3MF (#484)
When the 3MF source file wasn't downloaded from the printer (e.g. FTP
failure on P2S), archive.file_path was null. The finish photo capture
silently skipped because it derived the save directory from file_path.
Now falls back to archive/{id}/ directory and logs a warning.
|
||
|
|
7584a2455c |
Fix File Manager rename not updating displayed name (#460)
The rename endpoint updated `filename` but not `file_metadata.print_name`, which the UI uses as the primary display name. Since print_name is extracted from the 3MF at upload, it always took precedence over the renamed filename. Now also updates print_name in file metadata when present. |
||
|
|
257b4748e5 |
Fix developer mode detection always reporting null
The MQTT "fun" field is an integer in the JSON payload, but the parser used int(value, 16) which requires a string. This raised TypeError on every message, silently swallowed by the except clause, so developer_mode was never set. |
||
|
|
2ed32ad1e1 | Bumped version | ||
|
|
294bd74940 |
Fix AMS slot auto-config falling back to Generic instead of spool's slicer preset
Two bugs caused spool assignments to always configure AMS slots with generic Bambu filament IDs (e.g. GFB99 "Generic ABS") instead of the spool's actual slicer preset: 1. PFUS* IDs (cloud-synced custom presets) were blanket-rejected and replaced with generic IDs in both assign_spool and configure_ams_slot 2. Generic fallback IDs (GFB99, GFL99, etc.) were treated as "good" presets by the slot-reuse logic, making them sticky once set New priority: spool's own slicer_filament > slot's non-generic preset (same material) > generic fallback. |
||
|
|
0e87c377e6 |
Add developer LAN mode detection and warning banner
Parse the MQTT "fun" field bit 0x20000000 to detect whether connected printers have Developer LAN Mode enabled. Show a persistent orange warning banner when any printer lacks it, since newer firmware silently rejects MQTT write commands without developer mode. - Parse fun field into developer_mode on PrinterState - Add /printers/developer-mode-warnings lightweight polling endpoint - Include developer_mode in printer status API and support bundle - Orange banner with affected printer names and wiki link - Translations for all 6 locales (en, de, fr, it, ja, pt-BR) - 7 backend + 4 frontend tests |
||
|
|
055243683c |
Fix archive endpoints crash with "Is a directory" for BambuStudio prints (#475)
When FTP download of a 3MF fails (e.g. BambuStudio-initiated prints), the fallback archive has file_path="". Path.exists() on settings.base_dir / "" resolves to the base directory itself and returns True, so ZipFile() then fails with [Errno 21] Is a directory. Replace .exists() with .is_file() across all 15 archive route checks and 1 in main.py. Add file_path truthiness guard for finish photo capture to prevent saving photos under the base directory. |
||
|
|
7c5741b23c |
Fix wrong AMS unit displayed with dual AMS on P2S (#420)
P2S firmware sends local slot IDs (0-3) in tray_now, not global tray IDs, when multiple AMS units are connected. The UI highlighted the wrong AMS unit (e.g., AMS-A instead of AMS-B). Usage tracking was unaffected because it uses the MQTT mapping field. Added disambiguation in _handle_ams_data for single-nozzle printers with ams_exist_bits indicating >1 AMS: cross-references tray_now with the MQTT mapping field (snow-encoded) to resolve the correct global tray ID. Falls back to raw value when no mapping is available or ambiguous. No behavior change for single-AMS printers or dual-nozzle (H2D) printers. |
||
|
|
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 |
||
|
|
e6236301b4 |
Fix phantom prints from lingering SD card files (#477)
Three bugs allowed uploaded gcode files to survive on the printer's SD card, causing firmware restarts to auto-start old prints hours later. 1. The post-print cleanup retry loop always broke after attempt 1 regardless of delete success — delete_file_async returns False on failure instead of raising, so the except-based retry never fired. 2. When start_print() failed after uploading, the file was never cleaned up since on_print_complete never fires for prints that never started. 3. Cleanup failures were logged at DEBUG level, invisible in production. |
||
|
|
608a10eabb |
Fix filament not deducted from backup spool after runout auto-switch (#459)
When a spool runs empty mid-print and the AMS auto-switches to a backup, the entire print weight was attributed to the original spool. Track tray changes during the print via tray_change_log on PrinterState, then split the 3MF weight across trays using per-layer gcode segment boundaries at print completion. Falls back to linear layer-ratio splitting when gcode data is unavailable. |
||
|
|
442059bf2a |
Fix finish photo 404 for prints started from BambuStudio (#474)
When a print was started from BambuStudio (not Bambuddy), the
auto-archive has an empty file_path. The photo save code uses
base_dir / Path("").parent which resolves correctly, but the
serve/upload/delete endpoints used (base_dir / "").parent which
goes one directory level too high — returning 404 despite the
photo existing on disk.
|
||
|
|
6884e95103 |
Fix ntfy notifications failing when server disables attachments (#466)
ntfy servers with attachments disabled reject thumbnail uploads with "attachments not allowed" (HTTP 400 / code 40014), causing the entire notification to fail. Now automatically retries without the image so the notification still gets delivered. |
||
|
|
d7a15c79bb |
Filter non-actionable HMS errors from notifications (#470)
Infrastructure/auth HMS error codes like 0500_0007 (MQTT command verification failed) triggered false-alarm printer error notifications even though they don't indicate actual print problems. - Add suppress list for non-actionable error codes: 0500_0007 (MQTT auth failure), 0500_4001 (cloud connection failure), 0500_400E (print cancelled by user) - Skip suppressed codes in the notification loop so they are still tracked in HMS state and shown in the UI, but don't fire notifications |
||
|
|
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) |
||
|
|
baf823e51c |
Fix ntfy notifications failing with "Illegal header value" (#466)
When sending notifications with image attachments (progress/error events), the message body was placed in an HTTP Message header. Messages containing newlines (e.g. "Printer: file.stl\nRemaining: 4h 52m") were rejected by httpx since HTTP headers cannot contain newline characters. Escape newlines to literal \n which ntfy renders as line breaks. |
||
|
|
1404242e0c | Fix cost tracking issues | ||
|
|
965000c3ca | Merge branch '0.2.1b2' into feature/cost_tracker | ||
|
|
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> |
||
|
|
85645ce184 | Merge branch '0.2.1b2' into feature/cost_tracker | ||
|
|
b22f091dd0 |
Fix SD card cleanup silently failing after print completion (#374)
The post-print SD card cleanup used printer_manager.get_printer(), which returns a PrinterInfo object with only name and serial_number. The code then accessed .ip_address, .access_code, and .model, which don't exist on PrinterInfo — raising AttributeError on every print completion. The outer except Exception handler silently swallowed it at debug level. Result: uploaded gcode files were never deleted from the printer's SD card root. On some printers (e.g. P1S), files left in root auto-start on power cycle, causing phantom prints. Replaced with a DB query for the Printer model, matching the pattern used everywhere else in on_print_complete(). |
||
|
|
732ab8cb6d |
Fix "Any Model" queue jobs stuck in "Waiting" after plate clear (#435)
MQTT raw data returns AMS unit and tray IDs as strings (e.g. "0"), but _build_loaded_filaments() compared them to integers without casting. After the scheduler assigned an idle printer to an "Any Model" job, it crashed computing AMS mapping with: '>=' not supported between instances of 'str' and 'int' The exception prevented the assignment from committing, so the scheduler retried every 30 seconds in an infinite loop. The job stayed in "Waiting" and the "Clear Plate" button kept reappearing. Cast ams_id and tray_id to int(), matching the pattern already used for external spool IDs on line 550. |
||
|
|
3f201594f1 |
Fix spool usage lost when spool runs empty mid-print (#459)
When a spool ran empty during a print and the AMS auto-switched to a backup, on_ams_change eagerly deleted the SpoolAssignment (fingerprint mismatch). on_print_complete then queried the now-deleted assignment and silently dropped usage. Snapshot all spool assignments into PrintSession at print start. At completion, prefer the snapshot over live DB queries in both the 3MF primary path and the AMS remain% delta fallback. Fall back to live query for backward compatibility with in-flight sessions started before upgrade. |
||
|
|
427b08f9f6 | Add archive_id to SpoolUsageHistory model and update cost calculations in usage_tracker | ||
|
|
8a935a2bce |
Fix K-profile MQTT handler race condition crash (#462)
The MQTT callback thread checked self._pending_kprofile_response before calling .set(), but the asyncio thread could clear it to None between the check and the use (TOCTOU race after get_kprofiles() timeout). Capture the event reference in a local variable to eliminate the race. |