Bambu's `stg_cur`: what a printer is doing when it is not laying down plastic - bed levelling, nozzle cleaning, extrusion calibration. Passed through as the printer's own number rather than decoded, because the code-to-name table is not something we have. 0 means printing. It is here because progress without it is ambiguous in a way that reads as a fault. Confirmed on a P1P (2026-10-11): `percent` climbed to 14% while `layer` stayed 0 for several minutes, the printer working through stages 54, 14 and 13 before starting layer 1. A console showing 14% at layer 0 with no stage looks stuck, and an operator would reasonably go and power-cycle a machine that was working perfectly. Optional and additive, so gateways that predate it are unaffected.
115 lines
7.1 KiB
JSON
115 lines
7.1 KiB
JSON
{
|
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
"$id": "https://git.octoturge.com/Continuum/continuum-schemas/raw/branch/main/schemas/continuum/v1/edge/printer_telemetry.schema.json",
|
|
"title": "PrinterTelemetry",
|
|
"description": "A flattened snapshot of one printer, in the terms an operator console displays. Deliberately not any vendor's native status shape: it has to describe a Bambu, a Prusa and a Klipper printer alike, and Bambu's wire format in particular has traps that should not reach the rest of the system (fan speeds are 0-15 gears rather than a percent, temperatures arrive as either integers or floats, and protocol v2 reuses one sequence_id indefinitely). Every field but printer_id and name is optional, because a printer that is unreachable or has only just connected genuinely has nothing to report, and 'no data yet' is not the same as zero.",
|
|
"type": "object",
|
|
"properties": {
|
|
"printer_id": {
|
|
"type": "string",
|
|
"description": "The gateway's own id for this printer, from its printers.toml - NOT the vendor serial number and NOT the backend's printers.id UUID. The backend resolves it to a UUID via printers.gateway_printer_id, scoped to the farm the gateway authenticated as."
|
|
},
|
|
"name": {
|
|
"type": "string"
|
|
},
|
|
"state": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"description": "The printer's own state string, passed through rather than narrowed to an enum here, so an unrecognised state reaches the backend as itself instead of being dropped at the edge. Bambu emits IDLE, RUNNING, PAUSE, FINISH and FAILED. Readers must accept an explicit null here as equivalent to the key being absent: a gateway omits what it has no value for, but a serde-derived Rust producer emits null unless every field is annotated, and rejecting a whole batch over that is not worth it."
|
|
},
|
|
"percent": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"minimum": 0,
|
|
"maximum": 100,
|
|
"description": "Readers must accept an explicit null here as equivalent to the key being absent: a gateway omits what it has no value for, but a serde-derived Rust producer emits null unless every field is annotated, and rejecting a whole batch over that is not worth it."
|
|
},
|
|
"stage": {
|
|
"type": "integer",
|
|
"description": "The printer's current stage, when it is doing something other than laying down plastic: bed levelling, nozzle cleaning, extrusion calibration and so on. Bambu's `stg_cur`, passed through as the printer's own number rather than decoded, because the code-to-name table is not something we have. 0 means printing.\n\nWithout this, progress is ambiguous in a way that reads as a fault. Confirmed on a P1P (2026-10-11): `percent` climbed to 14% while `layer` stayed 0 for several minutes, because the printer was working through its pre-print stages - it reported `stg_cur` 54, then 14, then 13, then 0, and only then began layer 1. A console showing 14% at layer 0 with no stage looks stuck."
|
|
},
|
|
"layer": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"minimum": 0,
|
|
"description": "Readers must accept an explicit null here as equivalent to the key being absent: a gateway omits what it has no value for, but a serde-derived Rust producer emits null unless every field is annotated, and rejecting a whole batch over that is not worth it."
|
|
},
|
|
"total_layers": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"minimum": 0,
|
|
"description": "Readers must accept an explicit null here as equivalent to the key being absent: a gateway omits what it has no value for, but a serde-derived Rust producer emits null unless every field is annotated, and rejecting a whole batch over that is not worth it."
|
|
},
|
|
"remaining_minutes": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"minimum": 0,
|
|
"description": "Readers must accept an explicit null here as equivalent to the key being absent: a gateway omits what it has no value for, but a serde-derived Rust producer emits null unless every field is annotated, and rejecting a whole batch over that is not worth it."
|
|
},
|
|
"job_name": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"description": "Normalised at the edge: a Bambu reports an empty string rather than omitting the field when idle, and the gateway turns that into an absent value so consumers need not know it. Readers must accept an explicit null here as equivalent to the key being absent: a gateway omits what it has no value for, but a serde-derived Rust producer emits null unless every field is annotated, and rejecting a whole batch over that is not worth it."
|
|
},
|
|
"nozzle_temp": {
|
|
"type": [
|
|
"number",
|
|
"null"
|
|
],
|
|
"description": "Readers must accept an explicit null here as equivalent to the key being absent: a gateway omits what it has no value for, but a serde-derived Rust producer emits null unless every field is annotated, and rejecting a whole batch over that is not worth it."
|
|
},
|
|
"nozzle_target": {
|
|
"type": [
|
|
"number",
|
|
"null"
|
|
],
|
|
"description": "Readers must accept an explicit null here as equivalent to the key being absent: a gateway omits what it has no value for, but a serde-derived Rust producer emits null unless every field is annotated, and rejecting a whole batch over that is not worth it."
|
|
},
|
|
"bed_temp": {
|
|
"type": [
|
|
"number",
|
|
"null"
|
|
],
|
|
"description": "Readers must accept an explicit null here as equivalent to the key being absent: a gateway omits what it has no value for, but a serde-derived Rust producer emits null unless every field is annotated, and rejecting a whole batch over that is not worth it."
|
|
},
|
|
"bed_target": {
|
|
"type": [
|
|
"number",
|
|
"null"
|
|
],
|
|
"description": "Readers must accept an explicit null here as equivalent to the key being absent: a gateway omits what it has no value for, but a serde-derived Rust producer emits null unless every field is annotated, and rejecting a whole batch over that is not worth it."
|
|
},
|
|
"print_error": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"description": "Vendor error code. Non-zero means the printer is reporting a fault. Readers must accept an explicit null here as equivalent to the key being absent: a gateway omits what it has no value for, but a serde-derived Rust producer emits null unless every field is annotated, and rejecting a whole batch over that is not worth it."
|
|
},
|
|
"active_alerts": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"minimum": 0,
|
|
"description": "How many Health-Management-System entries the printer currently has active. A count only for now - decoding the {attr, code} pairs into messages needs Bambu's HMS tables, which Continuum does not have. Readers must accept an explicit null here as equivalent to the key being absent: a gateway omits what it has no value for, but a serde-derived Rust producer emits null unless every field is annotated, and rejecting a whole batch over that is not worth it."
|
|
}
|
|
},
|
|
"required": [
|
|
"printer_id",
|
|
"name"
|
|
]
|
|
}
|