Commit Graph
602 Commits
Author SHA1 Message Date
maziggy cf98daa0bb Security hardening (maziggy/bambuddy-security #10) 2026-10-06 11:48:37 +02:00
maziggy 57dd8651d8 Match a location job's trays on the printer it gets (#3239)
A job kept the AMS mapping of the printer it was made for. Moved to a
location and picked by another printer, a tray of the same material in
another colour passed the fit check, so the job printed in that colour.
The scheduler now drops a stored mapping when it assigns a job by model
or location and matches the trays on the chosen printer, by type and
colour. Moving a job from a printer to a model or location clears its
mapping and the "Print Anyway" given for that printer.

A printer without an AMS whose external spool has no filament set gave
the matcher nothing to match, so such a job went out without a mapping
and the firmware rejected it with 0700_8012. Every filament now goes to
the external spool there.
2026-10-05 11:16:41 +02:00
maziggy 6c8a821bca Add a wear cost per printing hour to printers (#694)
Print costs covered filament and energy but not the printer. Each printer
can now carry an optional wear cost per printing hour. Every run's wear is
its logged duration at that rate, stored on the print log entry; the
archive keeps the first run's wear, like energy (#1378). Failed and
cancelled runs count, reconciled runs (unknown duration) don't, and a rate
applies to new prints only.

Wear is shown on the archive card, as a hidden sortable Print Log column,
as a Quick Stats tile, in the most expensive record, in project totals and
in batch order cost, and is kept by GitHub backup and restore. Billing
still charges filament only.

New nullable columns: printers.wear_cost_per_hour, print_log_entries.wear_cost
and print_archives.wear_cost.
2026-10-05 09:29:12 +02:00
maziggy 175e683837 Give backfilled group permissions once, not on every start (#3238)
Four permission backfills in seed_default_groups ran on every start, so
removing MakerWorld, clear plate, forecasting or pipelines from a group
was undone by the next restart. Each now runs once behind a settings
flag. On the upgrade that adds the flag, a backfill whose permission the
Administrators group already held at the start of seeding is recorded as
done without running, so nothing an admin removed comes back one last
time. The Operators/Viewers block stays per-start: those system groups
can't be edited, so it only keeps them complete.
2026-10-05 08:11:55 +02:00
maziggy 6735e45563 Give library folders an owner and let admins share them (#3201)
Users with library:read_own saw every folder anyone had made, and the
folder counts and activity times included other users' files. Folders
now have an owner. A read_own user sees their own folders, shared ones,
folders holding their files and the parents leading there, and adds
files only to their own and shared folders. Admins can share a folder
with everyone. Owners can rename their folders and delete them when
everything inside is theirs.

On upgrade, a folder whose files all belong to one user becomes that
user's; every other folder is shared, so it stays visible as before.
2026-10-04 16:04:25 +02:00
maziggy 7f00816f7f List only online printers and loaded spools in the Slice dialog (#3172)
The person slicing is often away from the printer, and the useful filaments
are the ones already loaded. Two optional filters in the Slice dialog narrow
the printer profiles to the models online now and the filament profiles to
the spools loaded in them, and a Pick button fills a filament row and its
colour from a loaded spool.

A new route returns the connected printers and their slots in one call,
limited to the caller's printers. A spool is matched by the profile saved
for its slot, then that profile's copy for the selected printer, then its
brand text. Both filters are off by default, fall back to the full lists
when they would leave nothing, and never replace a profile the user chose.
2026-10-04 14:11:31 +02:00
maziggy d336bb2ad2 Merge printer-scoped access (#1727) and the queue review gate (#1620) into dev
Groups can be limited to printers and whole locations, managed on the new
Printer access page, and jobs can wait for staff review before they print.

Merging onto the current dev:
- The Printer Locations page keeps to the same access rules: a rename keeps
  its groups' access, deleting a granted location or moving printers into or
  out of one needs an admin and drops the stale grant, and a user limited to
  some printers sees and changes only their own locations.
- The overlay logo checks its token without a printer, which the stricter
  overlay check now needs and the logo route doesn't have.
2026-10-04 13:29:57 +02:00
maziggy 3480d39434 Browse a Manyfold library and import its files (issue #1471)
The MakerWorld page becomes Model Sources, with a MakerWorld tab and a
Manyfold tab. Bambuddy signs in to a self-hosted Manyfold with an OAuth
application (public read scopes), lists and searches its models with their
previews, and imports 3MF, STL and STEP files into the library, from where
they are sliced and printed like any other file.

New permissions manyfold:view and manyfold:import are granted once to the
groups that hold the matching MakerWorld permissions. The client secret is
never returned and is left out of GitHub backups. The Manyfold URL and every
redirect pass the LAN-service URL check. Old /makerworld links open the
MakerWorld tab.

Several files import at once: tick files in a model, or Select all, then
Import selected or Import all; or tick models in the grid and import all
their printable files. Files import one after another, failures don't stop
the rest, and a summary reports the outcome.
2026-10-04 13:09:25 +02:00
maziggy 6954cff3ee Turn on the chamber light while the camera is in use
A printer kept dark between uses showed a black live view and sent black
notification photos (#1655). Settings → Camera can turn the light on for
all printers or for selected ones, for the live view, notification
photos, the finish photo and the snapshot API that Home Assistant uses,
and turns it off 15 seconds after the last use. It only turns off a
light it turned on, and switching the light by hand hands it back.
Snapshots wait an adjustable delay after the light comes on. Timelapse,
the Obico check and the in-print frame bank don't switch it, since they
would make it flash.

The camera card no longer lists every printer: external cameras are
added from a searchable printer picker and only those printers are
listed, so large farms get a short page.
2026-10-04 11:26:07 +02:00
Adam Spice 3596eb0c31 Create streaming overlay tokens and import existing URLs (#3207) 2026-10-04 09:37:14 +02:00
WATARIE fa25956738 Easy management of printer locations (groups) (issue #2962)- #2970 (#2995) 2026-10-03 14:28:35 +02:00
Martin Grolmus 0a3e341584 Map each printer against its own AMS, and stop dispatching a job whose filament is not loaded (#2799) (#2803) 2026-10-03 13:28:26 +02:00
maziggyandKeybored02 12e543b1b4 Fix SpoolBuddy reading the filament type as the Bambu spool ID (#984)
The daemon took tray_uuid from tag blocks 4-5, which hold the filament
type, so every spool of one type sent the same value and the kiosk never
saved it. Read block 9, which both tags of a spool share and the AMS
reports as tray_uuid. Save it on kiosk quick-add and link in local and
Spoolman mode, and give spools added before the fix their tray_uuid when
their exact tag UID is scanned again. Drop any tray_uuid that is not a v4
UUID, so daemons that are not updated yet keep matching by tag UID.

Block 9 read based on #1200 by @Keybored02.

Co-Authored-By: Keybored02 <Keybored02@users.noreply.github.com>
2026-10-03 12:19:04 +02:00
Adam Spice 67d3e7e869 Add stream overlay logos and progress colours (#3208) 2026-10-03 09:33:13 +02:00
maziggy bff7f68106 Put back a slot's K-profile when the printer loses it (#3219) 2026-10-02 10:04:48 +02:00
maziggy 24509b17e0 Let jobs wait for staff review before they print (#1620) 2026-10-02 09:32:54 +02:00
maziggy 02e39b18b9 Configure Orca Cloud filaments with their own filament ID (#3216)
OrcaSlicer's Sync filaments finds a slot's preset by the slot's filament
ID alone. The Configure dialog looked up an Orca profile's ID in the
browser and quietly sent the generic for the material when that came back
empty, so Orca custom filaments reached the slicer as Generic and the log
showed nothing. configure now resolves the ID on the server from
orca_profile_id, follows inherits to the parent profile or the Bambu
filament it was copied from, logs the outcome and reports a fallback,
which the dialog shows as a warning.

Slot presets also store the filament ID they were written with, so the
slot card and the Configure dialog stop showing a preset once the slot is
changed from OrcaSlicer's Device tab or the printer.

Re-configuring a slot for another filament no longer carries over the old
filament's active K-profile, which switched the slot back to the old
filament.
2026-10-02 08:32:57 +02:00
maziggy fe07fbd07b Give groups whole locations and a printer access page (issue #1727)
A group can now be given locations as well as single printers: it then
reaches every printer in them, including printers added there later.
Printer access moves out of the group editor to Settings ->
Authentication -> Printer access, built for large fleets: groups and
printers searchable and filtered by location, model and access, edited
by group or by printer, saved together. "Who has access" in the printer
card menu opens it on that printer.

- group_locations table; the scope is picked printers plus printers
  whose location matches.
- Moving a printer into or out of a location a limited group has is
  admin-only, and open connections are rescoped. The edit dialog names
  the groups a move affects. Locations are trimmed on save.
- Clearing a printer's location in the edit dialog now clears it.
2026-10-02 07:30:04 +02:00
maziggy 0165dafd29 Stop firmware lookups when "Check printer firmware" is off 2026-10-01 16:27:07 +02:00
maziggy a81ac2cfb5 Keep the Announcements entry for whoever may see announcements 2026-10-01 15:59:54 +02:00
maziggy 45921b7a56 Limit groups to selected printers (issue #1727)
A group can now be limited to a set of printers. Its members see and
control only those printers. Every other printer answers 404, as if it
didn't exist.

- Groups gain restrict_printers and a group_printers table (migration
  for SQLite and Postgres). A user's printers are the union of their
  limited groups. Groups without the flag don't limit anything, a user
  in no limited group keeps every printer, and admins see all of them.
- core/printer_scope.py holds the scope. RequestPrinterScope and
  RequirePrinterPermissionIfAuthEnabled apply it to routes: printer
  routes, camera, queue and batches, archives, projects, stats, print
  log, pipeline runs, inventory and Spoolman assignments, maintenance,
  smart plugs, scheduled drying, firmware and Obico status.
- API keys, camera stream, Cam Wall, overlay and WebSocket tokens carry
  the printers of whoever created them. WebSocket broadcasts are
  filtered per connection, and the filtering fails closed.
- Scheduler: "Any <model>" jobs stay on their owner's printers. A job
  pinned to a printer its owner lost waits with a reason. Callers with
  no user identity and limited printers must queue to a specific printer.
- Group editor: new Printer access section, translated into all 15
  locales. Saving a system group no longer resends unchanged
  permissions, which the backend refused.
2026-10-01 14:47:40 +02:00
maziggy 6968433d70 Show the job the scheduler starts next on the printer card (#3200) 2026-10-01 12:58:13 +02:00
maziggy 5eb37cd41c Show announcements from the Bambuddy maintainers
Fetch a signed feed.json from the public bambuddy-notifications repo on
GitHub at startup and every 6 hours. Nothing about the install is sent;
targeting (version, beta channel, install type) is decided locally.

- Ed25519 against a key built into the app; an older serial is refused so a
  withdrawn message can't come back. The feed replaces the stored list, and
  a failed or rejected fetch keeps the last good one.
- Sidebar entry above System with an unread count, a slide-over list, and a
  banner for unread important/critical messages. Read state per user.
- Admins by default; Settings > General > Updates can show them to all
  users or switch them off, which also stops the fetch.
- Plain text only; links to github.com and bambuddy.cool only.
2026-10-01 10:45:06 +02:00
maziggy 1cc4bae5d2 Report a refused RFID refresh, and fall back to M620 R (#3206)
ams_get_rfid was published and reported as success without reading the
printer's answer. X1Plus on base 01.08.02.00 answers FAIL / ERROR STATE,
so the user saw "Refreshing" and the K profile was re-applied to a slot
that was never read.

- Wait for the ams_get_rfid answer (matched by sequence_id).
- On a refusal from an idle X1/P1/A1, send the legacy M620 R<ams*4+slot>
  gcode Bambu Studio uses for those models, AMS units 0-3 only. Never
  during a job, never on newer-protocol models; printers that accept
  ams_get_rfid never see it.
- Refused: the route returns 400 with the printer's reason and no PA
  re-apply is scheduled. No answer still counts as accepted.
- Log the answers at INFO so refusals reach support bundles.
2026-10-01 09:40:00 +02:00
adman234 b67c9b572c Add "Combine to 3MF" for slicing several STLs on one plate (#3162) 2026-10-01 08:11:19 +02:00
maziggy e9627e44a2 Start queued jobs in list order, whether pinned or "Any <model>" (#3200) 2026-09-30 15:55:05 +02:00
maziggy 8b5d8e3170 Add layers, job id, HMS faults and serial to the API-key printer status (#2919) 2026-09-30 11:45:31 +02:00
maziggy bf7fc67dc0 Choose what a spool label shows, preview it, and save it as PNG (#2981, #2980) 2026-09-30 11:08:05 +02:00
Kouki Ojima cb924e5c4a Match a Bambu roll to its own product line, not just its colour (issue #2907) (#2944) 2026-09-30 10:15:42 +02:00
maziggy 29e6d28205 Resolve LDAP groups on lldap and OpenLDAP (#3197)
lldap and OpenLDAP's memberof overlay omit memberOf from "*", so every
lldap login fell through to the default group. Request memberOf by name
when the schema defines it, and on non-AD directories also search the
directory root for groupOfNames/groupOfUniqueNames entries listing the
user, since groups often sit outside the user search base and the
overlay tracks only one group class.

Also: skip ldap3's anonymous schema read after StartTLS, which AD and
Samba AD reject, so StartTLS works there; reword a server's StartTLS
refusal with an LDAPS hint; stop the bundle sanitizer masking part of
an OID as an IP; skip the sync right after auto-provisioning so the
default-group warning logs once.
2026-09-30 09:46:54 +02:00
maziggy 2f7f17a891 Use the Spoolman spool's own initial_weight as its label weight (#3194)
Spoolman keeps a full spool's net weight on the spool (initial_weight)
and falls back to the filament's weight, but Bambuddy read only the
filament, so a 250 g spool of a 1000 g filament showed and synced as
1000 g. The list, weigh, AMS sync, SpoolBuddy scale, remain-% tracking,
fill bar and cost now share one lookup. Create writes initial_weight,
and a label-weight edit writes it instead of patching or duplicating the
filament. The spool form's cost per kg is converted at the spool's size
to and from Spoolman's per-spool price.
2026-09-30 09:12:45 +02:00
maziggy c145b3ebc1 Use the vendor's empty spool weight as tare in Spoolman mode (#3195)
Spoolman resolves a spool's tare from the spool, then the filament, then
the vendor's empty_spool_weight. Bambuddy skipped the vendor and fell
back to 250 g, so weighing a spool whose tare was set only on its vendor
gave the wrong remaining weight. The inventory weigh action, the
SpoolBuddy scale and the displayed core weight now share one lookup, and
"keep old weight" on a filament change stamps a vendor-inherited tare.
2026-09-30 08:43:21 +02:00
maziggy ad3b5f1982 Map the P-series model codes to the right printers
C11 is the P1P, C12 the P1S, C13 the X1E and N7 the P2S, as the virtual
printer and a real P1P 3MF already say. The frontend map had them shifted,
so discovery pre-filled a P1S as a P1P and an X1E as a P2S. The backend
map read C11/C12 as X1C/X1 and lacked N7, the firmware check sent C13 to
the P2S line, and the capability lists never matched BL-P001 because
their lookup strips the dash.

-----

Post work PR #3134
2026-09-29 16:43:04 +02:00
Thomansky 1c316e2ad6 Answer the outcome prompt by reacting to the Telegram message (#3129) 2026-09-29 16:06:51 +02:00
William Faircloth d04514c842 Sync OIDC provider groups to BamBuddy groups on every login (issue #3107) (#3122) 2026-09-29 15:49:44 +02:00
Thomansky 71d4b2f70d Material number as a first-class spool field (#2994) 2026-09-29 15:11:50 +02:00
maziggy 926957f648 Post work-2 PR #2990 2026-09-29 14:54:36 +02:00
Thomansky 226826f3bd File Manager previews: fullscreen and zoom, image previews, double-click to open (#2990) 2026-09-29 14:27:19 +02:00
maziggy 3497cf0d46 Hold an automatic slot unlink until the slot stays empty (issue #3186) 2026-09-29 09:37:04 +02:00
sgiffhorn 89dde591f2 Resolve dispatch plate_id from the archive instead of assuming 1 (#2951) 2026-09-28 16:06:41 +02:00
Thomansky 053cfa73ad Suppliers as a managed list with per-spool assignments (#2996) 2026-09-28 15:14:07 +02:00
Kouki Ojima b6521e93f8 Let a spool keep its own empty weight (issue #2908) (#3011) 2026-09-28 14:48:04 +02:00
maziggy 63e987e591 Paint SpoolBuddy spools with their extra colours and effect (issue #3033) 2026-09-28 14:27:21 +02:00
maziggy 0cc7cf0f36 Refuse null for number and on/off settings, and read bad rows as the default (issue #2518)
A PUT /settings with null for a number setting stored the literal
"None". From then on int()/float() raised inside the response builder,
and every settings read returned 503 until the row was fixed by hand.

Explicit null for any boolean or numeric setting is now refused with a
422 that names the keys, and nothing in that request is saved. A numeric
row that does not parse reads back as its default with a warning, so an
install that already stored one recovers. The typed-key lists moved to
module constants so the save check and the read path share them.
2026-09-28 11:32:02 +02:00
maziggy 89c4ac5583 Post work PR #2956
-----

Give each test worker its own scratch folder in the #3025 and #3029 tests (issue #3025)

Both modules wrote into one shared folder under settings.base_dir and deleted
it after every test. Under xdist, one worker's cleanup removed files another
worker was still serving, so tests failed at random with a 404. The folder name
now includes the process ID.
2026-09-28 10:48:51 +02:00
Kouki Ojima 4fdc55b884 Let the two stock alert toggles reach the database (issue #2945) (#2956) 2026-09-28 10:21:46 +02:00
Kouki Ojima ff07a82358 Keep the consumed-counter reset out of Spoolman's own numbers (issue #2906) (#2939) 2026-09-28 09:58:16 +02:00
maziggy 6855d65d12 Let other applications send messages through the notification channels
POST /notifications/app-message delivers an app's message to every channel
with the new "Messages from connected apps" switch on (off by default),
through quiet hours, the digest and the log. API keys need the new "Send
notifications" permission, and their owner notifications:update; plain text,
http(s) links, 20 messages a minute per key. The electricity-price door and
this one now share one scoped-key check. /queue?batch=<id> opens and
highlights one batch order.
2026-09-27 12:45:50 +02:00
Adam Spice 858f8c772f feat: add optional printer model to stream overlay (#3099) 2026-09-27 12:04:05 +02:00
maziggy b9e3fdc84f Post work PR #3047
fix(#1898): keep Telegram link previews, and keep the outcome prompt's failures its own

Four follow-ups to the post-print outcome confirmation merged in #3047.

Telegram: link previews were switched off for every message rather than
only for the outcome prompt, so a print_complete template carrying
{finish_photo_url} lost its photo preview whenever the photo was too
large to attach. _send_telegram now takes link_preview, and only the
prompt turns it off, as the Slack unfurl change already did.

Archives: Reset left the new Unconfirmed filter on, so the list stayed
narrowed and the button seemed to do nothing.

Print start: when the external-print check hit a failed statement, it
rolled back the caller's whole transaction, which expired the printer
and the just-created archive; on an async session the next read of
either raises, and the start notification, energy reading and timelapse
baseline were skipped. The check's reads now run in a savepoint, and a
failed flag write reloads the archive and printer after its rollback.

Print complete: a failed outcome prompt left the notification session
needing a rollback, so the per-user print email sent on it next failed
too. The dispatch now rolls back on failure.
2026-09-26 15:59:03 +02:00