| Filename | Latest commit message | Latest commit date |
|---|---|---|
SimplyPrint's multi-printer endpoint rejects add_connection unless unique_id is a UUID
or <=15 chars ('bambridge-<serial>' is 25), and the ws-client only logs the rejection at
debug level, so the visible symptom was 'No connections made in 30s'. Now a UUIDv5 of
the serial (stable across reinstalls), with migration of existing state files, and an
error-level log line when the server rejects a registration. Also fix two clients racing
SsdpListener.start() into a double bind.
|
||
| bambridge | ||
| deploy | ||
| docs/spikes | ||
| shim | ||
| tests | ||
| tools | ||
| .gitignore | ||
| Makefile | ||
| OPERATIONS.md | ||
| pyproject.toml | ||
| README.md | ||
bambridge — SimplyPrint ↔ Bambu Lab, cloud mode preserved
Use SimplyPrint (queue, start, monitor, pause/resume/cancel, webcam) with Bambu printers that stay bound to Bambu Cloud, so Bambu Handy, MakerWorld one-click printing and OTA firmware keep working exactly as before. Built for an H2D + X2D on a Linux home server; works for other models.
SimplyPrint cloud ──wss──▶ bridge ──HTTP 127.0.0.1:8765──▶ actuator ──▶ libbambu_networking.so ──▶ Bambu Cloud / LAN FTPS ──▶ printer
▲ (official plugin, unmodified)
printer ──MQTT 8883 (subscribe-only) + camera 322/6000──┘
- Reads come straight from the printer on the LAN (local MQTT + camera). No cloud needed.
- Writes (start print, pause/resume/stop) go through Bambu's own network plugin — the
same
libbambu_networking.soBambu Studio downloads — hosted in a small C++ shim. To Bambu's infrastructure this host is a logged-in Bambu Studio on Linux. Sends use Studio's own route ladder: LAN FTPS upload + cloud task record first, pure cloud upload second. - The bridge never trusts "sent"; a job counts as started only when the printer's MQTT report shows it running with the name we gave it.
Why not X? Bambu Connect has no Linux build and no automation surface; the Local Server SDK,
Fleet Hub and Developer Mode all unbind the printer from Bambu Cloud; SimplyPrint's own Bambu
client is monitor-only in cloud mode. See docs/spikes/S0-plugin-host.md.
Components
| Path | What |
|---|---|
shim/ |
libbnhost.so: plain-C facade over the plugin's C++ API (mirrors Studio's NetworkAgent). Built with the distro g++ so the libstdc++ ABI matches. |
bambridge/actuator/ |
Plugin fetch + version pin, headless Bambu login, .gcode.3mf inspection, AMS mapping, one-job-at-a-time send lane, HTTP API. Knows nothing about SimplyPrint. |
bambridge/bridge/ |
simplyprint-ws-client integration: local MQTT ingest, state mapping (X1/P1/A1 and H2D/X2D schemas), cameras, demand handlers, interlocks. |
bambridge/common/ |
Config (one TOML), logging (JSON lines, secrets redacted), notifier, report-document parser shared by both. |
deploy/linux/ |
systemd units + install.sh / uninstall.sh. deploy/docker/ alternative. |
docs/ |
Spike notes, operations. |
Install (Debian/Ubuntu host on the printers' LAN)
git clone … bambridge && cd bambridge
sudo ./deploy/linux/install.sh # builds the shim, venv in /opt/bambridge, state in /var/lib/bambridge
bambridge login --browser # sign in with Google/Apple/email in your browser (see below); or `bambridge login` for email+password
bambridge bridge add-printer # per printer: name + serial; IP and access code auto (LAN discovery + Bambu Cloud) or typed in
sudo systemctl enable --now bambridge-actuator bambridge-bridge
bambridge actuator selftest # plugin ok, logged in, cloud connected, printers bound, state flowing
bambridge bridge doctor # local MQTT + camera per printer, actuator reachable
Why auto-discovery is safe. LAN announcements are unauthenticated, so the bridge treats
them purely as a hint for where to connect. Who it is talking to is decided by TLS: the
printer must present a certificate that chains to Bambu's device CA and is issued to that
printer's serial number, or the handshake fails before the access code is sent (MQTT and the
port-6000 camera alike). Announcements are also ignored unless they come from the address they
advertise and that address is LAN-scoped, and a working link is never re-pointed by an
announcement; only a down link (or an explicit ip= in the TOML) moves. If you'd rather not
listen at all, set ip= for every printer and discovery has nothing to decide.
Adding the printer in SimplyPrint. There is no local web UI; pairing uses SimplyPrint's
setup-code flow (same as their Duet/Bambu integrations). Once bambridge-bridge is running and
online, each not-yet-added printer gets a short code from SimplyPrint:
bambridge bridge status
# lab-h2d 0948… WAITING TO BE ADDED — setup code: K8QZ
(also logged as *** lab-h2d: not yet added in SimplyPrint. Setup code: K8QZ ***). In the
SimplyPrint web panel or app: Printers → Add printer, enter that code, pick the Bambu model
(H2D / X2D), and set Multi-material to Bambu AMS. bridge status then shows PAIRED. The
pairing is stored under state/simplyprint/ and survives restarts and re-installs. Give the printers DHCP reservations. On X1/H2/X2 models enable
LAN Mode Liveview (a.k.a. LAN Only Liveview) on the printer for the webcam; the printer
stays cloud-bound.
Login options. bambridge login --browser prints a bambulab.com URL; open it on any machine,
sign in however you normally do (Google works), and Bambu redirects the browser to
http://localhost:13618/?ticket=…. If the browser is on the bridge host, or you ran
ssh -L 13618:localhost:13618 <host> first, the ticket is picked up automatically; otherwise
the page fails to load, which is expected: copy the URL from the address bar and paste it into
the waiting prompt. This is the same one-time-ticket mechanism Bambu Studio uses for
third-party sign-in; the plugin exchanges the ticket for its session. --provider google skips
Bambu's page and goes straight to Google. Plain bambridge login does email + password (+ the
emailed code or TFA if Bambu asks); --token-file accepts a token JSON if you have one.
Docker instead: cd deploy/docker && docker compose run --rm bambridge login && docker compose run --rm bambridge bridge add-printer && docker compose up -d (host networking).
Configuration
One file, $BAMBRIDGE_HOME/bambridge.toml (mode 0600; /var/lib/bambridge when installed).
bambridge config prints it with secrets masked. The interesting knobs:
[bambu]
region_country_code = "NL" # picks api.bambulab.com vs .cn
plugin_version = "02.08.02.54" # pinned; `bambridge plugin fetch` refuses silent changes
studio_version = "02.08.02.61" # whose headers/cert we present
[actuator]
listen_host = "127.0.0.1" # non-loopback requires `secret`
routes = ["lan_record", "cloud"] # Studio's order; add "lan" for no-history LAN-only as last resort
send_timeout_s = 240
[bridge]
start_timeout_s = 180 # FILE demand → printer reports PREPARE/RUNNING with our name
control_timeout_s = 60
offline_after_s = 30
[notify]
kind = "ntfy" # ntfy | pushover | slack | none
target = "https://ntfy.sh/your-topic"
[[printer]]
name = "lab-h2d"
serial = "0948…"
ip = "" # blank = follow the printer's LAN announcements (UDP 2021); set it to pin an address
access_code = "" # blank = use the code Bambu Cloud reports (via the actuator); set it to override
camera = "auto" # auto | rtsp322 | jpeg6000 | off
pushall_on_connect = true
What SimplyPrint can and can't do through this bridge
| Works | Notes |
|---|---|
| Status, temps (both nozzles), progress, layers, time left | within a second or two of Handy |
| Job attribution | SimplyPrint-started jobs carry their job id (task name sp-<jobid>-<file>); Handy/Studio-started jobs appear as external jobs |
| AMS → material data | per nozzle; AMS / AMS 2 Pro / AMS HT / external spool; active slot |
| HMS / print_error → notifications | text from Bambu's public HMS table (bambridge hms fetch) |
| Webcam | RTSPS 322 (X1/H2/X2/P2, needs LAN liveview toggle) or JPEG 6000 (P1/A1) |
Start print (.gcode.3mf) |
auto AMS mapping like Studio, or SimplyPrint's mms_map; bed-levelling/flow-cal/timelapse options honoured |
| Pause / resume / cancel | signed by the plugin; confirmed via MQTT |
| Not available | G-code terminal, manual temperature/motion, plain .gcode files (Bambu cloud printers need 3MF), host reboot from SimplyPrint |
Safety interlocks (bridge, before any send)
Printer must be IDLE/FINISH/FAILED, no fatal/serious HMS active, MQTT link up and fresh, no
other start in flight. The actuator repeats the state checks against the cloud view. A send
that the printer never acknowledges is not retried (no double prints); it fails as
start_unconfirmed and alerts. If Handy starts something while a SimplyPrint send is in
flight, the SimplyPrint job fails as printer_busy_external and the external job is shown.
Development
make -C shim # needs g++, nlohmann-json3-dev
uv venv -p 3.12 .venv && uv pip install -p .venv/bin/python -e '.[dev]'
.venv/bin/pytest -q # report parsing, state map, 3MF, mapping, actuator (fake plugin), bridge client
.venv/bin/python tools/sim_e2e.py # whole pipeline against a fake SimplyPrint + simulated H2D; prints every message sent
BAMBRIDGE_HOME=$PWD/.dev bambridge init && bambridge plugin fetch && bambridge actuator serve
tests/fixtures/mqtt/*_habambulab.json are captured printer reports from
ha-bambulab (MIT). Add your own captures (redact
serials/access codes) as tests/fixtures/mqtt/<name>.json with a top-level pushall key.
Licence: AGPL-3.0-or-later (inherits from simplyprint-ws-client). bambridge/data/ carries
Bambu's device CA bundle and slicer certificate as shipped in Bambu Studio's resources/cert.