Commit Graph
942 Commits
Author SHA1 Message Date
maziggy 9cbd66593e Show Spoolman fill level for AMS Lite and external spools (#293)
AMS Lite units (A1 series) have no weight sensor and always report 0%
fill level. When a spool is linked to Spoolman with weight data, use
Spoolman's remaining weight as a fallback. External spools also show
fill level from Spoolman data instead of always showing unknown.

Backend: Enrich GET /spoolman/spools/linked response with
remaining_weight and filament_weight alongside spool ID.

Frontend: Add getSpoolmanFillLevel() helper. Update regular AMS, HT
AMS, and external spool fill computations to use Spoolman fallback
when AMS reports 0%. Show "(Spoolman)" indicator in hover card when
fill data comes from Spoolman.
2026-02-08 08:47:18 +01:00
maziggy e073e494c7 Fix H2D Pro wrong nozzle routing causing extrusion motor overload (#245)
H2D Pro firmware interprets use_ams as a nozzle index when sent as
integer (1 = deputy nozzle) instead of boolean. Bambu Studio sends
use_ams: true (boolean) while using integers for calibration fields.
Bambuddy was converting all boolean fields to integers for H2D series,
routing filament to the deputy nozzle instead of main, causing
extrusion motor overload at ~75% print completion.

Keep use_ams as boolean for all printers, matching Bambu Studio format.
2026-02-08 08:18:52 +01:00
maziggy d888b8e902 Updated CHANGELOG 2026-02-08 07:59:59 +01:00
MartinNYHC 00d60d4bb8 Merge pull request #295 from bambuman/bug/spoolman-creates-dublicate-spools
bug/spoolman-creates-dublicate-spools
2026-02-08 07:55:07 +01:00
maziggy cf19ac8d39 Added two steps to the docker-test job in ci.yml 2026-02-08 07:53:32 +01:00
MartinNYHC 6ad02d1c59 Merge pull request #294 from bambuman/feature/home-assistant-env-vars
[Feature]: Configure home assistant via environment variables
2026-02-08 07:45:07 +01:00
bambuman c04df8ceb9 Add retry logic and connection resilience to Spoolman sync
Implements retry mechanism to handle intermittent network errors when
fetching spools cache for AMS sync operations.

Changes:
- Add retry logic to get_spools() with 3 attempts and 500ms delay
- Configure httpx client with connection pool limits to prevent stale
  connection reuse (max_keepalive_connections=5, keepalive_expiry=30s)
- Recreate client on connection errors (ReadError, RemoteProtocolError)
- Abort sync operations if cache fetch fails after all retries
- Update on_ams_change, sync_single_printer, and sync_all_printers to
  handle cache fetch failures gracefully

This addresses ReadError(ClosedResourceError()) failures that occurred
intermittently when Spoolman closed idle connections or connection
pooling reused stale connections.

Testing:
- Added 4 new unit tests for retry behavior
- All 1018 tests passing
2026-02-07 23:11:27 +02:00
bambuman deab81287f Optimize AMS Spoolman sync performance with spool caching
- Add cached_spools parameter to find_spool_by_tag, find_spools_by_location_prefix, sync_ams_tray, and clear_location_for_removed_spools
- Fetch spools once before loops in on_ams_change, sync_single_printer, and sync_all_printers endpoints
- Cache newly created spools during sync to avoid duplicate API calls
- Add 5 unit tests for caching functionality (all passing)
- Reduce redundant API calls when syncing multiple AMS trays
- Improve sync performance for users with large spool databases
- Maintain backward compatibility with optional cached_spools parameters
2026-02-07 22:29:52 +02:00
MartinNYHC 2cff40f2f1 Merge branch '0.1.9b' into feature/home-assistant-env-vars 2026-02-07 19:55:11 +01:00
bambuman 07d9db43cb Localize Home Assistant environment variable UI text
- Add translation keys for environment-managed labels
- Replace hardcoded English text with i18n function calls
- Add translations for English, German, and Japanese
- Keys: environmentManagedLabel, autoEnabledViaEnv, urlFromEnvReadOnly, tokenFromEnvReadOnly

Addresses PR feedback on #283
2026-02-07 20:25:48 +02:00
bambuman eda1f5a9e7 Home Assistant: add environment variable configuration support
- Add HA_URL and HA_TOKEN environment variables for automatic HA
  integration configuration in HA add-on deployments
- Environment variables always override database settings with
  non-negotiable precedence; database values preserved for fallback
- Auto-enable integration when both env vars are set; partial config
  (one env var) uses database enable state without auto-enabling
- Add centralized get_homeassistant_settings() function following
  Spoolman pattern; replace direct database queries across codebase
- Add ha_url_from_env, ha_token_from_env, ha_env_managed fields to
  AppSettings schema to inform frontend about configuration source
- UI shows read-only fields with lock icons and "(Environment Managed)"
  labels when env-controlled; toggle shows auto-enable badge
- Add comprehensive test coverage: 9 integration + 8 unit tests

Closes #283
2026-02-07 19:01:04 +02:00
maziggy 8511ce2c47 Add camera view controls: chamber light toggle & skip objects (fixes #291)
- Extract SkipObjectsModal from PrintersPage into reusable component
- Add chamber light toggle and skip objects buttons to EmbeddedCameraViewer
  and CameraPage header bars
- Add printerStatus query to camera views (React Query deduplicates with
  existing PrintersPage query)
- Fix camera/stop 401 when auth enabled: replace sendBeacon with
  fetch + keepalive + auth headers in both camera components
- Add camera.chamberLight i18n key (en, de, ja)
- Add AuthProvider to CameraPage test wrapper
2026-02-07 17:09:44 +01:00
maziggy 8944943981 Allow hostnames for printers in addition to IPv4 addresses (fixes #290)
Users with local DNS can now add printers using hostnames like
printer.local or my-printer.home.lan. Updated backend schema
validation, database column width, frontend form patterns/placeholders,
and i18n labels across all locales. Added integration tests for
hostname and FQDN creation plus invalid hostname rejection.
2026-02-07 16:16:43 +01:00
maziggy f1fc8b60ed Updated README and CHANGELOG 2026-02-07 15:51:48 +01:00
maziggy 42fc819efc Add proxy mode for virtual printer (cross-LAN slicer support)
Enable Bambu Studio on a remote network to print through BamBuddy
acting as a TLS-terminating proxy for both MQTT and FTP connections.

- Add TLSProxy base class and FTPTLSProxy with PASV response rewriting,
  EPSV→PASV translation, PROT P/C tracking, and one-shot data proxies
- Add SlicerProxyManager to coordinate per-slicer MQTT + FTP proxy pairs
- Support additional SAN IPs in certificate generation for proxy mode
- Broadcast SSDP on LAN B so slicers discover the proxy as a printer
- Narrow FTP passive port range to 50000-50100 with retry logic
- Expose proxy ports (8883, 9990, 50000-50100) in Dockerfile
- Document passive port range in docker-compose.yml
2026-02-07 15:34:12 +01:00
maziggy 70622e6e53 Add proxy mode for virtual printer (cross-LAN slicer support)
Enable Bambu Studio on a remote network to print through BamBuddy
acting as a TLS-terminating proxy for both MQTT and FTP connections.

- Add TLSProxy base class and FTPTLSProxy with PASV response rewriting,
  EPSV→PASV translation, PROT P/C tracking, and one-shot data proxies
- Add SlicerProxyManager to coordinate per-slicer MQTT + FTP proxy pairs
- Support additional SAN IPs in certificate generation for proxy mode
- Broadcast SSDP on LAN B so slicers discover the proxy as a printer
- Narrow FTP passive port range to 50000-50100 with retry logic
- Expose proxy ports (8883, 9990, 50000-50100) in Dockerfile
- Document passive port range in docker-compose.yml
2026-02-07 15:17:19 +01:00
maziggy 4dc3aaea5b Fix energy cost showing 0.00 in "Total Consumption" mode (fixes #284)
homeassistant_service.get_energy() was called without first configuring
the service with the HA URL and token, so it returned None for all
Home Assistant smart plugs. Added configure() call before the plug
loop, matching the pattern used in main.py and smart_plugs.py.
2026-02-07 11:08:18 +01:00
maziggy cfd5dd66e5 Fix filament usage charts inflated by quantity multiplier (fixes #229)
filament_used_grams already represents the total for the entire print
job. The daily, weekly, and filament-type charts were multiplying it
by quantity, e.g. a 26-object print using 126g was counted as 3,276g.

Removed the erroneous `* qty` from three aggregations in
FilamentTrends.tsx. Monthly comparison and summary cards were already
correct.

Fixes #229
2026-02-07 11:02:05 +01:00
maziggy f2468077fe Add mock FTPS server and comprehensive FTP test suite (67 tests)
FTP bugs have been the #1 recurring issue across releases (0.1.8+).
This adds a real implicit FTPS mock server and 67 test cases covering
every known failure mode — connection, upload, download, delete, storage
info, model-specific SSL behavior, async wrappers, and failure injection.

New files:
- mock_ftp_server.py: implicit FTPS server on pyftpdlib with failure injection
- conftest.py: FTP test fixtures (certs, server, client factory)
- test_bambu_ftp.py: 67 tests across 10 test classes

Also adds pyOpenSSL to requirements-dev.txt (needed by pyftpdlib
TLS_FTPHandler in the Docker test image).
2026-02-07 10:55:05 +01:00
maziggy 600f4261fc Bumped version 2026-02-07 10:19:21 +01:00
MartinNYHC 833a0c62d2 Merge pull request #289 from maziggy/0.1.8.1
Fix FTP download reporting success on 0-byte files
2026-02-07 10:09:31 +01:00
MartinNYHC b27f198386 Merge branch 'main' into 0.1.8.1 2026-02-07 10:06:57 +01:00
maziggy 70e7cba5e7 Fix FTP download reporting success on 0-byte files
download_to_file() returned True when retrbinary transferred 0 bytes
without raising an exception. This caused the /cover endpoint to hit
the empty file check and raise HTTP 500 instead of retrying or
returning 404.

Now treats 0-byte downloads as failures, allowing the cover endpoint's
retry logic to work and falling back to 404 if all attempts fail.
2026-02-07 10:04:17 +01:00
MartinNYHC 6e3cfae9e2 Merge pull request #288 from maziggy/0.1.8.1
v0.1.8.1
v0.1.8.1
2026-02-07 09:43:20 +01:00
MartinNYHC e87a41795c Merge branch 'main' into 0.1.8.1 2026-02-07 09:40:40 +01:00
maziggy c77c9c38fd Fix critical FTP upload failure and revert dangerous exception narrowing
The CodeQL cleanup in "Housekeeping" (2b11efd) bulk-narrowed except
clauses across 50+ files, breaking FTP uploads on ALL printer models.
ftplib.error_perm (550 errors) is not a subclass of ftplib.error_reply,
so diagnose_storage() CWD failures escaped the handler and prevented
STOR from ever executing — causing 100% upload failure and HTTP 500s
on /api/v1/archives/{id}/reprint and /api/v1/library/files/{id}/print.

FTP fixes:
- Remove diagnose_storage() from upload hot path
- Change all except (OSError, ftplib.error_reply) to
  except (OSError, ftplib.Error) across bambu_ftp.py

Exception handling reverts (9 files):
- Revert narrowed except clauses back to except Exception in route
  handlers and service code where broad catches are intentional
  defensive programming (archive parsing, HTTP clients, 3MF/ZIP
  processing, Home Assistant, firmware checks)
- Keep narrow exceptions only where safe (single-op blocks like
  int(), file.unlink(), socket.close())
- Remove unused XMLParseError imports from archive.py, threemf_tools.py

Version system:
- Add 4-segment version support (e.g. 0.1.8.1) for patch releases
- Bump version to 0.1.8.1

Closes #287
2026-02-07 09:29:51 +01:00
maziggy 4b46e443dc Fix critical FTP upload failure and revert dangerous exception narrowing
The CodeQL cleanup in "Housekeeping" (2b11efd) bulk-narrowed except
clauses across 50+ files, breaking FTP uploads on ALL printer models.
ftplib.error_perm (550 errors) is not a subclass of ftplib.error_reply,
so diagnose_storage() CWD failures escaped the handler and prevented
STOR from ever executing — causing 100% upload failure and HTTP 500s
on /api/v1/archives/{id}/reprint and /api/v1/library/files/{id}/print.

FTP fixes:
- Remove diagnose_storage() from upload hot path
- Change all except (OSError, ftplib.error_reply) to
  except (OSError, ftplib.Error) across bambu_ftp.py

Exception handling reverts (9 files):
- Revert narrowed except clauses back to except Exception in route
  handlers and service code where broad catches are intentional
  defensive programming (archive parsing, HTTP clients, 3MF/ZIP
  processing, Home Assistant, firmware checks)
- Keep narrow exceptions only where safe (single-op blocks like
  int(), file.unlink(), socket.close())
- Remove unused XMLParseError imports from archive.py, threemf_tools.py

Closes #287
2026-02-07 09:20:06 +01:00
maziggy 2b11efd882 Housekeeping 2026-02-06 16:36:08 +01:00
maziggy 8e9d252ad3 Housekeeping 2026-02-06 16:35:46 +01:00
maziggy aa3482e48b Add printer_model to 18 FTP call sites for A1/A1 Mini, PS1 compatibility
Several FTP operations (file browser, timelapse scan, storage info,
cover download, skip objects, etc.) were missing the printer_model
parameter. Without it, A1/A1 Mini and PS1 printers can't use the prot_p/prot_c
auto-detection and fallback logic, causing FTP failures on these models
when the mode cache isn't already populated.
2026-02-06 16:29:01 +01:00
maziggy c15fb83af8 Updated CONTRIBUTING.md 2026-02-06 14:56:05 +01:00
maziggy 92308a8afa Updated CONTRIBUTING.md 2026-02-06 14:55:46 +01:00
maziggy 22187ac363 Updated README 2026-02-06 14:16:27 +01:00
maziggy 0d0ed0e4c1 Updated README 2026-02-06 14:15:49 +01:00
maziggy 5803c8ceb1 Added missing toast messages to Spoolman settings 2026-02-06 14:12:12 +01:00
maziggy dccf85de74 Bumped version 2026-02-06 13:48:16 +01:00
MartinNYHC 1fd765017a Merge pull request #282 from maziggy/0.1.8
v0.1.8
v0.1.8
2026-02-06 13:36:12 +01:00
MartinNYHC 3c3781be32 Merge branch 'main' into 0.1.8 2026-02-06 13:33:51 +01:00
maziggy 74e84277cf Add CodeQL advanced setup workflow with accepted-risk exclusions 2026-02-06 13:25:23 +01:00
maziggy cfc97f8cc4 Add CodeQL advanced setup workflow with accepted-risk exclusions 2026-02-06 13:23:44 +01:00
maziggy dec89186e9 Updated CHANGELOG 2026-02-06 13:08:32 +01:00
maziggy 01cb23ee85 Add .trivyignore to suppress Dockerfile USER directive finding (DS-0002)
Bambuddy runs as a single-host Docker container where root is needed
for device access and FFmpeg. Trivy picks up the file automatically.
2026-02-06 13:05:35 +01:00
maziggy 7b90c743c2 Strip explanatory text from nosec comments to silence Bandit warnings
Bandit parses all words after `# nosec BXXX` as test IDs, producing
~35 "not a test name or id" warnings. Trim to just `# nosec BXXX`.
2026-02-06 12:57:37 +01:00
maziggy 598cc699d4 Add CodeQL query suites for zero-finding scans and fix remaining security issues
- Create .codeql/python-bambuddy.qls excluding 14 accepted-risk rule
  categories (all reviewed and documented with justifications)
- Create .codeql/javascript-bambuddy.qls excluding false-positive
  XSS findings (generated coverage file + blob URL in audio src)
- Fix stack trace exposure in updates.py: replace str(e) with generic
  error messages in HTTP responses (2 locations)
- Fix SSRF in homeassistant.py: add _validate_url() with scheme
  validation and metadata-service blocking
- Fix SSRF in tasmota.py: add _validate_ip() blocking loopback and
  link-local addresses
- Add --threads=0 to all CodeQL CLI commands in test_security.sh for
  parallel query evaluation (67s → 43s wall clock)
2026-02-06 12:51:17 +01:00
maziggy 93f416b922 Fix trivial conditionals, commented-out code, and dead variables (CodeQL)
Simplify always-true authEnabled ternary and localSettings truthiness
checks in SettingsPage.tsx. Remove commented-out auth re-setup guard
and its dead _existing_setting/_user_count queries from auth.py.
Add clarifying comments to firmware_check.py api_key logs (model
identifier, not a secret).
2026-02-06 12:32:29 +01:00
maziggy 42fd6d95a0 Fix unused globals and redundant JS conditions (CodeQL)
Remove vestigial _debug_logging_enabled and _debug_logging_enabled_at
globals from support.py (written but never read; DB is queried directly).
Simplify hue classification in PrintersPage.tsx and colors.ts by removing
always-true h < 345 checks and dead 'Unknown' fallbacks. Narrow
getWifiStrength param type to remove always-false null guard.
2026-02-06 12:26:38 +01:00
maziggy b99536cc33 Remove unused imports, variables, and fix minor CodeQL findings
- Remove 28 unused imports across 22 test files
- Prefix 4 unused local variables with _ in app code
  (archives, bambu_mqtt, main) and remove 1 dead store
- Consolidate import/import-from in test_plate_detection.py
- Fix unreachable statement in test_archive_service.py
- Simplify redundant comparison in timelapse_processor.py

Resolves ~50 CodeQL py/unused-import, py/unused-local-variable,
py/import-and-import-from, py/unreachable-statement, and
py/redundant-comparison findings.
2026-02-06 12:19:17 +01:00
maziggy 5dcabbdda8 Remove 30 redundant function-level imports
These modules were already imported at the top of each file.
Removes re-imports of re, json, zipfile, and logging from
inside functions in archive.py, library.py, main.py,
printers.py, support.py, and test_library_api.py.

Resolves all 30 CodeQL py/repeated-import findings.
2026-02-06 12:06:51 +01:00
maziggy 5b0a985da2 Add explanatory comments to 265 empty except blocks
CodeQL flags except blocks where `pass` has no comment explaining
why the exception is silently ignored (py/empty-except rule).

Added context-specific comments to all 265 instances across 31 files:
- database.py (~112): ALTER TABLE migrations — "Already applied"
- archive/library/3MF parsing (~64): "Skip unparseable metadata"
- virtual_printer network cleanup (~32): "Best-effort socket cleanup"
- discovery/SSDP (~13): "SO_REUSEPORT not available" / socket cleanup
- bambu_ftp/mqtt (~13): FTP cleanup, JSON decode, signal parsing
- remaining routes/services (~31): context-specific comments
2026-02-06 11:58:38 +01:00
maziggy a0133fb43b Fix safe security findings: hashlib, log injection, broad excepts, bandit suppressions
- Add usedforsecurity=False to MD5 (AMS fingerprint) and SHA1 (git blob
  hash) calls to silence Bandit B303 / CodeQL weak-crypto findings
- Convert ~996 f-string logging calls to parameterized %s-style across
  55 files to prevent log injection (Bandit G201 / CodeQL log-injection)
- Narrow ~199 broad except Exception blocks to specific types:
  OperationalError for DB migrations, OSError for network/file cleanup,
  (OSError, ftplib.error_reply) for FTP, and targeted tuples for
  ZIP/XML/JSON parsing — 36 intentionally left broad (mixed async,
  re-raise patterns)
- Add # nosec comments to 9 known-safe lines (0.0.0.0 virtual printer
  binds, ftplib imports) and exclude backend/tests/ from bandit scan
- Bandit now reports 0 medium/high findings
2026-02-06 11:45:12 +01:00