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.
This commit is contained in:
@@ -62,6 +62,11 @@ export const AppPrinterStateSchema = Type.Object({
|
|||||||
* calling; null means render no player at all.
|
* calling; null means render no player at all.
|
||||||
*/
|
*/
|
||||||
cameraStream: Type.Optional(Nullable(Type.String())),
|
cameraStream: Type.Optional(Nullable(Type.String())),
|
||||||
|
/**
|
||||||
|
* True when the camera can only be read as refreshing JPEG frames (Bambu
|
||||||
|
* P1/A1); `GET /printers/:id/stream` then answers `kind: "snapshot"`.
|
||||||
|
*/
|
||||||
|
cameraSnapshot: Type.Optional(Type.Boolean()),
|
||||||
/**
|
/**
|
||||||
* When a gateway last reported this printer; null means never. This is how
|
* 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
|
* a client tells "idle" from "nobody has heard from it in an hour", which
|
||||||
|
|||||||
@@ -65,6 +65,11 @@ export const PrinterTelemetrySchema = Type.Object({
|
|||||||
* implements yet.
|
* implements yet.
|
||||||
*/
|
*/
|
||||||
camera_stream: Maybe(Type.String()),
|
camera_stream: Maybe(Type.String()),
|
||||||
|
/**
|
||||||
|
* The camera can only be read as single JPEG frames (Bambu P1/A1) and the
|
||||||
|
* gateway answers `camera_snapshot_request` for it.
|
||||||
|
*/
|
||||||
|
camera_snapshot: Maybe(Type.Boolean()),
|
||||||
layer: Maybe(Type.Integer({ minimum: 0 })),
|
layer: Maybe(Type.Integer({ minimum: 0 })),
|
||||||
total_layers: Maybe(Type.Integer({ minimum: 0 })),
|
total_layers: Maybe(Type.Integer({ minimum: 0 })),
|
||||||
remaining_minutes: Maybe(Type.Integer({ minimum: 0 })),
|
remaining_minutes: Maybe(Type.Integer({ minimum: 0 })),
|
||||||
@@ -296,6 +301,13 @@ export const EdgeClientMessageSchema = Type.Union([
|
|||||||
session_id: Type.String(),
|
session_id: Type.String(),
|
||||||
message: Type.String(),
|
message: Type.String(),
|
||||||
}),
|
}),
|
||||||
|
/** One JPEG frame from a `camera_snapshot_request`, or why there is none. */
|
||||||
|
Type.Object({
|
||||||
|
type: Type.Literal("camera_snapshot"),
|
||||||
|
request_id: Type.String(),
|
||||||
|
jpeg_base64: Maybe(Type.String()),
|
||||||
|
error: Maybe(Type.String()),
|
||||||
|
}),
|
||||||
Type.Object({
|
Type.Object({
|
||||||
type: Type.Literal("frame_batch"),
|
type: Type.Literal("frame_batch"),
|
||||||
printer_id: Type.String(),
|
printer_id: Type.String(),
|
||||||
@@ -367,6 +379,20 @@ export const EdgeServerMessageSchema = Type.Union([
|
|||||||
/** The browser's offer SDP, passed through verbatim. */
|
/** The browser's offer SDP, passed through verbatim. */
|
||||||
sdp: Type.String(),
|
sdp: Type.String(),
|
||||||
}, { additionalProperties: false }),
|
}, { additionalProperties: false }),
|
||||||
|
/**
|
||||||
|
* Read one JPEG frame from a printer whose camera is not RTSP (Bambu P1/A1).
|
||||||
|
* Unlike `webrtc_offer` the picture itself crosses the cloud: frames are
|
||||||
|
* small and requested one at a time.
|
||||||
|
*/
|
||||||
|
Type.Object(
|
||||||
|
{
|
||||||
|
type: Type.Literal("camera_snapshot_request"),
|
||||||
|
request_id: Type.String(),
|
||||||
|
/** The gateway's own printer id. */
|
||||||
|
printer_id: Type.String(),
|
||||||
|
},
|
||||||
|
{ additionalProperties: false },
|
||||||
|
),
|
||||||
Type.Object({
|
Type.Object({
|
||||||
type: Type.Literal("command"),
|
type: Type.Literal("command"),
|
||||||
command_id: Type.String(),
|
command_id: Type.String(),
|
||||||
|
|||||||
@@ -62,6 +62,10 @@
|
|||||||
"type": ["string", "null"],
|
"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."
|
"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": {
|
"lastSeenAt": {
|
||||||
"type": ["string", "null"],
|
"type": ["string", "null"],
|
||||||
"format": "date-time",
|
"format": "date-time",
|
||||||
|
|||||||
@@ -183,6 +183,18 @@
|
|||||||
"message"
|
"message"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"title": "CameraSnapshot",
|
||||||
|
"description": "The answer to a CameraSnapshotRequest: one JPEG frame (base64), or the reason there is none.",
|
||||||
|
"properties": {
|
||||||
|
"type": { "const": "camera_snapshot" },
|
||||||
|
"request_id": { "type": "string" },
|
||||||
|
"jpeg_base64": { "type": "string" },
|
||||||
|
"error": { "type": "string", "description": "Set instead of jpeg_base64 when no frame could be read." }
|
||||||
|
},
|
||||||
|
"required": ["type", "request_id"]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"title": "DiscoveredPrinters",
|
"title": "DiscoveredPrinters",
|
||||||
|
|||||||
@@ -108,7 +108,11 @@
|
|||||||
},
|
},
|
||||||
"camera_stream": {
|
"camera_stream": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The stream name to ask the gateway's stream_base_url for, when this printer has a camera the gateway could restream. Absent means no stream: either the printer reports no camera source, or it is a model whose camera is not reachable this way. That second case is the common one today - a Bambu P1/A1 does not publish an RTSP URL at all (confirmed: a P1P's ipcam block has ipcam_dev and ipcam_record and no rtsp_url), and only the X1/H2 class does. Those need Bambu's proprietary port-6000 JPEG stream instead, which is a separate client this gateway does not have yet."
|
"description": "The stream name to ask the gateway's stream_base_url for, when this printer has a camera the gateway could restream. Absent means no stream: either the printer reports no camera source, or it is a model whose camera is not reachable this way. That second case is the common one today - a Bambu P1/A1 does not publish an RTSP URL at all (confirmed: a P1P's ipcam block has ipcam_dev and ipcam_record and no rtsp_url), and only the X1/H2 class does. Those are served by camera_snapshot instead."
|
||||||
|
},
|
||||||
|
"camera_snapshot": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "True when this printer's camera can only be read as single JPEG frames (a Bambu P1/A1: proprietary TLS stream on port 6000, no RTSP) and the gateway will answer a CameraSnapshotRequest for it. Mutually exclusive with camera_stream in practice. Absent means false."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
|
|||||||
@@ -110,6 +110,18 @@
|
|||||||
],
|
],
|
||||||
"additionalProperties": false
|
"additionalProperties": false
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"title": "CameraSnapshotRequest",
|
||||||
|
"description": "Read one JPEG frame from a printer's camera and send it back as a CameraSnapshot. For the printers whose camera is not RTSP (Bambu P1/A1, telemetry camera_snapshot true). Unlike WebrtcOffer this DOES carry the picture through the cloud, which is acceptable only because the frames are small, low-rate and requested one at a time.",
|
||||||
|
"properties": {
|
||||||
|
"type": { "const": "camera_snapshot_request" },
|
||||||
|
"request_id": { "type": "string" },
|
||||||
|
"printer_id": { "type": "string", "description": "The gateway's own printer id." }
|
||||||
|
},
|
||||||
|
"required": ["type", "request_id", "printer_id"],
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"title": "ProvisionPrinter",
|
"title": "ProvisionPrinter",
|
||||||
|
|||||||
Reference in New Issue
Block a user