fix(printer): H2S could not start prints without AMS — was misclassified as dual-nozzle (#1386)

H2S is single-nozzle (nozzle_count=1 across 9+ stored support bundles
  and the reporter's diagnostic) but had been added to the H-family model
  gate in start_print_job. That single flag controlled both the firmware
  bool->int format (legitimately needed for the whole H-family, including
  H2S) and the dual-nozzle external-spool routing (correct only for actual
  dual-extruder printers).

  With no AMS attached and an external-spool slot (tray_id=254), the
  dual-nozzle branch wrote ams_id=254 into ams_mapping2 instead of the
  canonical 255 — exactly the failure the comment six lines above warns
  against. Firmware rejected the dispatch with 07FF_8012 "Failed to get
  AMS mapping table". The use_ams=False fallback was also being skipped
  because the H-family bypass was meant for dual-nozzle routing.

  A second site at bambu_mqtt.py:3987 and its sibling at kprofiles.py:119
  detected dual-nozzle by serial prefix ("094", "20P9", "31B8B"). H2S
  shares prefix "094" with H2D, so prefix detection misclassified it too.

  Split the conflated flag into two:

  - is_h_family — firmware format (int 0/1 for calibration fields).
    Includes H2S. H2S firmware structurally accepted the current command
    shape (failure was at AMS routing, not parsing), so the int format
    stays for H2S.

  - is_dual_nozzle — external-spool routing and use_ams gating. Excludes
    H2S. Source-of-truth is the runtime _is_dual_nozzle flag set from
    device.extruder.info, with a model-name fallback for the brief window
    after connect before push data arrives.

  The K-profile delete site and the kprofiles route now use the same
  runtime+model check instead of serial prefix.
This commit is contained in:
maziggy
2026-05-17 07:56:48 +02:00
parent 4cfa5f655a
commit 96fd4bb7e3
4 changed files with 158 additions and 47 deletions
+11 -8
View File
@@ -113,14 +113,17 @@ async def set_kprofile(
if not client or not client.state.connected:
raise HTTPException(400, "Printer not connected")
# Detect dual-nozzle families by serial number prefix.
# H2 series: legacy "094"; post-2026 H2C batches ship with "31B8B" (#1105).
# X2D series: "20P9".
is_h2d = printer.serial_number.startswith(("094", "20P9", "31B8B"))
# Detect dual-nozzle for the in-place edit format. Runtime detection from
# device.extruder.info beats serial-prefix heuristics — H2S shares prefix
# "094" with H2D but is single-nozzle (#1386). Model name is the fallback
# for the brief window after connect before push data arrives.
is_dual_nozzle = client._is_dual_nozzle or (
printer.model and printer.model.upper().strip() in ("H2D", "H2D PRO", "H2DPRO", "H2C", "X2D")
)
if is_edit and is_h2d:
# H2D in-place edit: use cali_idx with slot_id=0 and empty setting_id
logger.info("[API] H2D in-place edit: cali_idx=%s", profile.slot_id)
if is_edit and is_dual_nozzle:
# Dual-nozzle in-place edit: use cali_idx with slot_id=0 and empty setting_id
logger.info("[API] Dual-nozzle in-place edit: cali_idx=%s", profile.slot_id)
success = client.set_kprofile(
filament_id=profile.filament_id,
name=profile.name,
@@ -133,7 +136,7 @@ async def set_kprofile(
cali_idx=profile.slot_id, # Pass the original slot for in-place edit
)
elif is_edit:
# Non-H2D edit: use delete + add approach
# Single-nozzle edit: use delete + add approach
logger.info("[API] Edit: deleting existing profile slot_id=%s", profile.slot_id)
delete_success = client.delete_kprofile(
cali_idx=profile.slot_id,