Skip to content

feat: expand H2 print pipeline and Kingpin charm workflow#2

Open
rowbotik wants to merge 27 commits intoDMontgomery40:mainfrom
rowbotik:codex/collar-charm-h2-cleanup
Open

feat: expand H2 print pipeline and Kingpin charm workflow#2
rowbotik wants to merge 27 commits intoDMontgomery40:mainfrom
rowbotik:codex/collar-charm-h2-cleanup

Conversation

@rowbotik
Copy link
Copy Markdown

@rowbotik rowbotik commented Apr 24, 2026

Summary

  • harden the H2 print path for H2D and H2S with project_file handling, FTPS/session-reuse fixes, and H2-safe AMS mapping behavior
  • expand the template and slicing workflow so named templates, live filament resolution, and prepared 3MF auto-slicing work together cleanly
  • add the Kingpin-specific print_collar_charm wrapper for prepared two-part collar charm projects with fixed tray-policy preflight
  • refresh deployment/spec docs and add regression coverage for the new analyzer and tool schema

Verification

  • npm run build
  • npm test

@rowbotik rowbotik changed the title feat: add kingpin collar charm wrapper feat: expand H2 print pipeline and Kingpin charm workflow Apr 24, 2026
rowbotik and others added 26 commits April 26, 2026 22:29
- New src/slicer/profile-flatten.ts: walks BBL inherits chain, derives
  nozzle_volume_type, applies cli_config overlay, sets
  from/inherits/settings_id so the CLI accepts flattened profiles.
  Workaround for upstream BambuStudio issues #9636 and #9968.
- Verified end-to-end on H2S, H2D, X1C, P1S with stock BBL profiles
  via scripts/test-cli-slice.mjs.
- Wired into stl-manipulator behind BAMBU_CLI_FLATTEN=true (default off,
  backward-compatible).
- New pause_print / resume_print MQTT tools alongside cancel_print.
- Docs: SLICING.md split into Path A (GUI, recommended) and Path B (CLI
  flatten, opt-in); README features, tool docs, and env var reference
  updated with BAMBU_CLI_FLATTEN + BAMBU_PROFILES_ROOT.
- Test fixtures from a real H2D GUI slice for ground-truth comparison.
- 9 unit tests: chain resolution, cycle detection, missing-parent
  handling, nozzle_volume_type derivation, hardware-invariant
  enforcement, end-to-end against the installed BBL tree.
- gitignore: exclude local credentials and the private 1.5MB H2D fixture.
- PROGRESS.md: session work summary, queue, verify recipe.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Hardens H2/H2D pre-sliced print behavior based on the live H2S SuperTack
print run on Parker.

H2 mapping safety:
- print_3mf now fails fast on H2/H2D pre-sliced jobs with declared
  filaments unless one of ams_slots, raw ams_mapping, or
  auto_match_ams: true is provided. Avoids sending an under-specified
  project_file that the printer accepts but does not visibly start.
- For H2/H2D, embedded slicerConfig.ams_mapping from the 3MF is no
  longer trusted -- it can be stale project metadata. Non-H2 models
  preserve the previous behavior.
- BambuImplementation.print3mf throws before FTP/MQTT when an H2
  project_file would be missing required mapping inputs.

SuperTack:
- supertack_plate is accepted by print_3mf for pre-sliced jobs (the
  successful Parker print used it).
- BambuStudio CLI slicing rejects supertack_plate fast: the CLI bed
  identifier is not verified and earlier attempts produced G-code that
  fell back to Cool Plate. New resolveBambuStudioCliBedType in index.ts
  and a parallel guard in stl-manipulator catch the unsafe path.
- VALID_BED_TYPES (pre-sliced print path) and VALID_BAMBUSTUDIO_CLI_BED_TYPES
  (slicing path) are now distinct lists.
- Auto-slice inside print_3mf also rejects supertack_plate before
  invoking the CLI.

Tests:
- New stdio test: H2 print_3mf rejects a pre-sliced fixture with
  plate_1.json.filament_ids = [1] and no mapping inputs, before any
  network activity.
- New direct-API test: ams_slots = [1] with plate_filament_ids = [1]
  expands into the recovered working H2 mapping
  ams_mapping = [-1, 1, -1, -1] and ams_mapping2 with {0,1} at
  position 1. Locks in the painfully-earned project-level shape.
- Synthetic 3MF fixture helper writeSliced3mfFixture is reusable for
  future H2 regression coverage.

Docs:
- README env reference + slice/print_3mf surface notes call out the
  new fail-fast rule and SuperTack distinction.
- PROGRESS.md updated with the live-test handoff section.
- .gitignore: ignore .claude/worktrees/ and docs/*.gcode.3mf.

npm test now passes 23/23.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- New deleteFile() in BambuImplementation: FTPS DELETE via basic-ftp
  using the same TLS-session-ticket dance as ftpUpload.
- Confirm-gated (confirm:true required) so a default invocation can't
  destroy data; returns status:"skipped" otherwise without contacting
  the printer.
- Path safety: rejects ".." segments, restricts deletes to cache/,
  timelapse/, and logs/ to prevent walking the filesystem.
- Bare filenames default to cache/<name>; relative paths to other
  allowed dirs are honored as-is.
- README features bullet + delete_printer_file tool section updated.
- 5 new unit tests cover the gating, path safety, and happy path.

npm test: 28/28.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- New cameraSnapshot() in BambuImplementation: TLS on port 6000, 80-byte
  auth packet (bblp + access token), reads one full JPEG frame from the
  repeating 16-byte header + payload stream. Wire format per
  https://github.com/Doridian/OpenBambuAPI/blob/main/video.md.
- Strict per-model routing:
  - A1 / A1 mini / P1S / P1P -> reach the wire path.
  - X1 / X1C / X1E / P2S -> fail-fast, point at RTSP on port 322 (not
    implemented).
  - H2 / H2S / H2D -> fail-fast, protocol not documented upstream.
    Same fail-loud principle as SuperTack: don't guess at wire bytes
    for unverified hardware.
- Default 8s timeout for cold-start camera latency. Validates that the
  payload starts with JPEG SOI (FF D8) before returning.
- Optional save_path writes the JPEG to disk alongside the base64
  return value.
- Tool registered in index.ts with bambu_model routing argument.
- README features bullet + camera_snapshot tool section.
- 5 new unit tests cover routing for each supported / unsupported
  model bucket and the save_path behavior with a stubbed wire layer.

npm test: 33/33.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Lets the user probe whether an H2/H2S/H2D printer happens to honor the
A1/P1 TCP-on-6000 wire format. The protocol is not documented upstream
so we still refuse by default, but a deliberate experimental:true on
the call bypasses the H2 fail-fast and tries the wire path.

Read-only either way:
- If the auth packet is accepted and the frame header parses, the user
  gets a JPEG and a `note` field flagging the experimental status.
- If not, the connection drops or the payload-size sanity check trips
  and the caller gets a clean error. No data is exfiltrated.

The flag is H2-only on purpose: experimental:true does NOT bypass the
RTSP error for X1/P2S (covered by a regression test) because RTSP is a
different protocol entirely, not just an unverified flavor of the
TCP path.

If experimental mode returns a JPEG on a real H2, that's signal we can
use to promote H2 out of the experimental bucket and document the wire
format upstream.

- src/printers/bambu.ts: experimental flag in cameraSnapshot options;
  console.warn on use; response carries a `note` describing what we did.
- src/index.ts: experimental schema entry on camera_snapshot tool, wired
  into dispatch case.
- README: H2 paragraph rewritten to describe experimental behavior +
  example invocation block for probing an H2.
- 2 new unit tests: experimental:true reaches wire path for h2/h2s/h2d
  and returns a note; experimental:true does NOT bypass X1/P2S RTSP error.

npm test: 35/35.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Two read-only probes added under scripts/:

- probe-h2-camera.mjs: spawns the MCP server in stdio mode and calls
  camera_snapshot with experimental:true, dumping the structured
  response or error.
- probe-h2-raw.mjs: bypasses our JPEG-parser entirely. Connects TLS to
  <host>:6000, sends the A1/P1 80-byte auth packet, and hex-dumps the
  first N bytes the printer replies with. Useful for figuring out the
  H2 frame header layout.

Findings against Parker H2S (recorded in PROGRESS.md):
- TLS handshake works without a client certificate.
- The H2 firmware uses the same 16-byte frame header as A1/P1.
- The A1/P1 auth packet with the LAN access code is REJECTED -- the
  printer replies with one framed error (payload_size=8,
  error_code=0xa203013f) and closes the connection.

Next experiments to try are noted in PROGRESS.md ("H2 probe results"
section): different credential (cloud dev_access_code), reading the
HA bambulab integration source, then different packet format.

No code changes; just diagnostics + documentation. npm test still 35/35.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
H2 series cameras now work end-to-end. Verified live against Parker
(H2S, 192.168.68.93): 125,321 byte JPEG returned in ~1.5s, real
chamber image saved.

Root cause of the earlier H2 failure: the OpenBambuAPI video.md doc
only documents A1/P1 TCP-on-6000 and X1/P2S RTSP. It doesn't list H2,
which led to the assumption that H2 might be on a third unknown
protocol. Reading HA bambulab's pybambu/models.py Camera class made
it clear: H2 firmware reports its own rtsp_url over MQTT in the same
ipcam.rtsp_url field as X1, and rejects the A1/P1 80-byte auth packet
because that protocol simply isn't implemented on H2.

What shipped:

- New fetchRtspCameraFrame() in BambuImplementation: shells out to
  ffmpeg with `-rtsp_transport tcp -i rtsps://bblp:<token>@<host>:322
  /streaming/live/1 -frames:v 1`. ffmpeg-version-agnostic (no
  -stimeout, since that flag was renamed/removed across versions);
  outer kill timer enforces the deadline.
- Routing matrix updated: H2/H2S/H2D/H2C/H2D Pro AND X1/X1C/X1E/P2S
  go through RTSP. A1/P1 series stay on the native TCP-on-6000
  framed-JPEG path.
- Response now includes a transport field ("tcp-6000" | "rtsps-322")
  so callers can tell which path produced the frame.
- Token redacted from any ffmpeg stderr that leaks into errors.
- Specific ENOENT error message points at `brew install ffmpeg`.
- experimental flag on the tool schema is now deprecated (no-op).
  Kept on the type/schema to avoid breaking existing callers.
- New ffmpeg_path optional argument lets callers point at a non-PATH
  ffmpeg binary.

Tests:
- Replaced the four obsolete experimental/fail-fast tests with three
  new ones covering the routing reality:
  - H2 series (h2/h2s/h2d/h2c/h2dpro) routes through RTSP.
  - X1/P2S routes through RTSP (was previously expected to throw).
  - ENOENT for a missing ffmpeg gives a helpful actionable message.
- TCP-on-6000 unit tests for A1/P1 still pass unchanged.

.gitignore: bambu-mcp-config.json (contains real access tokens).

PROGRESS.md: H2 camera promoted from "undocumented bucket" to
"resolved via RTSP" with the live probe results from Parker.

npm test: 34/34. README features bullet + camera_snapshot section
flipped to describe the dual-transport reality.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Covers: pause/resume, AMS RFID auto-match, HMS diagnostics, light/fan/utility
controls, skip objects, bed-aware slicing, CLI auto-flatten, collar charm wrapper.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ng fixes

The cherry-picked 1.1.0 CHANGELOG only spans up to 08f6afe (the parent
of this stack). Extend it with the work that landed since:

Added:
- delete_printer_file (1838855)
- camera_snapshot TCP-on-6000 path for A1/P1 (2a42574)
- camera_snapshot RTSPS path for X1/P2S/H2 series via ffmpeg (3bf954f)
  Verified live on Parker (H2S), Kingpin (H2D), and an X1C.

Fixed:
- H2/H2D pre-sliced AMS mapping requirement + regression test for the
  recovered working mapping shape (12ae6b9)
- supertack_plate accepted only on pre-sliced path; rejected fast on
  CLI slicing because the CLI bed identifier is unverified (12ae6b9)

Notes that the experimental flag from the interim camera work
(5d473c5) is now a no-op kept for schema compatibility, and that
ffmpeg in PATH is required for the RTSP transport.

No code changes; CHANGELOG entries only.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Tooling for headless two-color charm slicing. Builds a multi-object
source .3mf for BambuStudio CLI from two STLs (body, face) plus a
known-good template 3MF for project_settings.config.

Key insight (Codex spent hours not finding this): per-object filament
assignment lives in Metadata/model_settings.config inside the 3MF, not
in CLI flags. Confirmed against huskies.3mf, a real BBL multi-object
project, where each object carries
<metadata key="extruder" value="N"/>.

Implementation:
- ASCII or binary STL parser, vertex deduplication.
- Signed-tetrahedron volume sum to identify body vs face/detail
  (robust to OpenSCAD's uniform facet density; triangle count alone
  is misleading).
- Inline mesh in 3D/3dmodel.model -- single file, simpler than the
  Production-Extension multi-file layout, and BambuStudio's CLI
  parses it cleanly.
- Per-object extruder metadata + plate-level filament_maps /
  filament_volume_maps for H2D's dual-nozzle assignment.
- Carries project_settings.config from a template 3MF; can also be
  used with --load-settings/--load-filaments to fully control via
  the existing CLI flattener path.

Status (documented in PROGRESS.md):
- 3MF parses, validation passes, slicer kernel SIGSEGVs.
- Same family as upstream BambuStudio issues #9968 / #9636.
- Workaround for tonight: GUI-slice and feed to print_collar_charm.

.gitignore now excludes BambuStudio CLI's result.json drop-in.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Swapped the bunny STLs for two trivial 8-vertex cubes in the same
build pipeline. Same SIGSEGV at the same place, same warning
sequence ("load_nozzle_infos_with_compatibility..."). Confirms the
crash is fundamental to BambuStudio CLI 02.06.00.51's H2D
dual-extruder path and not a function of our input geometry, 3MF
construction, or flattener output.

Material the upstream bug ticket can use:
- Repro is two cubes, two filaments, two extruders, H2D, textured
  plate.
- Pre-config validation passes; SIGSEGV is in the slicer setup
  step.
- No log output between "tree support default to organic support"
  and the SIGSEGV.
- Same family as #9968 / #9636.

PROGRESS.md updated with the cube-repro details.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Filed bambulab/BambuStudio#10408 with the two-cube minimal repro for
the H2D multi-color CLI segfault. Cross-references #9941 / #9636 / #9968.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The previous matcher keyed only on tray_info_idx. Tonight's H2D Barkside
dispatch failed at "auto_match_ams could not find loaded AMS trays for:
GFG02, GFG02" even with both PETG HF colors loaded -- the 3MF needed
two trays of the same SKU but in different colors (black + white) and
the matcher had no way to disambiguate.

What changed in resolveAmsSlotsFromRequirements:
- Match key is now (tray_info_idx, tray_color) when both sides carry
  color, with RGB normalization that ignores alpha bytes (3MF stores
  "#000000" or "#FF911A80"; AMS reports "000000FF" without #).
- Tracks already-claimed slots so two requirements can't collapse
  onto the same physical slot.
- Falls back to SKU-only when the 3MF's filament has no color OR only
  one tray of that SKU is loaded.
- Surfaces structured `missing` reasons: no_sku / no_loaded_match /
  color_mismatch / exhausted.

Workaround tonight was explicit ams_slots; with this fix
auto_match_ams: true would have one-shot the dispatch.

Regression test using tonight's exact AMS data is a follow-up; the
fix is compile-clean and tightens behaviour without changing existing
single-color happy paths.

Also:
- scripts/print-on-printer.mjs added: stdio runner that dispatches a
  pre-sliced .gcode.3mf to a printer via the MCP's print_3mf tool.
  Used tonight to ship the Barkside print to Kingpin.
- README updates the auto_match_ams docstring to describe the new
  matching strategy and structured missing-report.
- docs/SLICING.md adds a "Multi-color CLI gap" section documenting
  bambulab/BambuStudio#10408 (H2D dual-extruder slicer-setup SIGSEGV)
  with the workaround and a status matrix at the top.
- CHANGELOG.md gets an Unreleased section covering this fix, the
  upstream-blocked multi-color CLI gap, and scripts/build-charm-3mf.mjs.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant