Fix camera on CC1 firmware >= V1.4.x: enable video stream via SDCP Cmd 386 - #4
Open
AeromXundes wants to merge 1 commit into
Open
Fix camera on CC1 firmware >= V1.4.x: enable video stream via SDCP Cmd 386#4AeromXundes wants to merge 1 commit into
AeromXundes wants to merge 1 commit into
Conversation
…d 386 Newer CC1 firmware gates the MJPEG port behind Cmd 386: :3031/video accepts connections but emits no frames until the stream is enabled, so snapshot, /stream, and the RTSP bridge all timed out. Verified live on V1.4.49; V0.3.0-o streams unconditionally and acks the enable harmlessly. - add Cmd.ENABLE_VIDEO_STREAM = 386 (commented out in the official SDK but firmware-handled, same story as Cmds 258/259) - add Printer.enable_video_stream() returning the firmware VideoUrl; no-op override on CC2Printer (its camera does not gate on SDCP) - snapshot() sends the enable best-effort before reading the camera - server re-sends the enable on every (re)connect so /stream, /snapshot and RTSP recover after printer reboots (the enable resets with them) - tests: fake printer acks Cmd 386 with a VideoUrl; round-trip + snapshot-ordering tests Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
On a CC1 updated to firmware V1.4.49, every camera surface times out:
centauri snapshotraisesReadTimeout, and the server's/snapshot,/stream, and RTSP bridge all 502. The MJPEG port itself looks healthy —GET http://<printer>:3031/videoanswersHTTP 200— but the body iszero bytes, indefinitely.
This is distinct from the connection-slot starvation fixed in 0.7.0's
CameraBroadcaster: it reproduces from a fresh printer boot with exactly oneclient connected.
Timing note: V1.4.49 shipped 2026-07-29 — after this library's last release
(v0.9.0, 2026-07-16) — which may be why it hasn't been reported. I can only
attest V1.1.29 (no gate) and V1.4.49 (gate); the earlier V1.4.x releases
(April/May 2026) are untested and may also be affected.
Root cause
Newer firmware gates the MJPEG stream behind SDCP Cmd 386 ("enable video
stream"): the port accepts connections but emits no frames until the stream is
enabled. pycentauri never sends Cmd 386 — older firmware streamed
unconditionally, so it never had to.
Cmd 386 is present-but-commented-out in the official SDK
(
elegoo_fdm_cc_message_adapter.cpp:// {MethodType::VIDEO_STREAM, 386}, // Get camera video stream) — the same situation as Cmds 258/259, which thislibrary already ships. Request payload is
{"Enable": 1|0}; the responseDatacarries{"Ack": 0}plus aVideoUrl. Ack codes (per the OpenCentauriSDCP docs, https://docs.opencentauri.cc/software/api/): 0 = success,
1 = max streams exceeded, 2 = camera does not exist, 3 = unknown error.
Verified live on V1.4.49: sending Cmd 386 once makes
:3031/videostreamimmediately; the enable is global on the printer and resets when it reboots.
Changes
sdcp.Cmd.ENABLE_VIDEO_STREAM = 386, with the SDK reference comment.Printer.set_video_stream(enabled=True, force=False)— returnsthe firmware-reported
VideoUrl, if any. Version-gated: the command isonly sent when the firmware version the printer reports in its Attributes
parses to >= V1.4; on older or unknown firmware it is a no-op returning
Noneunlessforce=True.CC2Printeroverrides it as a documented no-op(the CC2 camera does not gate on SDCP).
Printer.snapshot()enables the stream first (capped atmin(timeout, 8 s)so SDCP waits can't eat the camera-read budget;failures logged, read still attempted), then adopts the port/path of
the returned
VideoUrlwhile always connecting to the configured host —the printer reports its own LAN address in the URL, which is the wrong
host behind a tunnel/NAT, and a firmware-controlled string shouldn't pick
the fetch target anyway. Note: V1.4.49 returns the URL scheme-less
(
172.16.2.78:3031/video) even though the OpenCentauri docs showhttp://…— the client normalizes before parsing.centauri rtspcommand sends the enable (short-lived SDCPconnection) before wiring ffmpeg to the MJPEG port — it previously relied
on the stream being ungated. If the printer reboots while the bridge
runs, re-run the command.
/streambroadcaster and the RTSP configstill build their upstream URL from the static host:port. Today V1.4.49
reports the same
<ip>:3031/video, so behavior is identical; unifyingall camera consumers behind one resolved port/path is left for a
follow-up to keep this diff small.
PrinterManager(server) sends the enable on every (re)connect, so/stream,/snapshot, and RTSP recover automatically after printerreboots.
[Unreleased]; three new unit tests (the fake printermodels Cmd 386 from its firmware version, and its
VideoUrldeliberatelycarries a different host than the fake itself so a client that dials
the reported host fails the suite): round-trip envelope/normalization,
snapshot ordering + port/path-but-not-host adoption (asserted at camera
read time), and pre-V1.4 firmware never receiving the command without
force=True.Compatibility
Pre-V1.4 firmware streams without the enable (this library never sent Cmd 386
and the camera worked). The command is documented for those versions too, but
I could not test it there — so rather than send an unverified command at
someone else's firmware, the client never sends Cmd 386 below V1.4 (or
when the version is unknown).
force=Trueexists for anyone who wants toprobe their own printer deliberately.
Testing
ruff check/ruff format --checkclean; full suite: 96 passed(mypy has pre-existing errors in
mcp/server.pyonly, untouched here)./snapshot,/stream, andreverse-proxied access all verified working from a cold service start with
this branch installed; before the change all of them timed out.
🤖 Generated with Claude Code