Skip to content

Onboarding report: Roborock Saros 10R success on firmware 02.50.56 using pfSense + HAProxy #78

Description

@BlackRockCity

This is a real issue?

  • I have confirmed this is a issue, not a report that the project works on my device.

What happened?

Onboarding report: Roborock Saros 10R success on firmware 02.50.56 using pfSense + HAProxy

I successfully onboarded a Roborock Saros 10R to local_roborock_server running firmware 02.50.56.

I'm posting this partly as a companion data point to #61, where @skittyxan reported a successful Saros 10R installation on firmware 02.52.86. My network architecture and onboarding path were substantially different, so this may be useful for anyone running pfSense/Home Assistant or trying to put HAProxy in front of the local server.

I have also published a separate companion repository documenting this installation and related configuration work:

Roborock Local Server Guides

This issue is intended primarily as an onboarding report and tested configuration data point. The GitLab project is the better place for longer-form implementation notes and guides that can continue to evolve independently of this issue.

Setup

  • Model: Roborock Saros 10R
  • Firmware: 02.50.56
  • Home automation: Home Assistant OS
  • Local server: local_roborock_server Home Assistant add-on
  • Router/firewall: pfSense
  • Reverse proxy: HAProxy running on pfSense
  • Certificates: ACME package on pfSense
  • DNS: Cloudflare
  • Public HTTPS: HAProxy :443 → Home Assistant/local Roborock server :555
  • Local server HTTPS port: 555
  • Local server MQTT TLS port: 8881
  • Local server internal MQTT broker: 127.0.0.1:18830
  • Region: us

The server ultimately reported the expected listeners, including:

https_server            tls:0.0.0.0:555
mqtt_backend_broker     127.0.0.1:18830
mqtt_tls_proxy          tls:0.0.0.0:8881

How this differs from #61

Issue #61 was extremely useful as confirmation that the Saros 10R could work with firmware newer than the version documented as tested.

My successful configuration is different in several important ways.

1. Firmware 02.50.56

My unit is running:

02.50.56

Issue #61 reports success on 02.52.86, so this adds another confirmed-working Saros 10R firmware version.

2. pfSense + HAProxy

My network architecture is:

                 pfSense
                    |
             +------+------+
             |             |
        HAProxy HTTPS   HAProxy TCP
            :443          MQTT
             |             |
             v             v
           :555          :8881
             \             /
              \           /
          local_roborock_server

HAProxy runs directly on pfSense.

This is significant because my installation demonstrates that a reverse proxy can be used successfully in front of local_roborock_server, but HTTPS and MQTT cannot simply be treated as the same type of proxy traffic.

For HTTPS I used the normal HAProxy HTTPS/SNI arrangement.

For MQTT I had to configure HAProxy for TCP passthrough. Trying to handle the MQTT side as HTTP/HTTPS proxy traffic does not work. Once MQTT was treated as a raw TCP stream and forwarded to the local server's MQTT listener, the robot was able to establish its MQTT connection.

My HAProxy MQTT backend ultimately forwarded to:

HA_IP:8881

in TCP mode.

That distinction was one of the important pieces in getting the Saros 10R fully connected.

3. Certificates were managed by pfSense

I already used the pfSense ACME package for certificates.

I generated/renewed the wildcard certificate there and copied the resulting certificate and private key to Home Assistant as:

/ssl/roborock-fullchain.pem
/ssl/roborock-key.pem

The local server was configured for tls_mode: provided.

I verified the certificate chain independently with openssl s_client before continuing.

I also encountered a certificate-chain problem during setup. Updating the pfSense ACME package and reissuing the certificate corrected the chain.

4. Cloud Import and local onboarding are separate things

I initially added the robot using the normal Roborock infrastructure and used the local_roborock_server Cloud Import workflow:

Send Code
    ↓
Fetch Data
    ↓
account/device information imported

That worked, but this taught me an important distinction:

A successful Cloud Import does not mean that the robot itself has been successfully redirected to and connected with the local server.

I reached a point where the account and device information existed locally while the robot still had not established the expected local MQTT connection.

Onboarding

I used the project's onboarding tooling from another computer.

The general process was:

  1. Reset the Saros 10R Wi-Fi.
  2. Connect to the robot's temporary Wi-Fi network.
  3. Run the onboarding utility.
  4. Provide the normal Wi-Fi credentials and local-server information.
  5. Send the configuration to the robot.
  6. Reconnect to the normal network.
  7. Examine local_roborock_server logs.
  8. Repeat the required onboarding/public-key exchanges until the server and robot had everything required.

Eventually I reached the important state:

Public Key: Yes
MQTT connected: Yes
Device paired and connected

MITM redirect problem and PR #77

My onboarding path also exposed a problem in the MITM/redirection tooling that mattered specifically with my HAProxy architecture.

My local Roborock server listens internally on:

:555

but that port is deliberately not the endpoint clients should use.

The externally reachable API is:

https://api-roborock.<domain>:443

HAProxy receives that connection and routes it internally to the local server.

During onboarding, the MITM redirect logic could instead end up targeting the local API's :555 endpoint. In my architecture that was wrong because 555 is an internal backend port, not the externally reachable API endpoint.

I modified the MITM redirect handling so that an explicitly supplied HTTPS :443 local API endpoint is preserved and routed through HAProxy rather than effectively falling back to :555.

There was also an HTTP Host/authority issue around explicitly carrying :443. Normalizing the standard HTTPS port was necessary to avoid HAProxy routing problems in this configuration.

Those changes became:

PR #77: MITM redirect fix

The practical difference is:

WRONG FOR MY NETWORK

MITM
  |
  +----> api-roborock.<domain>:555
                         X


CORRECT

MITM
  |
  +----> api-roborock.<domain>:443
                         |
                      HAProxy
                         |
                         v
                    HA_IP:555

So the fix was not merely cosmetic. It allowed the onboarding/MITM path to use the same public API authority that the rest of my network architecture was designed around, while keeping port 555 private behind HAProxy.

Verification that the robot was actually local

I did not consider the setup successful simply because the vacuum appeared in the Roborock app.

I verified several independent layers.

TLS

I tested the certificate and TLS paths independently.

HTTP

The robot began making requests against local endpoints such as:

/time/now
/location
/getHomeDetail

MQTT

I observed the expected Roborock MQTT connections and rr/... topics.

An additional complication was that not everything appearing in the logs was immediately human-readable. Some fields and payload data appeared encoded, including Base64-encoded data. I used ChatGPT during troubleshooting to decode and interpret portions of the logs and correlate the encoded traffic with what the robot and server were doing.

That was useful because simply seeing MQTT traffic was not enough. Interpreting the logs helped distinguish between:

MQTT socket exists
        ↓
robot is exchanging Roborock traffic
        ↓
local server understands the robot
        ↓
device is actually paired and operational

I would recommend saving the logs during onboarding and decoding or inspecting anything that looks opaque rather than assuming unreadable payloads indicate an error.

Local server state

The definitive local-server status eventually became:

Public Key: Yes
MQTT connected: Yes
Device paired and connected

Home Assistant

I then connected the Home Assistant Roborock integration to the local setup.

I encountered an account already configured/disabled integration situation during the transition and subsequently completed Home Assistant's repair/re-authentication flow using the local PIN.

The integration then loaded successfully and exposed:

vacuum.saros_10r

with firmware:

02.50.56

Commands from Home Assistant worked.

What I learned

For anyone doing this with pfSense or another nontrivial network, I strongly recommend debugging the stack as separate layers:

1. DNS
2. Certificate chain
3. HAProxy HTTPS frontend
4. HAProxy HTTPS backend
5. HAProxy MQTT TCP passthrough
6. local_roborock_server
7. Cloud Import
8. cfgwifi/onboarding
9. MITM API redirection
10. public-key recovery
11. MQTT connection
12. MQTT/log interpretation
13. Home Assistant integration

A successful result at one layer does not prove the next one works.

In particular:

  • Cloud Import succeeding does not prove the robot is local.
  • The robot appearing in the app does not prove MQTT is local.
  • HTTPS working does not prove MQTT works.
  • HAProxy working for HTTPS does not mean the same HAProxy configuration will work for MQTT.
  • MQTT requires the appropriate TCP passthrough configuration.
  • Seeing MQTT packets does not necessarily tell you what they contain. Some of the Roborock traffic/log output may require decoding or interpretation.
  • The MITM/onboarding endpoint needs to agree with the network architecture. In my case that meant using the externally valid :443 endpoint and letting HAProxy reach internal :555.

Result

My final arrangement is approximately:

                       Cloudflare DNS
                             |
                             v
                          pfSense
                             |
                +------------+------------+
                |                         |
          HAProxy HTTPS              HAProxy TCP
              :443                MQTT passthrough
                |                         |
                v                         v
              :555                      :8881
                \                         /
                 \                       /
                  local_roborock_server
                           |
                    HTTP + MQTT
                           |
                      Saros 10R
                     FW 02.50.56
                           |
                           v
                    Home Assistant

The Saros 10R is paired and connected, local MQTT communication is present, the Home Assistant integration works, and normal control is available locally.

Comparison with #61

Issue #61 My setup
Robot Saros 10R Saros 10R
Firmware 02.52.86 02.50.56
Deployment Docker Compose/build from source Home Assistant add-on
Router/firewall Homelab environment pfSense
Reverse proxy NPM present but bypassed for Roborock pfSense HAProxy actively used
Certificates Let's Encrypt/NPM pfSense ACME
DNS AdGuard Home wildcard Cloudflare + existing DNS infrastructure
HTTPS Direct local-server arrangement HAProxy :443 → internal :555
MQTT Direct arrangement HAProxy TCP passthrough → :8881
Onboarding cfgwifi cfgwifi + MITM/redirection troubleshooting
MITM modification Not required Required, resulting in PR #77
Troubleshooting Server/HA verification TLS + HTTP + MQTT + Base64/log interpretation + HA verification

The important additional findings from my installation are therefore:

Saros 10R firmware 02.50.56 works with local_roborock_server.

and:

A pfSense/HAProxy architecture also works. HTTPS can be reverse-proxied through HAProxy while MQTT is handled separately using TCP passthrough.

My setup also uncovered an MITM redirect issue affecting this architecture, which resulted in PR #77.

Companion guides and related reports

For anyone trying to reproduce this configuration or understand the individual pieces in more detail, I am maintaining a separate guide repository here:

Other directly relevant references:

I think these reports are particularly useful together because they demonstrate that there is not only one viable network topology for the Saros 10R. #61 established one successful path, while this installation demonstrates a second path using the Home Assistant add-on, pfSense, HAProxy, externally managed certificates, TCP MQTT passthrough, and a reverse-proxied onboarding endpoint.

Thanks to everyone working on local_roborock_server, and thanks to @skittyxan for #61. That report gave me an extremely useful known-good Saros 10R reference while I worked through a substantially different network and onboarding path.

Steps to reproduce

Issue: The following URL is 404 https://github.com/Python-roborock/local_roborock_server/discussions/categories/compatibility

Vacuum model

Roborock Saros 10r

Server / image version

v1.0.2

Relevant logs

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions