Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ JSON field names and exit codes are part of the public API.
## [Unreleased]

### Added
- `ams set --slot S --type T --filament-id ID --color RRGGBB --nozzle-temp-min T --nozzle-temp-max T`: record a non-RFID spool's metadata with `--confirm`, or preview with `--dry-run`. Requires an idle printer, Developer Mode, and physical filament detection. Verifies every field from fresh tray reports; exits 14 when submitted but unverified. Repeating identical values sends nothing. Flow calibration is reported but unchanged.
- Operator parity with `bambu-op`: verified `light status|on|off`, chamber-light telemetry, and `--light` snapshots that restore the previous light mode even on failure or interruption.
- Monitor `--notify` with optional `[ntfy]` configuration and keychain/stdin token storage (`auth set --ntfy`), `--watch` for continuous monitoring, configurable `--interval`/`--pushall-every`, and full final status/snapshot/exit-code data.
- STEP/STP slicing through a CadQuery interpreter (`[slicer] step_python`), object footprints including brim, and `slice --slot` suggested-slot metadata.
Expand Down
36 changes: 34 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Slice, check, send and monitor **Bambu Lab** prints from the terminal over your
- **Safety first:**
- Preflight gates check that the printer is idle, the right filament is in the slot, the plate and nozzle match, Developer Mode is on, and there's enough filament.
- `print send` refuses to run without `--confirm`.
- No command ever changes printer settings.
- AMS spool metadata edits require `--confirm` and verified read-back. AI protections and network settings stay read-only.
- **LAN only:** MQTT and FTPS go directly to the printer. No cloud account, no Bambu Connect.
- **Agent-friendly:** `--json` everywhere (NDJSON for streams), stable exit codes, `schema` introspection, and no prompts with `--no-input`.
- **Single static binary** for macOS, Linux and Windows.
Expand Down Expand Up @@ -127,6 +127,35 @@ Recipes name presets generically (`"0.20mm Standard"`, `"Bambu PLA Basic"`), and
- **Custom recipes:** drop JSON files in `~/.config/bambu/recipes/`. The same name overrides a built-in. See `bambu recipe show solid-pla`.
- **`--set key=value`** takes any Bambu Studio setting key. Unknown keys are rejected before slicing. At 100% infill, patterns the slicer rejects (grid, gyroid, …) switch to zig-zag automatically.

### Configure an AMS spool

After loading a non-RFID spool, record what is physically in the slot:

```bash
bambu ams set --slot A1 --type PLA --filament-id GFL99 --color C8A26B \
--nozzle-temp-min 200 --nozzle-temp-max 230 --dry-run --json
# Use --confirm instead of --dry-run to apply the same values.
```

`GFL99` is Generic PLA; PLA+ uses material type `PLA`. Supply the matching profile ID,
preview color, and temperature range from the spool manufacturer. Common Generic
profile IDs are type-checked; matching other IDs to the material is the caller's responsibility. A wood-colored PLA+
spool uses a PLA profile; a wood-filled material needs its own suitable profile.

All five material fields are required so a changed spool does not inherit old values.
The printer must be idle, in Developer Mode, and detect filament in the slot. Paused
jobs, busy AMS operations, empty or unknown slots, and RFID spools are refused.
Dry-run runs the same gates and shows the protocol payload without changing anything.
Exit 0 on a write means a fresh tray report matched every field, including color alpha;
an acknowledgement alone is insufficient. Repeating the same values sends nothing.

This records metadata without loading filament or heating the printer. Temperature
bounds are used by later filament loads and preflight checks. Bed temperature, flow
ratio, and volumetric speed belong to the slicing profile; this command also leaves
the tray's flow calibration unchanged and reports any calibration telemetry before
and after. Only use it after a human identifies the physical spool, never to bypass a
preflight mismatch.

### Safety model

1. **`preflight` checks before anything is sent:**
Expand All @@ -141,7 +170,10 @@ Recipes name presets generically (`"0.20mm Standard"`, `"Bambu PLA Basic"`), and
3. **`print pause|resume|stop`** require `--confirm`. `resume` exits 0 only once the printer reports RUNNING. It refuses mid-filament-change, and with an empty toolhead on the X1 series.
4. **`filament load`** requires `--confirm` and works only while paused or idle. When paused, the toolhead must hold an AMS filament and the slot must hold the same material. It exits 0 only once the printer reports that slot in the toolhead.

`bambu` has no command that changes printer settings.
5. **`ams set`** requires `--confirm` to record non-RFID spool metadata while idle,
with physical filament detection and verified read-back. `--dry-run` sends nothing.

AI protections, network settings, and direct temperature controls remain read-only.

### Exit codes

Expand Down
33 changes: 30 additions & 3 deletions SPEC.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ In v0.1:
- Pause / resume / stop. `resume` succeeds only once the printer reports RUNNING.
- Two-filament jobs: a layer-height colour change that the AMS performs from the G-code, one `--slot` per filament.
- `filament load`: a remote AMS colour change while paused (the manual route when the second colour isn't in the job).
- `ams set`: record a human-identified, non-RFID spool's metadata while idle, with verified read-back.
- Status, and a streaming `status --watch`.
- `monitor` with a layer-N snapshot and an exec hook.
- Camera snapshot for RTSPS models (X1/X1E/H2/P2S/X2D) via ffmpeg.
Expand All @@ -25,7 +26,7 @@ Out of scope for v0.1:
- Cloud API and Bambu Connect.
- Per-object or painted multi-colour slicing: `slice` makes multi-filament jobs only from layer-height changes.
- The P1/A1 camera, which uses the port-6000 JPEG protocol: a clear error for now.
- Changing persistent printer settings: no xcam/AI toggles, network configuration, or temperature controls. The chamber light is an explicit, verified control.
- Changing persistent printer settings other than AMS spool metadata: no xcam/AI toggles, network configuration, or direct temperature controls. The chamber light is an explicit, verified control.
- OrcaSlicer (see §8).

## 2. Settled decisions
Expand All @@ -44,7 +45,7 @@ Out of scope for v0.1:

## 3. Command tree

The tree is noun-verb where there is a real noun: `printer`, `auth`, `print`, `camera`, `recipe`, `slicer`.
The tree is noun-verb where there is a real noun: `printer`, `auth`, `print`, `camera`, `recipe`, `slicer`, `ams`.
Top-level verbs are kept for the high-frequency, single-purpose actions an operator types all the time: `status`, `slice`, `preflight`, `monitor`.

```
Expand All @@ -55,6 +56,7 @@ bambu print send <file.gcode.3mf> --slot S [--slot S2]... (--dry-run | --confirm
bambu print pause|stop --confirm
bambu print resume --confirm [--wait 30s] # exit 0 only once the printer reports RUNNING
bambu filament load --slot S --confirm [--timeout 5m] # paused or idle; exit 0 only once S is in the toolhead
bambu ams set --slot S --type PLA --filament-id GFL99 --color RRGGBB --nozzle-temp-min T --nozzle-temp-max T (--dry-run | --confirm) [--wait 10s]
bambu monitor [--snapshot-at-layer N] [--snapshot-dir D] [--exec CMD] [--timeout 2h]
bambu camera snapshot [-o file.jpg]
bambu printer add <name> --host H --serial S [--model X1C] [--nozzle 0.4] [--plate textured_plate] [--default]
Expand Down Expand Up @@ -86,6 +88,7 @@ Slots: `1`–`4` (first AMS) or `A1`…`D4`, plus `ext` for the external spool (
- status: state
- slice: the path of the .gcode.3mf
- snapshot: the path of the image
- ams set: the normalized slot label
- send: state
- preflight: PASS/FAIL
- **Errors in `--json` mode** print `{"error":{"code":N,"name":"...","message":"...","hint":"..."}}` to stdout **and** a human line to stderr.
Expand Down Expand Up @@ -164,6 +167,27 @@ pause, A4 → A1): `{"print":{"sequence_id":"<n>","command":"ams_change_filament
Done when `ams.tray_now` is the target and `ams_status >> 8` is no longer `0x01` (filament_change) nor the stage a
loading/unloading one.

**AMS metadata:** Studio's `command_ams_filament_settings` sends
`{"print":{"sequence_id":"<n>","command":"ams_filament_setting","ams_id":A,"slot_id":S,"tray_id":S,
"tray_info_idx":"<filament ID>","setting_id":"","tray_type":"PLA","tray_color":"RRGGBBFF",
"nozzle_temp_min":200,"nozzle_temp_max":230}}`. `tray_id` is local to the AMS (0–3).
All metadata fields are required; colors accept an optional `#`, and temperatures
must satisfy 150 ≤ min ≤ max ≤ 350 °C. Common Generic profile IDs (PLA, PETG, ABS,
ASA, PA, PC, TPU) are checked against the material type. For other IDs, the caller
must supply a matching pair; the CLI does not resolve slicer presets.
`tray_exist_bits` is a hexadecimal physical detection mask, independent of configured
`tray_type`. Refuse missing detection or an empty slot, RFID identity, active jobs
(including PAUSE), busy AMS operations, blocking errors, and missing Developer Mode.
After publishing, request fresh `pushall` reports and compare type, filament ID, full
RGBA color, and both temperature bounds. Exit 14 means submitted, unverified, with
before/after evidence in the error data. An identical initial report is a verified
no-op. Dry-run performs the same gates and returns `dry_run:true, sent:false,
verified:false` with the payload. Successful writes include `before`, `after`,
`sent`, `verified`, `payload`, and optional `ack` and calibration telemetry.
Plain columns: slot, type, filament_id, color, nozzle_temp_min, nozzle_temp_max,
dry_run, sent, verified. Bed/flow/speed remain slicing settings; tray calibration
is reported but never selected or changed by this command.

**Two-filament `ams_mapping`:** one entry per project filament in filament order, e.g. `[3, 0]` for A4 then A1
(Studio's "v0" format, `SelectMachine.cpp`). Not yet verified on a real print.

Expand Down Expand Up @@ -279,7 +303,10 @@ internal/errfmt/ exit codes, typed errors with hints
- `print pause|resume|stop` and `filament load` require `--confirm`. `filament load` runs only while PAUSE or
IDLE/FINISH/FAILED. It refuses during a change, with a blocking HMS code, or on an empty slot. When paused, it also
refuses without an AMS tray in the toolhead, or with a different material than the job's.
- No command changes printer settings.
- `ams set` is the exception for human-identified, non-RFID spool metadata. It needs
`--confirm`, an idle printer, physical filament detection, and fresh read-back;
never use it to bypass a preflight mismatch. It does not load, heat, or select flow calibration.
- AI protections, network settings, and direct temperature controls stay read-only.
- The access code is never printed, never logged, and never written to config. `ffmpeg` errors are redacted.
- `--no-input` or a non-TTY stdin never prompts.

Expand Down
25 changes: 25 additions & 0 deletions docs/protocol.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,31 @@ September 2026).
- **AMS state:** `print.ams_status >> 8` is Bambu Studio's `AmsStatusMain`: `0x00` idle, `0x01` filament_change, `0x02` rfid_identifying, `0x03` assist (resting, filament loaded), `0x04` calibration, `0x07` cold_pull, `0x10` self_check, `0x20` debug. `ams.tray_now` is the tray in the toolhead (`255` none, `254` external spool). A G-code pause (`M400 U1`) reports `PAUSE` with `print_error` `0300_8013`. (verified)
- **Filament load:** `{"print":{"sequence_id":"<n>","command":"ams_change_filament","ams_id":A,"slot_id":S,"target":A*4+S,"curr_temp":T1,"tar_temp":T2}}`, as Studio's `command_ams_change_filament` sends it. Each temperature is the middle of that tray's `nozzle_temp_min`/`max` (Studio's default is 210). The printer cuts and unloads, loads the target and purges: `ams_status` goes `filament_change`, then `tray_now` becomes the target and `ams_status` returns to `assist`. (verified on an X1 Carbon during a pause, 2026-10-08: A4 → A1, then `resume` → RUNNING, and the print finished cleanly.)

## AMS spool metadata: `print.ams_filament_setting`

Matches Bambu Studio's `DeviceManager.cpp::command_ams_filament_settings`:

```json
{"print":{"sequence_id":"<n>","command":"ams_filament_setting",
"ams_id":0,"slot_id":0,"tray_id":0,"tray_info_idx":"GFL99","setting_id":"",
"tray_type":"PLA","tray_color":"C8A26BFF","nozzle_temp_min":200,"nozzle_temp_max":230}}
```

`ams_id` names the unit; `slot_id` and `tray_id` are local indices (0–3).
Colors are RGBA. The command sends an empty `setting_id`; its effect is unverified
and it is not included in the read-back guarantee. Metadata is
verified through fresh `pushall` tray reports, comparing all five fields; the
command acknowledgement does not establish success. `tray_exist_bits` is the
hexadecimal physical filament detection mask, independent of configured type.
RFID spools are refused because their metadata can be restored from the tag.
This command does not load filament, heat the nozzle, or change flow calibration.
Temperature bounds affect subsequent filament loads and preflight checks.

Verified on an X1 Carbon on 2026-10-12: an unconfigured non-RFID spool became
PLA / GFL99 / C8A26BFF / 200–230 °C, confirmed by a separate status connection.
The other three slots, toolhead selection, and heater targets stayed unchanged.
Repeating the same settings published nothing. Other printer models remain unverified.

## Start a job: `print.project_file` (verified)

```json
Expand Down
Loading
Loading