Chris Collins

Tools · fabrication

3-D printer farm dashboard

One page for every Klipper (Moonraker), OctoPrint and Bambu Lab (LAN mode) printer on your network — state, job, progress, time left, layer, temperatures with a graph, webcam, filament, and for Bambu printers the AMS spools and decoded HMS messages — with pause, resume, cancel and start, alerts when a print finishes, fails or a printer sits idle, and a job queue. Through a small relay you run, directly, or as a simulated demo farm.

Added · updated 28 October 2026

Works with

How to use it

With a few printers running, I wanted one screen that shows which are busy, which have finished, and which have stopped with an error — not a browser tab per Mainsail or OctoPrint. This is it.

How to use it

Pick how the page reaches the printers:

  • Demo farm — seven simulated printers (three Klipper, two OctoPrint, two Bambu Lab) that answer like the real APIs and the relay, with time running 30× faster. Try everything here first; nothing leaves the page.

  • Through the relay — the normal way. This page is HTTPS, and Moonraker and OctoPrint answer on plain http:// on your LAN; browsers block an HTTPS page from calling those (mixed content). printer-relay.py is a short Python 3 script (standard library only) that you run on your own computer. It listens on 127.0.0.1:8094 — browsers count localhost as secure, so the page may call it — and forwards the dashboard’s requests to the printers you name:

    curl -O https://geekychris.github.io/tools/printer-relay.py
    python3 printer-relay.py --printer voron=moonraker:http://192.168.1.50:7125 \
                             --printer ender=octoprint:http://192.168.1.60

    It prints a random token and a link that opens this page connected (the token travels in the link’s # part, which browsers don’t send to any server); or paste the token in. OctoPrint needs an API key: give it as OCTOPRINT_KEY_ENDER=… in the environment or in a --config JSON file (chmod 600). The relay adds the key to the printer request; the page never sees it.

  • Direct — no relay, when the browser allows it. If you serve this page from http://localhost (save it, or run the site locally), it may call http:// printers. From the HTTPS site it can only call printers on https:// (behind a reverse proxy with a certificate). Either way the printer must allow the page’s origin in CORS: in Moonraker add it to [authorization] cors_domains in moonraker.conf; in OctoPrint tick Settings → API → Allow Cross Origin Resource Sharing (CORS). The page checks each address and says which rule stops it. An OctoPrint API key entered here is kept in this browser’s storage only.

Each printer gets a card: state, file, progress, time left and the clock time it finishes, layer (Klipper reports it when the slicer sets it), elapsed time, filament used, temperatures with a graph of the last 120 polls (dashed lines are targets), and a webcam snapshot refreshed every few seconds. The time left leans on the slicer’s estimate early in a print (Moonraker’s file metadata, OctoPrint’s analysis) and on the measured rate — elapsed ÷ progress — from half way, as that settles.

Pause, Resume and Cancel ask first. Print a file… lists the G-code already on that printer and starts the one you pick (after a reminder to clear the bed). The dashboard can’t upload files, send G-code or move axes, and the relay refuses those paths too.

Alerts — a print finished or was cancelled, a printer went into error (a Klipper shutdown included), stopped answering, or has sat idle longer than you set. They go in the list, as a toast, and as a system notification if you press Allow notifications. They come only while this tab is open.

Queue — a manual list of jobs (files already on the printers), each for a printer or any printer. Start one from the queue or from a free printer’s card (Next: …); it is marked done when that printer finishes.

Bambu Lab printers

X1 Carbon, X1E, P1S, P1P, A1, A1 mini, H2D (and H2S, P2S) show up as cards too, through the relay only. They don’t have an HTTP API: in LAN mode they talk MQTT over TLS on port 8883 (user bblp, password the LAN access code), which a web page cannot open. The relay keeps one connection per printer and gives this page a small JSON API.

BAMBU_CODE_X1C=12345678 python3 printer-relay.py --printer x1c=bambu:192.168.1.70:01S00C123456789

The number after the address is the printer’s serial number; both it and the 8-character access code are on the printer’s screen (Settings → WLAN / Network, or LAN Only Mode). Or use a config file entry: {"id": "x1c", "kind": "bambu", "host": "192.168.1.70", "serial": "…", "access_code": "…", "model": "X1C"}. The access code stays in the relay.

A Bambu card shows the state and the step the printer is on (heating, levelling, changing filament), progress, layer, time left, nozzle(s), bed and chamber temperatures, fan speeds, the speed profile, the AMS units with a colour chip, material and remaining percentage for each slot (the one feeding is outlined), and any HMS messages and print error, decoded — each code links to Bambu HMS and error codes. Buttons: pause, resume, stop, the chamber light, and the speed profile (silent, standard, sport, ludicrous). The camera snapshot works for P1 and A1 (the relay reads one JPEG from their camera stream on port 6000); X1, H2 and P2S stream RTSPS, which the relay can only grab a frame from if ffmpeg is installed on your computer and LAN Mode Liveview is on.

What it can’t do: start prints, send files, G-code or moves, change AMS filament, or update firmware. The relay has no route for any of those.

What the printer must allow — read this. Since January 2025 Bambu’s firmware has Authorization Control: in ordinary LAN mode, software other than Bambu Studio, Handy and Bambu Connect can read the printer’s status but its commands are refused. To control the printer from here you need LAN-only mode and then Developer Mode switched on at the printer (Settings → LAN Only / Network → Developer Mode; firmware X1 01.08.03.00+, P1 01.08.02.00+, A1 01.05.00.00+, H2D 01.01.00.01+; P2S ships with it). Developer Mode cuts the printer off from Bambu’s cloud — the Handy app and cloud printing stop working, and firmware updates have to be done another way — and Bambu does not support it. Without it the card still shows status, and a refused command says so. This is how things stood in October 2026; Bambu has changed these rules before and could again, and I have not tested this against real printers (the relay is tested against a simulated one that speaks the same protocol).

The printer’s TLS certificate is signed by Bambu’s own authority, so the relay does not verify it by default (it is on your LAN). It prints the certificate’s SHA-256 when it connects (run without --quiet); put that in the printer’s config as "fingerprint" and the relay will refuse to send the access code anywhere else.

For the cost of a print see Print cost, for what went wrong Print troubleshooting, and for spool labels the Label maker.

The relay

What printer-relay.py will and won’t do:

  • binds to 127.0.0.1, answers only this site and local previews (--allow-origin for others), and refuses requests whose Host isn’t localhost (against DNS rebinding);

  • needs the token on every request (X-Relay-Token), compared in constant time;

  • reaches only the printers on its command line or config, and only these paths — Moonraker: /printer/objects/query, /server/files/list, /server/files/metadata, /server/webcams/list, /printer/info, /server/info, and POST /printer/print/start|pause|resume|cancel; OctoPrint: /api/job, /api/printer, /api/files, /api/connection, /api/version, POST /api/job (start, pause, cancel) and POST /api/files/local/<file> with select only;

  • fetches webcam snapshots only from the printer’s own host;

  • for Bambu printers, sends only pause, resume, stop, the chamber light, the speed profile and a status refresh over MQTT, and never shows the page the access code or the serial number;

  • drops the page’s cookies and Authorization headers, and limits request bodies to 16 KB.

Browser support

Any current browser. Notifications need permission and, on phones, often a page installed to the home screen; the dashboard works without them.

Privacy

In demo mode nothing leaves the page. Otherwise the page talks only to the relay on your own computer, or (direct) to your printers — nothing goes through this site. Your settings and queue, and the token if you tick remember, stay in this browser’s local storage.

Runs entirely in your browser; nothing you type leaves this page.