mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-10-22 03:49:18 +02:00
feat(print-options): add "Auto" state to bed levelling, flow & nozzle-offset calibration
Bed levelling, flow calibration, and nozzle-offset calibration were on/off only, so the sole way to run bed levelling was to force a full level before every print. Bambu Studio has always offered a third "Auto" state that lets the printer skip the calibration when it was done recently -- the state most users actually want. Make these three options tri-state (off/on/auto), defaulting to auto, and leave vibration/layer-inspect/timelapse as on/off (Bambu Studio exposes no auto for those). Wire encoding follows Bambu Studio's source exactly: each option sends a JSON bool (true only for "on") plus a companion int -- off=0, on=1, auto=2. The bool fields stay booleans (the #1478 H2S regression); only the companion int widened from {0,1} to {0,1,2}. #1721's observation that stage 8/39 stays queued when sending 2 is the auto contract (queued, skipped at runtime if recent), not a broken "off". - schemas: TriState = Literal[off/on/auto] with a BeforeValidator coercing legacy bool / 0-1 / true-false so old clients and un-migrated rows validate - model + migration: boolean columns -> String; SQLite via column affinity + data backfill, PostgreSQL via ALTER COLUMN TYPE guarded on information_schema (verified on both dialects); settings rows normalised true/false -> on/off - MQTT: start_print takes the tri-state strings and emits the paired bool+int - Virtual Printer: reconstructs the slicer's auto/on/off from the int companion (auto_bed_leveling / extrude_cali_flag) in both capture paths - frontend: CalibrationMode type; off/auto/on segmented controls in the print dialog, queue bulk-edit, and Settings -> Workflow; calibrationMode_* strings in all 11 locales
This commit is contained in:
@@ -128,6 +128,31 @@ _SLICER_OPTIONS_WAIT_TIMEOUT = 5.0
|
||||
# scheduler tick interval before dispatch picks the item up.
|
||||
_RECENT_QUEUE_ITEM_TTL = 30.0
|
||||
|
||||
# BambuStudio's tri-state calibration options (bed_leveling / flow_cali /
|
||||
# nozzle_offset_cali) travel on the project_file command as a bool plus an int
|
||||
# companion — off=0, on=1, auto=2 (getValueInt parity). The int carries the full
|
||||
# state; the bool is true only for "on".
|
||||
_TRISTATE_INT = {0: "off", 1: "on", 2: "auto"}
|
||||
|
||||
|
||||
def _tristate_from_slicer(data: dict, bool_field: str, int_field: str) -> str | None:
|
||||
"""Reconstruct off/on/auto from a captured slicer project_file dict.
|
||||
|
||||
Prefer the int companion (auto_bed_leveling / extrude_cali_flag / etc.) which
|
||||
carries all three states; fall back to the bool field (on/off only); return
|
||||
None when the slicer sent neither so the caller can use its own default.
|
||||
"""
|
||||
if int_field in data:
|
||||
try:
|
||||
resolved = _TRISTATE_INT.get(int(data[int_field]))
|
||||
except (TypeError, ValueError):
|
||||
resolved = None
|
||||
if resolved is not None:
|
||||
return resolved
|
||||
if bool_field in data:
|
||||
return "on" if bool(data[bool_field]) else "off"
|
||||
return None
|
||||
|
||||
|
||||
def _get_serial_for_model(model: str, serial_suffix: str) -> str:
|
||||
"""Get serial number for the given model and suffix."""
|
||||
@@ -411,9 +436,16 @@ class VirtualPrinterInstance:
|
||||
# `nozzles_info` is intentionally not stamped — column kept for
|
||||
# legacy rows but never written; see PrintQueueItem.nozzles_info.
|
||||
patch: dict = {}
|
||||
# Tri-state options (off/on/auto) — reconstruct from the int companion.
|
||||
for bool_field, int_field, column in (
|
||||
("bed_leveling", "auto_bed_leveling", "bed_levelling"),
|
||||
("flow_cali", "extrude_cali_flag", "flow_cali"),
|
||||
):
|
||||
resolved = _tristate_from_slicer(data, bool_field, int_field)
|
||||
if resolved is not None:
|
||||
patch[column] = resolved
|
||||
# On/off options.
|
||||
for mqtt_field, column in (
|
||||
("bed_leveling", "bed_levelling"),
|
||||
("flow_cali", "flow_cali"),
|
||||
("vibration_cali", "vibration_cali"),
|
||||
("layer_inspect", "layer_inspect"),
|
||||
("timelapse", "timelapse"),
|
||||
@@ -714,6 +746,19 @@ class VirtualPrinterInstance:
|
||||
def _bool_setting(value: str | None, default: bool) -> bool:
|
||||
return value.lower() == "true" if value is not None else default
|
||||
|
||||
def _tristate_setting(value: str | None, default: str) -> str:
|
||||
"""Tri-state workflow default, coercing legacy true/false rows."""
|
||||
if value is None:
|
||||
return default
|
||||
low = value.strip().lower()
|
||||
if low in ("on", "off", "auto"):
|
||||
return low
|
||||
if low in ("true", "1"):
|
||||
return "on"
|
||||
if low in ("false", "0"):
|
||||
return "off"
|
||||
return default
|
||||
|
||||
def _slicer_or(field_mqtt: str, settings_default: bool) -> bool:
|
||||
"""Slicer's MQTT value if present, else the settings default.
|
||||
|
||||
@@ -725,13 +770,27 @@ class VirtualPrinterInstance:
|
||||
return bool(slicer_opts[field_mqtt])
|
||||
return settings_default
|
||||
|
||||
def _slicer_tristate(bool_field: str, int_field: str, settings_default: str) -> str:
|
||||
"""Slicer's tri-state (off/on/auto) if present, else the default."""
|
||||
if slicer_opts is not None:
|
||||
resolved = _tristate_from_slicer(slicer_opts, bool_field, int_field)
|
||||
if resolved is not None:
|
||||
return resolved
|
||||
return settings_default
|
||||
|
||||
# Note the MQTT field names differ from Bambuddy's column
|
||||
# names: MQTT uses `bed_leveling` (single L) while the
|
||||
# column / settings key use `bed_levelling` (double L).
|
||||
bed_levelling = _slicer_or(
|
||||
"bed_leveling", _bool_setting(await get_setting(db, "default_bed_levelling"), True)
|
||||
bed_levelling = _slicer_tristate(
|
||||
"bed_leveling",
|
||||
"auto_bed_leveling",
|
||||
_tristate_setting(await get_setting(db, "default_bed_levelling"), "auto"),
|
||||
)
|
||||
flow_cali = _slicer_tristate(
|
||||
"flow_cali",
|
||||
"extrude_cali_flag",
|
||||
_tristate_setting(await get_setting(db, "default_flow_cali"), "auto"),
|
||||
)
|
||||
flow_cali = _slicer_or("flow_cali", _bool_setting(await get_setting(db, "default_flow_cali"), False))
|
||||
vibration_cali = _slicer_or(
|
||||
"vibration_cali", _bool_setting(await get_setting(db, "default_vibration_cali"), True)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user