Skip to content

Saros 20 (a288 / L01): map frame delivered but not decodable — GET_MAP_V1 never produces an image #947

Description

@flesrouy

Describe the bug

On the Roborock Saros 20 (roborock.vacuum.a288, an L01-protocol device), all V1 traits work — status, get_maps, and rooms all refresh correctly — but the map image can never be decoded. The robot does answer GET_MAP_V1, but the returned map frame is in the new L01/GCM-framed format that the current V1 map decoder cannot handle, so no image.* entity is ever produced (this is what surfaces in Home Assistant as a permanently missing Roborock map for Saros 20).

This looks related to, but distinct from, #532 (that report is a Saros Z70 hitting decrypt_cbc → "Padding is incorrect"; here the device negotiates L01 and the payload is not classic CBC at all).

Roborock Model

Roborock Saros 20 — roborock.vacuum.a288

Python-roborock Version

Reproduced on 2.19.0 and current 6.2.1 (also 7.2.3). Behavior is the same across all three.

What works

Using create_device_manager(...) (6.x), the device connects locally (is_local_connected == True) over its local server (TCP port 58867) speaking protocol L01:

  • status → OK
  • maps / get_maps → OK (returns the correct single map "First Floor" with the full, correctly-named room list)
  • rooms → OK

Only map_content.refresh() (GET_MAP_V1) fails to yield an image.

Observed map-fetch behavior

  • Local (L01) channel: GET_MAP_V1 returns only an empty proto=3 ack — no protocol=301 map frame is ever sent locally.
  • Cloud MQTT channel: GET_MAP_V1 returns exactly one protocol=301 frame per request (verified causal: 0 frames arrive when no request is sent; 1 arrives per request). The frame is ~7080 bytes and is high-entropy end-to-end (~7.97/8.0 across the entire payload) — there is no plaintext header region. The session SecurityData.nonce does not decrypt it at any offset (0–63), under AES-CBC or AES-ECB, or with key variants (nonce, md5(nonce), reversed). No gzip/zlib stream is present anywhere in the payload.

So the map response is being delivered, but in an encrypted L01 framing the V1 map decoder doesn't understand.

Secondary bug: uncaught UnicodeDecodeError in the map decoder

While reproducing, the map-response decoder crashes on these frames:

roborock/protocols/v1_protocol.py::create_map_response_decoder_decode_map_response calls endpoint.decode() on the leading bytes of the payload. For these L01 map frames the "endpoint" region is binary, raising UnicodeDecodeError. That exception is not caught in roborock/devices/rpc/v1_channel.py::find_response (which only catches RoborockException), so the response callback dies, the future never resolves, and the caller just times out (~10s) with no useful error. Even before full L01 map support lands, catching/handling this would turn a silent timeout into a clear failure.

Expected Behavior

GET_MAP_V1 on a288 / L01 devices should decode the returned map frame (or at least surface a specific, non-timeout error) so the image.* map entity can be produced.

Offer

I have captured raw 301 map frames plus the exact per-session SecurityData (nonce + endpoint) for this device and am happy to share samples / test candidate decoders to help wire up L01 map decoding.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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