Files
OrcaSlicer/docs/printer-agent/printing.md
2026-08-04 18:12:43 +08:00

5.9 KiB

Printing through printer agents

Owns the send path: connection choices, preflight, upload, start, and the two recovery flows. Defers filament mapping delivery to Filament synchronization, which is a separate contract even though it is applied at print time.

This chapter describes the printer-agent send path. It is separate from the older print-host implementation, even when both target Moonraker. Keep the paths separate unless their contracts and failure handling can be deliberately reconciled.

Connection choices

Three connection paths are in use:

Target Connection path Use
Native Bambu Custom TLS tunnel on port 6000 Send and optional eMMC preflight
Bambu Python agent Implicit FTPS on port 990 Upload and Bambu preflight fallback
Moonraker family HTTP Upload and start print

The Bambu connection paths are independent. Selecting one does not prove that the other is available. The Moonraker agent uploads with a multipart request to its gcodes storage and then starts the uploaded filename; it does not reuse the legacy Moonraker print-host class.

Bambu native tunnel

The native tunnel depends on the versioned networking DLL and its file-transfer module. InitFTModule() is a single-owner initialization: it rejects a second call. Any future shared initialization must therefore be idempotent, while BBLNetworkPlugin remains the single teardown owner. It must call UnloadFTModule() before freeing the DLL, otherwise the module's function pointers can point into unloaded code.

There is currently an initialization gap: selecting a printer agent does not initialize this module. It is initialized only when the installed_networking option causes the native BBL network plugin to initialize. Calls to the tunnel must continue to fail safely until that path has initialized the module. The Send UI catches this failure and reports an initialization error instead of letting an exception leave a wx event handler.

Bambu FTPS upload

The Python Bambu agent uses implicit FTPS on port 990. Its live upload path closes the data connection, then waits at most two seconds for the control response with voidresp(). A TimeoutError is accepted as a completed transfer. An error_reply is also accepted when its reply begins with 200. This is the behavior to preserve.

Do not describe the path as using TLS unwrap(): the live construction does not enable it. Enabling it without a bounded wait could hang while waiting for the peer's TLS close notification. The current timeout-based handling has not been verified on hardware against every printer and FTP server combination.

Print preflight and recovery

For normal LAN prints, PrintJob performs a preflight before the real send. When eMMC is eligible it tries the native tunnel, then it sends a small verify_job upload through the selected agent. The latter is a real upload, not a special protocol command. Non-Bambu agents therefore upload the probe too.

Do not re-enable eMMC by default without hardware coverage for the affected devices. It is opt-in because the tunnel can hang during upload on some printers.

The whole send, including the thread hop and the recovery fork:

sequenceDiagram
    participant UI as Send UI (UI thread)
    participant J as PrintJob (worker)
    participant A as Selected IPrinterAgent
    participant P as Printer

    UI->>J: Start send
    opt eMMC eligible - off by default
        J->>P: Native Bambu tunnel attempt
        Note over J,P: Can hang on some printers
    end
    J->>A: verify_job preflight
    Note over J,A: A real upload, not a protocol probe -<br/>non-Bambu agents upload it too
    A->>P: Upload probe

    alt Preflight and upload succeed
        J->>A: Upload the real job
        A->>P: Upload, then request print start
        Note over A,P: The start response may stay open while<br/>the printer prepares - a timeout is not<br/>proof of failure, so check reported print state
        A-->>UI: Result from the reported print state
    else Upload fails
        J-->>UI: Failure callback, marshalled to the UI thread
        Note over UI: Re-resolve the machine here.<br/>Never reuse a machine pointer captured<br/>on the worker - agent or machine may have changed
        alt Printer still connected
            UI->>UI: Explain that storage upload failed
        else Printer disconnected
            UI->>UI: Open the IP or access-code flow
        end
    end

An upload failure and a disconnected printer need different recovery:

Condition UI response
Printer is still connected Explain that storage upload failed.
Printer is disconnected Open the IP or access-code flow.

Do not retain a machine pointer from a worker callback. The callback that chooses between these two outcomes runs on the UI thread and re-resolves the machine there, because the selected agent or machine can change first. The connection check is adequate for choosing the message, but is not a strong enough signal to authorize a reconnect.

Moonraker upload and start

MoonrakerPrinterAgent uploads through Moonraker HTTP, then requests the print start separately. The start endpoint may keep its response open while the printer prepares the job. A timeout after that request is not automatically proof that the start failed: the agent checks the reported print state before deciding the result.

The legacy print-host Moonraker path implements its own upload and start logic. It is not the agent path and should not be changed as an implicit side effect of agent work.

Maintenance checklist

  • Test the selected connection path, not just another path on the same printer.
  • Preserve cancellation and progress callbacks across upload and start.
  • Treat verify_job as an actual upload when estimating storage effects.
  • Keep eMMC opt-in until its hanging behavior is resolved and verified.
  • Keep the connected-upload-failure dialog distinct from the disconnected recovery flow.