A network-connected desktop 3D printer with a four-spool automatic material feeder in a modern workshop.

DillaDev Notes

August 27, 2026 · Field-tested protocol guide

Starting Bambu A2L prints over LAN with correct AMS Lite mapping

When an uploaded print is accepted but stalls at Preparing, the missing piece may be the A2L's unit-aware AMS mapping—not the file or the heater.

The decisive detail

Send both mapping fields.

json
"ams_mapping": [0, 3],
"ams_mapping2": [
  { "ams_id": 16, "slot_id": 0 },
  { "ams_id": 16, "slot_id": 3 }
]

Diagnosis

The short version

The A2L reports its AMS Lite as physical unit 16. Bambu Studio shows that unit as Q, with trays Q1 through Q4. A flat ams_mapping supplies local zero-based slots; ams_mapping2 preserves the unit identity the A2L needs.

An MQTT acknowledgement with result: "success" only means the command was accepted. It does not prove the project passed mapping validation or reached RUNNING.

Mental Model

There were actually two separate problems

Troubleshoot file indexing and print initialization independently.

Layer 1

Indexed upload

Put the sliced archive directly at /gcodes/<name>.gcode.3mf and verify that the printer can see it.

Layer 2

Unit-aware mapping

Start the indexed project with both flat local slots and A2L AMS unit 16 entries.

Part 1

Upload the sliced .gcode.3mf correctly

LAN Only Mode and Developer Mode enabled

Implicit FTPS on port 990; user bblp

Archive contains Metadata/plate_1.gcode

Upload directly to the final /gcodes filename

bash
curl \
  --fail \
  --show-error \
  --ftp-pasv \
  --ssl-reqd \
  --insecure \
  --user "bblp:$ACCESS_CODE" \
  --upload-file "$LOCAL_FILE" \
  "ftps://$PRINTER_IP:990/gcodes/$REMOTE_FILE"

Validate more than the transfer

Match local and remote byte counts, confirm the exact filename in the /gcodes listing, and wait until it appears under Print Files. Temporary-upload-then-rename patterns were unreliable on the tested A2L.

Part 2

Map Q1–Q4 to AMS unit 16

Q is a Studio-facing label. The wire payload uses numeric local slots plus the physical AMS ID.

Four filament spools connected through a network mapping node to a two-color printed part.
Project filament order—not the feeder's total capacity—determines the mapping array order.
StudioTraySlot IDAMS ID
Q11016
Q22116
Q33216
Q44316

For black on Q1 and white on Q4, project filament 0 maps to local slot 0 and project filament 1 maps to local slot 3. Do not pad the arrays to four entries just because the AMS Lite has four trays.

Known-Good Shape

Full working Q1/Q4 payload

json
{
  "print": {
    "sequence_id": 0,
    "command": "project_file",
    "param": "Metadata/plate_1.gcode",
    "project_id": "0",
    "profile_id": "0",
    "task_id": "0",
    "subtask_id": "0",
    "subtask_name": "two-color-model.gcode.3mf",
    "url": "file:///sdcard/gcodes/two-color-model.gcode.3mf",
    "bed_type": "auto",
    "timelapse": false,
    "bed_leveling": true,
    "flow_cali": false,
    "vibration_cali": false,
    "layer_inspect": false,
    "use_ams": true,
    "ams_mapping": [0, 3],
    "ams_mapping2": [
      { "ams_id": 16, "slot_id": 0 },
      { "ams_id": 16, "slot_id": 3 }
    ]
  }
}

The URL locates the archive on the printer. The param path locates the sliced G-code inside the archive. They describe different layers and both must be correct.

Telemetry

Do not stop at command accepted

Accepted

project_file reports result=success

Preparing

gcode_state becomes PREPARE

Actually started

gcode_state becomes RUNNING

Subscribe to device/<serial>/report before publishing. Watch gcode_state, mc_percent, print_error, hms, tray_tar, and nozzle/bed targets. On the tested printer, subscribing to the request topic caused the broker to close the connection.

Fast Triage

What the symptoms usually mean

File missing from Print Files

Check the .gcode.3mf suffix, internal Metadata/plate_1.gcode, final /gcodes destination, byte count, and direct-to-final-name upload.

Success, then IDLE

Treat it as project initialization failure. Verify url, param, subtask_name, and both AMS mapping fields.

Stuck at PREPARE, 0%

Inspect live state and tray_tar. A falling or stalled nozzle temperature can be a consequence of the aborted startup—not the root cause.

Wrong tray

Use zero-based slots: Q1=0, Q2=1, Q3=2, Q4=3, with ams_id 16 in every A2L AMS Lite entry.

For Integrators

Keep the unit identity in your data model

A UI that stores only slots 0–3 throws away information newer printer families may need. Store unit plus slot internally, generate model-specific wire payloads, and never apply AMS ID 16 blindly to other Bambu families.

typescript
type AmsMapping2Entry = { ams_id: number; slot_id: number };

function buildA2LAmsMapping2(mapping: number[]): AmsMapping2Entry[] {
  return mapping.map((slot) =>
    slot >= 0
      ? { ams_id: 16, slot_id: slot }
      : { ams_id: 255, slot_id: 255 }
  );
}

Log model, remote path and byte count, mappings, acknowledgement, state transitions, HMS, and print errors—but never log the LAN access code.

Final Takeaway

If the file prints from the touchscreen but a LAN start silently aborts, inspect the AMS payload first.

On the tested A2L, adding the paired unit-aware ams_mapping2 structure was the difference between an accepted command that returned to IDLE and a print that consistently reached RUNNING.