Route telemetry up and commands down over the cloud uplink
The proxy did not actually proxy. `fleet` was loaded and connected in main.rs and then never touched again, while the uplink said hello and sent heartbeats into the void - two halves of the program running side by side with nothing between them. Both directions are wired now. Up: every 5s, one vendor-neutral `PrinterTelemetry` snapshot per printer that has reported, batched into a single `Telemetry` message. The snapshot is a translation rather than a forwarded `print.push_status`, because it has to describe a Prusa too, and because Bambu's wire format has traps (0-15 fan gears, ints-or-floats temperatures) that should not reach the rest of the system. Down: a `Command` is looked up by our own printer id, executed, and answered with a `CommandResult`. `PrinterCommand` is deliberately small and deliberately has no "start a print" variant - `start_uploaded_file` has never been run against hardware, and the first thing to exercise it should be a human watching the machine, not a message from the internet. The fleet becomes `Arc<Mutex<Vec<PrinterHandle>>>` so main and the uplink can share it. One lock for the whole Vec is coarse - a slow command to one printer stalls telemetry for all of them - which is fine at a handful of printers and is the shape to revisit (a lock per printer, or an actor task each) before a farm gets large. Two things found by running this against the live P1P and H2C: - A v1 Bambu reached the cloud as a row of nulls with one real bed temperature in it, while the v2 H2C beside it was fully populated. v1 only sends a *complete* status when asked, and `pushall`'s own doc comment said to call it periodically - nothing ever did. Each telemetry tick now collects, then requests the next refresh, so v1 telemetry runs one tick behind instead of staying stuck on fragments. The quirk lives in `PrinterHandle::refresh_status` so the uplink does not have to know it. - The third instance of the silent-swallow parse bug, at the old uplink/mod.rs:63: `if let Ok(server_msg) = serde_json::from_str(..)` with no else. Same shape that hid broken `print.push_status` parsing for weeks, except here it would mean commands vanishing with the cloud never being told. Now a `match` with a loud `Err` arm. Verified end to end against both printers with a throwaway WebSocket server: H2C `RUNNING 88% layer 48/50 13min nozzle 230/230 bed 35/35`, P1P `IDLE 0% nozzle 23.5/0 bed 22.5/0`, both fan commands `ok=true`, zero warnings over 24s. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -48,22 +48,37 @@ cloud control plane (`continuum-backend`).
|
||||
(FTPS upload, fan speed). Requires an explicit printer id and refuses to
|
||||
run unless that printer reports `gcode_state: "IDLE"`.
|
||||
|
||||
## What's still a stub (cont.)
|
||||
## What routes between the cloud and the printers
|
||||
|
||||
The uplink and the printer fleet are wired together, in both directions
|
||||
(`uplink/mod.rs`):
|
||||
|
||||
- **Up:** every 5s, one `PrinterTelemetry` snapshot per printer that has
|
||||
reported, batched into a single `Telemetry` message. Verified live against
|
||||
a P1P and an H2C.
|
||||
- **Down:** a `Command` from the cloud is looked up by our own printer id,
|
||||
executed, and answered with a `CommandResult`. The set of commands is
|
||||
deliberately small - a fan speed and a single gcode line - and deliberately
|
||||
has no "start a print" variant; see `PrinterCommand`.
|
||||
|
||||
One quirk worth knowing: a Bambu on protocol v1 only sends a *complete*
|
||||
status when asked, so each telemetry tick also fires a `pushing.pushall` for
|
||||
the next one. A v1 printer's telemetry is therefore one tick behind, which
|
||||
is why it shows up on the second frame rather than the first.
|
||||
|
||||
## What's still a stub
|
||||
|
||||
`start_uploaded_file` - the MQTT command that actually *starts* a print from
|
||||
an uploaded file - is written but has deliberately never been fired, since
|
||||
that commits a machine to hours of work. Its doc comment lists the three
|
||||
details to confirm on the first real attempt.
|
||||
|
||||
## What's still a stub
|
||||
details to confirm on the first real attempt. `upload_file` is proven, but
|
||||
only with a small text file, not a multi-megabyte sliced `.3mf`.
|
||||
|
||||
PrusaLink (REST) and Klipper/Moonraker (WebSocket) - `printer/prusa.rs`
|
||||
and `printer/klipper.rs` just `println!` what they'd send. Also not built
|
||||
yet: dispatching a cloud-issued command to a connected printer (the uplink
|
||||
and the printer fleet run side by side in `main.rs`, but nothing routes
|
||||
between them yet), local buffering for telemetry across connectivity gaps,
|
||||
LAN printer discovery (SSDP/mDNS), and the mechanical plate-changer
|
||||
interface.
|
||||
yet: local buffering for telemetry across connectivity gaps (so telemetry
|
||||
produced while the uplink is down is simply lost), LAN printer discovery
|
||||
(SSDP/mDNS), and the mechanical plate-changer interface.
|
||||
|
||||
## Getting started
|
||||
|
||||
|
||||
Reference in New Issue
Block a user