First of all: Thank you so much for drawing inspiration from Valetudo and having enough drive to provide a privacy-focused solution for vacuums from Roborock :)!
For my new vacuum (updated to FW v02.51.82 using original App with Internet connection), I tried the following:
I am using Traefik as a reverse proxy (handles Let's Encrypt certificate renewal) for both :555 (https -> http) and :8881 (tcp) to forward to the HA addon. This unfortunately leads to the source IP to be improperly attributed (see below, "<TRAEFIK_IP>" instead of "<VACUUM_IP>"), but I don't think this matters for onboarding (correct me if I'm wrong). HA addon gets fake certs so it doesn't complain about missing certs.
The admin server is running and GUI onboarding seems to be starting as it should. The robot says "connecting to Wifi" after I send the onboarding packet, but then it will just keep blinking and never properly say it's connected as it did before with the app pairing (maybe that's alright?).
The problem now is that it never captures any samples, baseline also stays at "0", pubkey shows "missing" and connected "no". The only thing that even tells me I perhaps did something right is that the live vacuums json object will (after like 3-4 mins into onboarding) go from
//...
"missing_steps": [
"region",
"nc_prepare"
],
//...
to
//...
"missing_steps": [
"nc_prepare"
],
//...
and I can see the "/region" request in the logs. But apart from that, nothing will happen after that.
Also, to even get to that point I needed to change the "DUID" from the cloud import from some cryptic ID (alphanumeric "random" string) to the DID (so DID and DUID are equal). If I don't do that I get a "new" vacuum entry - during onboarding - in the admin overview that is vastly incomplete, with just the DID reported as the DUID, empty DID and empty almost everything:
{
"duid": "110xxxxxxxxxx",
"did": "",
"id_kind": "",
"name": "110xxxxxxxxxx",
"local_key": "",
"source": "",
"key_model": "",
"ips": [
"<TRAEFIK_IP>"
],
"connected": false,
"last_ip": "<TRAEFIK_IP>",
"last_http_at": "2026-06-04T17:35:34.006021+00:00",
"last_http_route": "region",
"last_http_path": "/region",
"last_http_remote": "<TRAEFIK_IP>:40316",
"last_http_host": "api-bla.example.com:555",
"last_mqtt_at": "",
"last_mqtt_topic": "",
"last_mqtt_direction": "",
"last_mqtt_payload_preview": "",
"last_disconnect_at": "",
"last_message_at": "2026-06-04T17:35:34.006021+00:00",
"last_message_source": "http",
"onboarding_steps": {
"region": "2026-06-04T17:35:34.006021+00:00"
},
"onboarding": {
"required_steps": [
"region",
"nc_prepare"
],
"step_labels": {
"region": "Region",
"nc_prepare": "NC Prepare",
"login_key_sign": "Key Sign"
},
"missing_steps": [
"nc_prepare"
],
"has_required_messages": false,
"has_public_key": false,
"public_key_ready": false,
"status": "collecting_messages",
"guidance": "Still waiting for onboarding messages: NC Prepare. The vacuum reached /region, but some models delay NC Prepare for a few minutes.",
"key_state": {
"query_samples": 0,
"header_samples": 0,
"max_signature_len": 0,
"has_modulus": false,
"recovery_state": "collecting",
"recovery_note": "Need at least 2 query signature samples (0 captured).",
"recovery_error": "",
"recovery_started_at": "",
"recovery_finished_at": ""
}
},
"model": "",
"product_id": "",
"inventory_source": ""
}
(it's also missing the "runtime_did" field which the imported complete object has.)
Of course, this lead to not even attributing any traffic to the imported vacuum during onboarding and what I did was to then just override the two inventory json files' DUID with the DID. Also, I had to remove the phantom vacuum from the runtime_credentials.json as the onboarding GUI would otherwise show "Runtime DID 110xxx... is already linked to DUID yyyyyy...; not reassigning it automatically."
As explained above, after rectifying all of that, I ended up with the Saros' entry being updated to the state of "only missing the nc_prepare step".
Now, this begs the question: is this already an indication of "Robot might not be supported"/ "new Firmware might have different behavior" or do you think I should provide some logs so this can be sorted out? I am unsure if the reverse proxy might also be culprit to some extent?
I am asking because it means I will have to manually censor vast amounts of configs/ output (which I am very happy to do!) but maybe this already rings a bell or the lack of "nc_prepare" call is already quite bad?
Thank you in advance!
First of all: Thank you so much for drawing inspiration from Valetudo and having enough drive to provide a privacy-focused solution for vacuums from Roborock :)!
For my new vacuum (updated to FW v02.51.82 using original App with Internet connection), I tried the following:
I am using Traefik as a reverse proxy (handles Let's Encrypt certificate renewal) for both :555 (https -> http) and :8881 (tcp) to forward to the HA addon. This unfortunately leads to the source IP to be improperly attributed (see below, "<TRAEFIK_IP>" instead of "<VACUUM_IP>"), but I don't think this matters for onboarding (correct me if I'm wrong). HA addon gets fake certs so it doesn't complain about missing certs.
The admin server is running and GUI onboarding seems to be starting as it should. The robot says "connecting to Wifi" after I send the onboarding packet, but then it will just keep blinking and never properly say it's connected as it did before with the app pairing (maybe that's alright?).
The problem now is that it never captures any samples, baseline also stays at "0", pubkey shows "missing" and connected "no". The only thing that even tells me I perhaps did something right is that the live vacuums json object will (after like 3-4 mins into onboarding) go from
to
and I can see the "/region" request in the logs. But apart from that, nothing will happen after that.
Also, to even get to that point I needed to change the "DUID" from the cloud import from some cryptic ID (alphanumeric "random" string) to the DID (so DID and DUID are equal). If I don't do that I get a "new" vacuum entry - during onboarding - in the admin overview that is vastly incomplete, with just the DID reported as the DUID, empty DID and empty almost everything:
{ "duid": "110xxxxxxxxxx", "did": "", "id_kind": "", "name": "110xxxxxxxxxx", "local_key": "", "source": "", "key_model": "", "ips": [ "<TRAEFIK_IP>" ], "connected": false, "last_ip": "<TRAEFIK_IP>", "last_http_at": "2026-06-04T17:35:34.006021+00:00", "last_http_route": "region", "last_http_path": "/region", "last_http_remote": "<TRAEFIK_IP>:40316", "last_http_host": "api-bla.example.com:555", "last_mqtt_at": "", "last_mqtt_topic": "", "last_mqtt_direction": "", "last_mqtt_payload_preview": "", "last_disconnect_at": "", "last_message_at": "2026-06-04T17:35:34.006021+00:00", "last_message_source": "http", "onboarding_steps": { "region": "2026-06-04T17:35:34.006021+00:00" }, "onboarding": { "required_steps": [ "region", "nc_prepare" ], "step_labels": { "region": "Region", "nc_prepare": "NC Prepare", "login_key_sign": "Key Sign" }, "missing_steps": [ "nc_prepare" ], "has_required_messages": false, "has_public_key": false, "public_key_ready": false, "status": "collecting_messages", "guidance": "Still waiting for onboarding messages: NC Prepare. The vacuum reached /region, but some models delay NC Prepare for a few minutes.", "key_state": { "query_samples": 0, "header_samples": 0, "max_signature_len": 0, "has_modulus": false, "recovery_state": "collecting", "recovery_note": "Need at least 2 query signature samples (0 captured).", "recovery_error": "", "recovery_started_at": "", "recovery_finished_at": "" } }, "model": "", "product_id": "", "inventory_source": "" }(it's also missing the "runtime_did" field which the imported complete object has.)
Of course, this lead to not even attributing any traffic to the imported vacuum during onboarding and what I did was to then just override the two inventory json files' DUID with the DID. Also, I had to remove the phantom vacuum from the
runtime_credentials.jsonas the onboarding GUI would otherwise show "Runtime DID 110xxx... is already linked to DUID yyyyyy...; not reassigning it automatically."As explained above, after rectifying all of that, I ended up with the Saros' entry being updated to the state of "only missing the nc_prepare step".
Now, this begs the question: is this already an indication of "Robot might not be supported"/ "new Firmware might have different behavior" or do you think I should provide some logs so this can be sorted out? I am unsure if the reverse proxy might also be culprit to some extent?
I am asking because it means I will have to manually censor vast amounts of configs/ output (which I am very happy to do!) but maybe this already rings a bell or the lack of "nc_prepare" call is already quite bad?
Thank you in advance!