Skip to content

Roborock Q10 S5 support #392

Closed
Closed

Description

@Shadester

I got a new Q10 S5 and it seems like I can get the device in products, but not in devices?

From https://api-us.roborock.com/user/homes/3807116

{
"api": "获取家庭详细信息",
"result": {
"id": 3807116,
"name": "My Home",
"lon": null,
"lat": null,
"geoName": null,
"products": [
{
"id": "1O9BlCxWe4loekRE624qPv",
"name": "Roborock Q10 Series",
"model": "roborock.vacuum.ss07",
"iconUrl": null,
"attribute": null,
"capability": 0,
"category": "robot.vacuum.cleaner",
"schema": [
{
"id": 101,
"name": "RPC Request",
"code": "rpc_request",
"mode": "rw",
"type": "RAW",
"property": "null"
},
{
"id": 102,
"name": "RPC Response",
"code": "rpc_response",
"mode": "rw",
"type": "RAW",
"property": "null"
},
{
"id": 120,
"name": "错误代码",
"code": "error_code",
"mode": "ro",
"type": "ENUM",
"property": "{"range": []}"
},
{
"id": 121,
"name": "设备状态",
"code": "state",
"mode": "ro",
"type": "VALUE",
"property": "null"
},
{
"id": 122,
"name": "设备电量",
"code": "battery",
"mode": "ro",
"type": "ENUM",
"property": "{"range": []}"
},
{
"id": 123,
"name": "吸力档位",
"code": "fan_power",
"mode": "rw",
"type": "ENUM",
"property": "{"range": []}"
},
{
"id": 124,
"name": "拖地档位",
"code": "water_box_mode",
"mode": "rw",
"type": "RAW",
"property": "null"
},
{
"id": 125,
"name": "主刷寿命",
"code": "main_brush_life",
"mode": "ro",
"type": "ENUM",
"property": "{"range": []}"
},
{
"id": 126,
"name": "边刷寿命",
"code": "side_brush_life",
"mode": "ro",
"type": "ENUM",
"property": "{"range": []}"
},
{
"id": 127,
"name": "滤网寿命",
"code": "filter_life",
"mode": "ro",
"type": "ENUM",
"property": "{"range": []}"
},
{
"id": 135,
"name": "离线原因",
"code": "offline_status",
"mode": "ro",
"type": "ENUM",
"property": "{"range": []}"
},
{
"id": 136,
"name": "清洁次数",
"code": "clean_times",
"mode": "rw",
"type": "ENUM",
"property": "{"range": []}"
},
{
"id": 137,
"name": "扫拖模式",
"code": "cleaning_preference",
"mode": "rw",
"type": "ENUM",
"property": "{"range": []}"
},
{
"id": 138,
"name": "清洁任务类型",
"code": "clean_task_type",
"mode": "ro",
"type": "ENUM",
"property": "{"range": []}"
},
{
"id": 139,
"name": "返回基站类型",
"code": "back_type",
"mode": "ro",
"type": "ENUM",
"property": "{"range": []}"
},
{
"id": 140,
"name": "基站任务类型",
"code": "dock_task_type",
"mode": "ro",
"type": "ENUM",
"property": "{"range": []}"
},
{
"id": 141,
"name": "清洁进度",
"code": "cleaning_progress",
"mode": "ro",
"type": "ENUM",
"property": "{"range": []}"
},
{
"id": 142,
"name": "窜货信息",
"code": "fc_state",
"mode": "ro",
"type": "RAW",
"property": "null"
},
{
"id": 201,
"name": "启动清洁任务",
"code": "start_clean_task",
"mode": "wo",
"type": "ENUM",
"property": "{"range": []}"
},
{
"id": 202,
"name": "返回基站任务",
"code": "start_back_dock_task",
"mode": "wo",
"type": "ENUM",
"property": "{"range": []}"
},
{
"id": 203,
"name": "启动基站任务",
"code": "start_dock_task",
"mode": "wo",
"type": "ENUM",
"property": "{"range": []}"
},
{
"id": 204,
"name": "暂停任务",
"code": "pause",
"mode": "wo",
"type": "RAW",
"property": "null"
},
{
"id": 205,
"name": "继续任务",
"code": "resume",
"mode": "wo",
"type": "RAW",
"property": "null"
},
{
"id": 206,
"name": "结束任务",
"code": "stop",
"mode": "wo",
"type": "RAW",
"property": "null"
},
{
"id": 207,
"name": "用户改善计划",
"code": "ceip",
"mode": "rw",
"type": "ENUM",
"property": "{"range": ["0,1"]}"
}
]
}
],
"devices": [],
"receivedDevices": [],
"rooms": []
},
"status": "ok",
"success": true
}

Activity

  1. Shadester commented on Jun 22, 2025

    @Shadester
    Author

    I can see it if I use get_home_data_v3, but I don't seem to be able to get anything over mqtt. Tried get_status and get_consumable.

  2. anotherdave commented on Jul 4, 2025

    @anotherdave
    Contributor

    The Q10 and the Q7B use a new B01 protocol version for MQTT, complete with changed packet encryption. The MQTT authentication still works with python-roborock, but the initialization vector for the decryption is wrong so the first 16 bytes of the decrypted payload is bad, and python-roborock isn't set up for B01 packets anyway.

    As far as I can see there is no local comms between the app and the robot at all, everything goes over internet MQTT.

    I am having a look at encryption at the moment, but may be some time!

  3. Lash-L commented on Jul 5, 2025

    @Lash-L
    Collaborator

    Hi

    I talked with another use who made significant progress

    The protocol packets have the version B01 and each packet uses a custom IV which is derived from a number in the header. I think this is very similar to how A01 works but the IV is then created as follows:
    
    def derive_iv_from_int(iv_int32):
        prefix = f"{iv_int32:08x}"
        suffix = "E2d1o7gxc8UMpSAjRhCki9hww5"[::-1]  
        iv_input_str = prefix + suffix
        md5_hex = hashlib.md5(iv_input_str.encode()).hexdigest()
        return md5_hex[9:25].encode()
    
    So the IV seed string is different to A01 and the offset is 1 character different I think. I reversed the string to avoid it being too obvious in web searches if it is published.
    
    I think it uses the same padding as previously although possibly is pkcs7
    
    # Encryption function
    def aes_encrypt_custom_iv_from_int(plaintext_bytes, key_str, iv_int32):
        try:
            key = key_str.encode()
            iv = derive_iv_from_int(iv_int32)
            padded_plaintext = pad(plaintext_bytes, AES.block_size, style='pkcs7')
            cipher = AES.new(key, AES.MODE_CBC, iv)
            ciphertext = cipher.encrypt(padded_plaintext)
            return binascii.hexlify(ciphertext).decode()
        except Exception as e:
            return f"Encryption error: {e}"
    
    # Decryption function
    def aes_decrypt_custom_iv_from_int(ciphertext_hex, key_str, iv_int32):
        try:
            key = key_str.encode()
            iv = derive_iv_from_int(iv_int32)
            ciphertext = binascii.unhexlify(ciphertext_hex.replace(" ", ""))
            cipher = AES.new(key, AES.MODE_CBC, iv)
            decrypted = cipher.decrypt(ciphertext)
            plaintext = unpad(decrypted, AES.block_size, style='pkcs7')
            return plaintext
        except Exception as e:
            return f"Decryption error: {e}"
    
    I think this is basically the same as how A01 is constructed but this is the python I put together to test encryption/decryption with some offline data.
    

    They have had limited time - but if anyone wants to continue along, I'm happy to helphow i can. I have limited time myself.

  4. anotherdave commented on Jul 5, 2025

    @anotherdave
    Contributor

    Thanks @Lash-L , I had missed the offset change! I am not great at Python but this protocol.py fix seems to work with the Q7B. I can make a PR if you like or try to get more stuff working.

  5. Lash-L commented on Jul 5, 2025

    @Lash-L
    Collaborator

    Thanks @Lash-L , I had missed the offset change! I am not great at Python but this protocol.py fix seems to work with the Q7B. I can make a PR if you like or try to get more stuff working.

    So I need to see if the messages look the same - my thought is there has to be a difference between what they are sending other than the encryption otherwise a new protocol doesn't make much sense I.e in a01 they send all of the commands at once to update. I have not seen that difference or any of the b01 messages for that fact so it's hard for me to know

  6. anotherdave commented on Jul 5, 2025

    @anotherdave
    Contributor

    Sure, I have fully MITMed the app so I can dump out some decoded packets. Is there anything in particular I should get the robot doing?

  7. Lash-L commented on Jul 5, 2025

    @Lash-L
    Collaborator

    Really anything for about a minute or two.

    The app will automatically send the requests asking for new data.

    I'd make one setting change as well.

    You can email @ conway220@gmail.com

  8. Subia75 commented on Jul 8, 2025

    @Subia75

    Hi everyone,
    I buy the Roborock Q10 S5 and I thought it was seen in HA as my old good S6 pure.
    Unfortunately I'm not a programmer but if there is some testing to do to be able to integrate it,
    Just ask me explaining what is needed, I would be happy to help.

    @Lash-L I read a few posts above that a user has made progress with this.
    As I said above, if anyone has the knowledge to do this, I could run some tests to gather more data.

  9. lboue commented on Jul 17, 2025

    @lboue
    Contributor

    I can see it if I use get_home_data_v3, but I don't seem to be able to get anything over mqtt. Tried get_status and get_consumable.

    Same for me. I looked at the exchanges between the application and the API. I see that it uses this version of the API: https://api-eu.roborock.com/v3/user/homes/1234567

  10. lboue commented on Jul 17, 2025

    @lboue
    Contributor

    I was able to discover my Q10 device after changing to v3: #418

    (venv) user@vm:~/roborock/python-roborock/python-roborock$ python -m roborock.cli discover
    Discovered devices Roborock Q10 S5+
    (venv) user@vm:~/roborock/python-roborock/python-roborock$ python -m roborock.cli list-devices
    Known devices Roborock Q10 S5+: 1simZp7ZguuihAICo*****
    
  11. lboue commented on Oct 12, 2025

    @lboue
    Contributor

    Any progress regarding this?

  12. Lash-L commented on Oct 13, 2025

    @Lash-L
    Collaborator

    Any progress regarding this?

    There seem to be multiple different messaging formats on b01 which have greatly complicated the process. I have been working on a pipeline to help me reverse engineer the code and figure things out, but it is a rather complicated byte code format.

    But I am always limited on time so I will bounce from this problem to other ones when I have free time to work on this project.

  13. lboue commented on Dec 12, 2025

    @lboue
    Contributor

    Is the implementation of the protocol different between the Q7 and Q10 models?

  14. Lash-L commented on Dec 12, 2025

    @Lash-L
    Collaborator

    The protocol is the same (i.e. encryption and decryption), but the messaging structure and the messages are different. I have a good bit of data reverse engineered for both.

    https://github.com/Python-roborock/python-roborock/tree/main/roborock/data

    You can see the b01_q7 and b01_q10 separated here

  15. added a commit that references this issue on Dec 27, 2025
  16. anotherdave commented on Dec 27, 2025

    @anotherdave
    Contributor

    Hi @Lash-L , thanks for the work on the Q7! I did some testing on the q7_setters branch and it mostly works but the mappings needed tweaking as in the above PR.

    For what it's worth I improved the example test harness a bit to save the login token etc so you only need to request a code once, and enabled debug logging.

    With debug logging enabled you can run the Android/iOS app in parallel and see the commands and responses sent from the app, so no more need to set up MITM. Test is here: https://gist.github.com/anotherdave/e994f34c90c8b3595036356f98f9a68a

  17. BOFH90 commented on Jan 9, 2026

    @BOFH90

    I just got the Q10 X5+ ("roborock.vacuum.ss09"). Is this any different to the Q10 S5 Support - should i open a new ticket?

  18. Lash-L commented on Jan 10, 2026

    @Lash-L
    Collaborator

    I just got the Q10 X5+ ("roborock.vacuum.ss09"). Is this any different to the Q10 S5 Support - should i open a new ticket?

    They are mainly aligned and support will be shared. I think the only difference is the dock iirc

  19. cdnninja commented on Jan 30, 2026

    @cdnninja

    I am happy to support with testing or some basic dev on this if you need a hand. I am available via discord and support a few other integrations.

  20. lboue commented on Feb 1, 2026

    @lboue
    Contributor

    Thanks to the latest commits, it works. You can test the scripts in this PR:
    Add Q10 VacuumTrait Test Scripts #758

  21. lboue commented on Apr 8, 2026

    @lboue
    Contributor

    Can we close this now?

  22. allenporter commented on Apr 9, 2026

    @allenporter
    Contributor

    Yeah, seems good to me. I assume may have more things to expose or get details right on, but we generally have all the basics supported.

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