mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-10-19 15:54:27 +02:00
145 lines
5.7 KiB
Python
145 lines
5.7 KiB
Python
"""Pydantic schemas for the unified slicer-presets endpoint.
|
|
|
|
The SliceModal pulls printer/process/filament options from three sources, in
|
|
priority order: cloud (the user's Bambu Cloud account), local (DB-backed
|
|
imported profiles), and standard (slicer-bundled stock profiles). The endpoint
|
|
returns all three lists with name-based dedup applied so each preset appears
|
|
exactly once across the response.
|
|
"""
|
|
|
|
from typing import Literal
|
|
|
|
from pydantic import BaseModel
|
|
|
|
CloudStatus = Literal["ok", "not_authenticated", "expired", "unreachable"]
|
|
|
|
|
|
class UnifiedPreset(BaseModel):
|
|
"""A single printer/process/filament preset with its source.
|
|
|
|
The ``id`` shape varies by source:
|
|
- cloud → Bambu Cloud setting_id (e.g. ``"PFUS9ac902733670a9"``)
|
|
- local → stringified DB row id from ``local_presets``
|
|
- standard → preset name as written in the bundled JSON (the slicer
|
|
resolves bundled profiles by name during inheritance walk)
|
|
|
|
The frontend treats ``id`` as opaque; the slice dispatch path uses
|
|
``(source, id)`` to fetch / pass the preset content to the sidecar.
|
|
|
|
``filament_type`` and ``filament_colour`` are populated for the filament
|
|
slot only — they let the SliceModal pre-pick a preset per plate slot in
|
|
the multi-color flow by matching against the source 3MF's per-slot type
|
|
and color. Populated when the underlying preset JSON exposes them; left
|
|
as ``None`` on bundled profiles where colour is a runtime spool attribute.
|
|
|
|
``compatible_printers`` is the slicer's own list of printer-preset names a
|
|
process / filament preset declares itself valid for. Populated for the
|
|
local tier (stored at import time); left ``None`` for cloud (no per-preset
|
|
detail is fetched — rate limits) and standard (the sidecar's bundled
|
|
listing doesn't expose it). The SliceModal uses it to filter the
|
|
process / filament dropdowns by the selected printer (#1325); when it is
|
|
``None`` the modal falls back to matching the preset name against the
|
|
``@BBL <code>`` printer-model registry.
|
|
|
|
``inherits`` is the preset a printer preset was saved from, for the local
|
|
and OrcaSlicer Cloud tiers. A printer preset saved under a name of its own
|
|
("Bambu Lab H2D 0.4 nozzle - Skew") is listed in no process's
|
|
``compatible_printers`` and its name says nothing reliable about the
|
|
model, so the SliceModal matches against this parent as well (#3250).
|
|
"""
|
|
|
|
id: str
|
|
name: str
|
|
source: Literal["orca_cloud", "cloud", "local", "standard"]
|
|
filament_type: str | None = None
|
|
filament_colour: str | None = None
|
|
compatible_printers: list[str] | None = None
|
|
inherits: str | None = None
|
|
|
|
|
|
class UnifiedPresetsBySlot(BaseModel):
|
|
"""Three slots in the order Bambu Studio / OrcaSlicer use."""
|
|
|
|
printer: list[UnifiedPreset] = []
|
|
process: list[UnifiedPreset] = []
|
|
filament: list[UnifiedPreset] = []
|
|
|
|
|
|
class UnifiedPresetsResponse(BaseModel):
|
|
"""Every tier carries its full preset list — no cross-tier dedup.
|
|
|
|
Priority order: ``local > orca_cloud > cloud > standard``. The order
|
|
drives auto-pick (first non-empty tier wins, name-lookup walks tiers
|
|
in this order, filament scoring tiebreaks by per-tier bonus) and
|
|
determines the visual rendering order of the SliceModal's optgroups,
|
|
but a name that exists in multiple tiers appears in EACH of their
|
|
groups so the user can pick any source.
|
|
|
|
``cloud_status`` / ``orca_cloud_status`` let the frontend show a banner
|
|
explaining why a cloud tier is empty when the user expected to see it
|
|
(signed out / token expired / network down). Each tier has its own
|
|
status because they can fail independently.
|
|
"""
|
|
|
|
orca_cloud: UnifiedPresetsBySlot = UnifiedPresetsBySlot()
|
|
cloud: UnifiedPresetsBySlot = UnifiedPresetsBySlot()
|
|
local: UnifiedPresetsBySlot = UnifiedPresetsBySlot()
|
|
standard: UnifiedPresetsBySlot = UnifiedPresetsBySlot()
|
|
cloud_status: CloudStatus = "ok"
|
|
orca_cloud_status: CloudStatus = "ok"
|
|
|
|
|
|
class LoadedSpoolPreset(BaseModel):
|
|
"""The filament profile Bambuddy recorded for a slot (``slot_preset_mappings``).
|
|
|
|
``tray_info_idx`` is the filament id the slot was configured with alongside
|
|
it. The SliceModal compares it with the tray's live id the same way the
|
|
slot card does, so a row that outlived a spool swap isn't trusted (#3216).
|
|
"""
|
|
|
|
preset_id: str
|
|
preset_name: str
|
|
preset_source: str
|
|
tray_info_idx: str | None = None
|
|
|
|
|
|
class LoadedSpoolTray(BaseModel):
|
|
"""One AMS slot or external holder, as the printer reports it right now."""
|
|
|
|
ams_id: int
|
|
tray_id: int
|
|
tray_type: str | None = None
|
|
tray_sub_brands: str | None = None
|
|
tray_color: str | None = None
|
|
tray_info_idx: str | None = None
|
|
# Firmware's presence bit. A non-RFID spool it can't identify is present
|
|
# (True) but has no tray_type, which reads as "loaded, unconfigured".
|
|
exists: bool | None = None
|
|
state: int | None = None
|
|
saved_preset: LoadedSpoolPreset | None = None
|
|
|
|
|
|
class LoadedSpoolUnit(BaseModel):
|
|
id: int
|
|
is_ams_ht: bool
|
|
trays: list[LoadedSpoolTray]
|
|
|
|
|
|
class LoadedSpoolPrinter(BaseModel):
|
|
id: int
|
|
name: str
|
|
# Short model name ("X1C", "H2D") — the form the slicer's @BBL tags use.
|
|
model: str | None = None
|
|
ams: list[LoadedSpoolUnit] = []
|
|
# Only holders that currently have a spool in them.
|
|
external: list[LoadedSpoolTray] = []
|
|
# How many holders the printer has, loaded or not: two on a dual-nozzle
|
|
# printer, whose holders are labelled left and right.
|
|
external_holders: int = 0
|
|
|
|
|
|
class LoadedSpoolsResponse(BaseModel):
|
|
"""Connected printers and what is loaded in them, for the SliceModal (#3172)."""
|
|
|
|
printers: list[LoadedSpoolPrinter] = []
|