You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Hello,
I have a question, not a real issue, but I'm not sure where to place it. Maybe it's worth to enable discussions?
So the question:
My robot has a remote function, were is is possible to see the camera image. This is not working - a timeout error appears instantly after klicking on the camera symbol in the app. Is that supposed to be like that or should I've enabled that before switching to the local server?
Was about to suggest trying localrock, because my vacuum doesnt have live camera feed so could not test it. Thanks for sharing ill tinker about more with it. And hopefully fix it ;)
if you could capture the request that happens on the local server, that happens when you press the preview on the app (logs + the MQTT rr/... topics) that would help alot. I think we need to implement a turn server so we can answer the robots provisioning request. Beccause it looks like from the error code that the robot is trying to fetch a turn server config for the preview setup. but cant since we redirect the api domain to local server ;)
Following up on the TURN idea from July — that instinct was right, and I got live camera working end to end against the local server on a Roborock Saros 10R (roborock.vacuum.a144, US firmware 02.33.88). Sharing the full recipe since a few of you don't have a camera-capable unit to test on.
There are three missing pieces, not just the TURN server:
1. The robot asks the server for TURN credentials via a fwapi call the server doesn't currently answer.
After the preview is requested, the firmware POSTs to a path ending in /fwapi/createca. If that request isn't answered, the app shows the instant "request turnserver failed" / timeout. The response that works is plain JSON:
I run coturn (long-term credentials, relay ports 49160-49200/udp) and the robot completes the full WebRTC handshake against it.
2. The robot derives the fwapi/TURN host from the onboarding region string, truncated to 15 characters.
The firmware builds the host as region[:15] + "iot.roborock.com". So to make the robot send createca to your own server, the region must be exactly 15 characters and resolve to you, e.g. a 15-char domain you control. With that, the robot calls https://<your-host>/iot.roborock.com/fwapi/createca instead of the real cloud. A region string without a port makes it use 443.
3. On this model the stream only starts after the two-key physical activation. set_camera_status with the two-key request bits set and the monitor bit off, then a press of the Power button on the robot within ~60s. The firmware then sets the monitor bit itself. Enabling the remote-view PIN first (set_homesec_password) is also required. Without this the robot answers start_camera_preview with -10012 camera status denied preview regardless of TURN.
With all three in place, a go2rtc roborock:// source (MQTT 8881 + the session keys + local key + PIN) runs the handshake and I get frames. I captured the createca request/response and the rr/... MQTT exchange around start_camera_preview and can post sanitized logs here.
Caveat: this is one model on US firmware, so the exact bit layout for activation may differ per device, but the createca shape and the region-host rule look like general firmware behavior.
Happy to open a PR that adds the createca handler to the server and documents the TURN requirement, if that's a direction you'd take.
Awesome @cptntrps! I have been looking at this a bit in the background - Restarted recently after seeing this message here: #140
Looking at the firmware, your conclusion is roughly the same I came to. If you would like to do the PR that would be great and I can review it. I'll add some tooling around the onboarding ui/cli as well stating that if you want the camera to work you need a region under 15 characters, which is a pretty tight fit. And actually, the region has to be under 14 characters as it needs a trailing '/'.
Live camera confirmed on Saros 20X (roborock.vacuum.a288), firmware 02.55.44, region EU
Setup: server built from main at c3b3284 (#144/#155), [turn] mode = "provided", onboarding via LocalRock, original Roborock app 4.74.04 (patched) logged in through the MITM helper. Live video works in the original app; the robot fetched POST /iot.roborock.com/fwapi/createca (route fw_createca) and the embedded coturn relayed the stream.
Findings that may help others with an a288:
The a288 builds the camera bootstrap URL from token.r (like the Qrevo MaxV), not from country_domain (like the Saros 10R). It takes the first 15 characters of token.r and appends iot.roborock.com. With a stack host of api-. this means ./ must fit into 15 characters including the trailing slash, so the hostname may have at most 14 characters. A longer name (17 characters in my case) produced lookups like xxxx.duckdns.oriot.roborock.com. I moved the whole stack to a short name and re-onboarded; one onboarding pass was enough because the public key was already recovered.
The original app failed with "Device initialization failed -21020" right after re-login, without sending a single RPC. Two changes made it work for me (I could not determine which one was decisive, both are harmless):
ALL_HTTP_METHODS in server.py lacked HEAD. The app sends HEAD /time/now to the stack host on port 443 and got a 405. Adding "HEAD" fixed that.
MODEL_PRODUCT_ID_OVERRIDES had no entry for the a288, so /api/v5/product returned a hashed product id (188724). Roborock's cloud returns 251 for the Saros 20. Adding "roborock.vacuum.a288": 251 fixed it.
Both changes only took effect after logging out and back in through the MITM helper; restarting the app was not enough.
Unlike the Saros 10R, no activation on the robot (PIN plus button) was needed. The live view started right after entering the remote-view pattern in the app.
Activity
[-]Remote function[/-][+]Remote camera function[/+]Lash-L commentedon Apr 19, 2026
It's likely I need to add some wiring for the connection stream. I will take a look!
DonSidro commentedon Jul 10, 2026
What platform are you on (Android/iOS)?
Thomas55555 commentedon Jul 10, 2026
Android
Thomas55555 commentedon Jul 10, 2026
I just tried it with LocalRock for testing and got this
DonSidro commentedon Jul 10, 2026
Was about to suggest trying localrock, because my vacuum doesnt have live camera feed so could not test it. Thanks for sharing ill tinker about more with it. And hopefully fix it ;)
if you could capture the request that happens on the local server, that happens when you press the preview on the app (logs + the MQTT rr/... topics) that would help alot. I think we need to implement a turn server so we can answer the robots provisioning request. Beccause it looks like from the error code that the robot is trying to fetch a turn server config for the preview setup. but cant since we redirect the api domain to local server ;)
cptntrps commentedon Oct 9, 2026
Following up on the TURN idea from July — that instinct was right, and I got live camera working end to end against the local server on a Roborock Saros 10R (
roborock.vacuum.a144, US firmware 02.33.88). Sharing the full recipe since a few of you don't have a camera-capable unit to test on.There are three missing pieces, not just the TURN server:
1. The robot asks the server for TURN credentials via a fwapi call the server doesn't currently answer.
After the preview is requested, the firmware POSTs to a path ending in
/fwapi/createca. If that request isn't answered, the app shows the instant "request turnserver failed" / timeout. The response that works is plain JSON:{ "code": 200, "msg": "success", "data": { "url": "turn:<your-server-host>:3478", "user": "<turn-user>", "pwd": "<turn-pass>", "ttl": 86400, "urls": ["turn:<your-server-host>:3478", "stun:<your-server-host>:3478"], "username": "<turn-user>", "credential": "<turn-pass>", "realm": "<turn-realm>" }, "result": { "...same object..." } }I run coturn (long-term credentials, relay ports 49160-49200/udp) and the robot completes the full WebRTC handshake against it.
2. The robot derives the fwapi/TURN host from the onboarding region string, truncated to 15 characters.
The firmware builds the host as
region[:15] + "iot.roborock.com". So to make the robot sendcreatecato your own server, the region must be exactly 15 characters and resolve to you, e.g. a 15-char domain you control. With that, the robot callshttps://<your-host>/iot.roborock.com/fwapi/createcainstead of the real cloud. A region string without a port makes it use 443.3. On this model the stream only starts after the two-key physical activation.
set_camera_statuswith the two-key request bits set and the monitor bit off, then a press of the Power button on the robot within ~60s. The firmware then sets the monitor bit itself. Enabling the remote-view PIN first (set_homesec_password) is also required. Without this the robot answersstart_camera_previewwith-10012 camera status denied previewregardless of TURN.With all three in place, a go2rtc
roborock://source (MQTT 8881 + the session keys + local key + PIN) runs the handshake and I get frames. I captured thecreatecarequest/response and therr/...MQTT exchange aroundstart_camera_previewand can post sanitized logs here.Caveat: this is one model on US firmware, so the exact bit layout for activation may differ per device, but the createca shape and the region-host rule look like general firmware behavior.
Happy to open a PR that adds the
createcahandler to the server and documents the TURN requirement, if that's a direction you'd take.Lash-L commentedon Oct 9, 2026
Awesome @cptntrps! I have been looking at this a bit in the background - Restarted recently after seeing this message here: #140
Looking at the firmware, your conclusion is roughly the same I came to. If you would like to do the PR that would be great and I can review it. I'll add some tooling around the onboarding ui/cli as well stating that if you want the camera to work you need a region under 15 characters, which is a pretty tight fit. And actually, the region has to be under 14 characters as it needs a trailing '/'.
feat(camera): answer the robot's fwapi/createca TURN request for live…
feat(camera): answer the robot's fwapi/createca TURN request for live…
Brat-Wurscht commentedon Oct 13, 2026
Live camera confirmed on Saros 20X (roborock.vacuum.a288), firmware 02.55.44, region EU
Setup: server built from main at c3b3284 (#144/#155), [turn] mode = "provided", onboarding via LocalRock, original Roborock app 4.74.04 (patched) logged in through the MITM helper. Live video works in the original app; the robot fetched POST /iot.roborock.com/fwapi/createca (route fw_createca) and the embedded coturn relayed the stream.
Findings that may help others with an a288:
Both changes only took effect after logging out and back in through the MITM helper; restarting the app was not enough.