Files
octoturge 1b1df9c438 Add camera snapshot messages and flag for P1/A1 cameras
camera_snapshot_request (cloud to gateway) and camera_snapshot (gateway
to cloud) carry one JPEG frame at a time; telemetry gains camera_snapshot
and the app view gains cameraSnapshot.
2026-10-29 15:53:50 +00:00

79 lines
4.9 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/app/telemetry_message.schema.json",
"title": "AppTelemetryMessage",
"description": "What continuum-backend pushes down /ws/telemetry to an operator console. Discriminated on 'type'. NOTE the casing: camelCase, unlike continuum/v1/edge/ and every other schema here, because this is the backend's own HTTP vocabulary rather than a format shared with the Rust gateway - the browser already consumes camelCase from GET /printers and should not have to hold two models of a printer. A previous frontend invented its own shape against nothing (printerId, nozzleTempC, progressPct, a closed state enum) and no backend ever sent it; this file exists so both ends have something to mirror.",
"oneOf": [
{
"type": "object",
"title": "PrinterTelemetryPush",
"description": "One printer's current state, sent whenever its gateway reports a change. The payload is deliberately the same shape GET /printers/:id returns, so a client can apply it to the row it already has rather than reconciling two vocabularies. Only printers in an organisation the authenticated user belongs to are ever sent.",
"properties": {
"type": { "const": "printer.telemetry" },
"printer": { "$ref": "#/$defs/PrinterState" }
},
"required": ["type", "printer"],
"additionalProperties": false
},
{
"type": "object",
"title": "Ready",
"description": "Sent once, immediately after the socket authenticates, naming how many printers the user can see. Worth its own message rather than leaving the client to infer readiness from silence: an operator with no printers claimed and an operator whose gateway is offline both see nothing arrive, and those need different things said to them.",
"properties": {
"type": { "const": "ready" },
"visiblePrinters": { "type": "integer", "minimum": 0 }
},
"required": ["type", "visiblePrinters"],
"additionalProperties": false
}
],
"$defs": {
"PrinterState": {
"type": "object",
"description": "A printer as the console displays it. Every telemetry field is nullable because a printer that has never reported has no temperature, and 'no data yet' is not 0 degrees.",
"properties": {
"id": { "type": "string", "format": "uuid" },
"farmId": { "type": "string", "format": "uuid" },
"name": { "type": "string" },
"vendor": { "type": "string" },
"status": {
"type": ["string", "null"],
"description": "The backend's own narrowed status, which the UI filters and groups on."
},
"vendorState": {
"type": ["string", "null"],
"description": "The printer's own word for what it is doing - a Bambu's 'RUNNING', 'PREPARE', 'FINISH'. Kept alongside 'status' rather than replaced by it, because the narrowed enum necessarily loses detail an operator sometimes needs. Not an enum here on purpose: an unrecognised state must reach the screen as itself rather than being dropped."
},
"vendorErrorCode": { "type": ["integer", "null"] },
"nozzleTempC": { "type": ["number", "null"] },
"nozzleTargetTempC": { "type": ["number", "null"] },
"bedTempC": { "type": ["number", "null"] },
"bedTargetTempC": { "type": ["number", "null"] },
"progressPercent": { "type": ["integer", "null"] },
"currentLayer": { "type": ["integer", "null"] },
"totalLayers": { "type": ["integer", "null"] },
"remainingMinutes": { "type": ["integer", "null"] },
"currentJobName": { "type": ["string", "null"] },
"activeAlerts": {
"type": ["integer", "null"],
"description": "How many Health-Management-System entries the printer currently has active. A count, not messages: decoding them needs Bambu's HMS tables, which Continuum does not have."
},
"cameraStream": {
"type": ["string", "null"],
"description": "The go2rtc stream name, when this printer has a camera that can actually be restreamed. Null is the common case - only Bambu's X1/H2 class publishes an RTSP URL. Present means it is worth calling GET /printers/:id/stream; null means render no player."
},
"cameraSnapshot": {
"type": "boolean",
"description": "True when the camera can only be read as refreshing JPEG frames (Bambu P1/A1); GET /printers/:id/stream then answers kind 'snapshot'."
},
"lastSeenAt": {
"type": ["string", "null"],
"format": "date-time",
"description": "When a gateway last reported this printer. Null means never. This is how a client tells 'idle' from 'nobody has heard from it in an hour', which the status alone cannot say."
}
},
"required": ["id", "farmId", "name", "vendor"]
}
}
}