Skip to content

Conversation

Crocmagnon
Copy link
Contributor

@Crocmagnon Crocmagnon commented Aug 16, 2025

Supersedes #997

Relates to #1052

I have no idea how to test this. Could someone point me in the correct direction? I didn't find contributing documentation, though I may have missed something :)

I have a working HomeAssistant dev environment, I don't know how to install my forked library to test the change.

@Crocmagnon Crocmagnon changed the title feat: support x9 pro omni following x8 pro omni feat: support x9 pro omni following x8 omni Aug 16, 2025
@Crocmagnon Crocmagnon marked this pull request as draft August 16, 2025 13:37
@Crocmagnon
Copy link
Contributor Author

Crocmagnon commented Aug 16, 2025

Okay we're getting there.

2025-08-16 13:36:43.244 ERROR (MainThread) [deebot_client.message] Handler for message getMapSubSet: {'code': 20003, 'msg': 'rcp not support'} returned no response. This is a bug should not happen. Please report it.
2025-08-16 13:36:43.244 WARNING (MainThread) [deebot_client.message] Could not parse getMapSubSet: {'body': {'code': 20003, 'msg': 'rcp not support'}, 'header': {'fwVer': '1.42.2', 'hwVer': '0.1.1', 'pri': 1, 'ts': '1755351403010', 'tzm': 480, 'ver': '0.0.1', 'wkVer': '0.1.54'}}
2025-08-16 13:36:43.244 WARNING (MainThread) [deebot_client.message] Could not parse getMapSubSet: {'body': {'code': 20003, 'msg': 'rcp not support'}, 'header': {'fwVer': '1.42.2', 'hwVer': '0.1.1', 'pri': 1, 'ts': '1755351403010', 'tzm': 480, 'ver': '0.0.1', 'wkVer': '0.1.54'}}
2025-08-16 13:36:43.244 WARNING (MainThread) [deebot_client.command] Could not parse getMapSubSet: {'ret': 'ok', 'resp': {'body': {'code': 20003, 'msg': 'rcp not support'}, 'header': {'fwVer': '1.42.2', 'hwVer': '0.1.1', 'pri': 1, 'ts': '1755351403010', 'tzm': 480, 'ver': '0.0.1', 'wkVer': '0.1.54'}}, 'id': 'lwyB', 'payloadType': 'j'}

Looks like it fails to retrieve the map data.

Otherwise, it looks like sensors report OK.
Is there a way to trigger cleaning? I don't see it in controls.

image image

@Crocmagnon
Copy link
Contributor Author

Some other errors

2025-08-16 14:20:13.417 WARNING (MainThread) [deebot_client.message] Could not parse getLifeSpan: [{'left': 17943, 'total': 18000, 'type': 'brush'}, {'left': 100, 'total': 100, 'type': 'cleaningSolution'}, {'left': 2944, 'total': 3000, 'type': 'dustBag'}, {'left': 30000, 'total': 30000, 'type': 'handFilter'}, {'left': 7144, 'total': 7200, 'type': 'heap'}, {'left': 8999, 'total': 9000, 'type': 'roundMop'}, {'left': 3599, 'total': 3600, 'type': 'sewageBox'}, {'left': 8940, 'total': 9000, 'type': 'sideBrush'}, {'left': 1800, 'total': 1800, 'type': 'strainer'}, {'left': 1740, 'total': 1800, 'type': 'unitCare'}, {'left': 3599, 'total': 3600, 'type': 'waterSink'}]
Traceback (most recent call last):
  File "/workspaces/deebot-client/deebot_client/message.py", line 254, in __handle_body_data
    response = cls._handle_body_data(event_bus, data)
  File "/workspaces/deebot-client/deebot_client/message.py", line 325, in _handle_body_data
    return cls._handle_body_data_list(event_bus, data)
           ~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
  File "/workspaces/deebot-client/deebot_client/commands/json/life_span.py", line 37, in _handle_body_data_list
    component_type = LifeSpan(component["type"])
  File "/home/vscode/.local/share/uv/python/cpython-3.13.6-linux-x86_64-gnu/lib/python3.13/enum.py", line 726, in __call__
    return cls.__new__(cls, value)
           ~~~~~~~~~~~^^^^^^^^^^^^
  File "/home/vscode/.local/share/uv/python/cpython-3.13.6-linux-x86_64-gnu/lib/python3.13/enum.py", line 1203, in __new__
    raise ve_exc
ValueError: 'waterSink' is not a valid LifeSpan
2025-08-16 14:20:13.417 WARNING (MainThread) [deebot_client.message] Could not parse getLifeSpan: {'data': [{'left': 17943, 'total': 18000, 'type': 'brush'}, {'left': 100, 'total': 100, 'type': 'cleaningSolution'}, {'left': 2944, 'total': 3000, 'type': 'dustBag'}, {'left': 30000, 'total': 30000, 'type': 'handFilter'}, {'left': 7144, 'total': 7200, 'type': 'heap'}, {'left': 8999, 'total': 9000, 'type': 'roundMop'}, {'left': 3599, 'total': 3600, 'type': 'sewageBox'}, {'left': 8940, 'total': 9000, 'type': 'sideBrush'}, {'left': 1800, 'total': 1800, 'type': 'strainer'}, {'left': 1740, 'total': 1800, 'type': 'unitCare'}, {'left': 3599, 'total': 3600, 'type': 'waterSink'}]}
2025-08-16 14:20:13.417 WARNING (MainThread) [deebot_client.message] Could not parse getLifeSpan: {'body': {'data': [{'left': 17943, 'total': 18000, 'type': 'brush'}, {'left': 100, 'total': 100, 'type': 'cleaningSolution'}, {'left': 2944, 'total': 3000, 'type': 'dustBag'}, {'left': 30000, 'total': 30000, 'type': 'handFilter'}, {'left': 7144, 'total': 7200, 'type': 'heap'}, {'left': 8999, 'total': 9000, 'type': 'roundMop'}, {'left': 3599, 'total': 3600, 'type': 'sewageBox'}, {'left': 8940, 'total': 9000, 'type': 'sideBrush'}, {'left': 1800, 'total': 1800, 'type': 'strainer'}, {'left': 1740, 'total': 1800, 'type': 'unitCare'}, {'left': 3599, 'total': 3600, 'type': 'waterSink'}]}, 'header': {'fwVer': '1.42.2', 'hwVer': '0.1.1', 'pri': 1, 'ts': '1755354012981', 'tzm': 480, 'ver': '0.0.1', 'wkVer': '0.1.54'}}
2025-08-16 14:20:13.417 WARNING (MainThread) [deebot_client.message] Could not parse getLifeSpan: b'{"body":{"data":[{"left":17943,"total":18000,"type":"brush"},{"left":100,"total":100,"type":"cleaningSolution"},{"left":2944,"total":3000,"type":"dustBag"},{"left":30000,"total":30000,"type":"handFilter"},{"left":7144,"total":7200,"type":"heap"},{"left":8999,"total":9000,"type":"roundMop"},{"left":3599,"total":3600,"type":"sewageBox"},{"left":8940,"total":9000,"type":"sideBrush"},{"left":1800,"total":1800,"type":"strainer"},{"left":1740,"total":1800,"type":"unitCare"},{"left":3599,"total":3600,"type":"waterSink"}]},"header":{"fwVer":"1.42.2","hwVer":"0.1.1","pri":1,"ts":"1755354012981","tzm":480,"ver":"0.0.1","wkVer":"0.1.54"}}'
2025-08-16 14:20:23.086 WARNING (MainThread) [deebot_client.message] Could not parse getWaterInfo: {'customAmount': 30, 'enable': 1, 'mopCount': 2, 'sideMop': 0, 'sweepType': 1, 'type': 1}
Traceback (most recent call last):
  File "/workspaces/deebot-client/deebot_client/message.py", line 254, in __handle_body_data
    response = cls._handle_body_data(event_bus, data)
  File "/workspaces/deebot-client/deebot_client/message.py", line 298, in _handle_body_data
    return cls._handle_body_data_dict(event_bus, data)
           ~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
  File "/workspaces/deebot-client/deebot_client/commands/json/water_info.py", line 38, in _handle_body_data_dict
    event_bus.notify(WaterAmountEvent(WaterAmount(int(data["amount"]))))
                                                      ~~~~^^^^^^^^^^
KeyError: 'amount'
2025-08-16 14:20:23.087 WARNING (MainThread) [deebot_client.message] Could not parse getWaterInfo: {'data': {'customAmount': 30, 'enable': 1, 'mopCount': 2, 'sideMop': 0, 'sweepType': 1, 'type': 1}}
2025-08-16 14:20:23.087 WARNING (MainThread) [deebot_client.message] Could not parse getWaterInfo: {'body': {'data': {'customAmount': 30, 'enable': 1, 'mopCount': 2, 'sideMop': 0, 'sweepType': 1, 'type': 1}}, 'header': {'fwVer': '1.42.2', 'hwVer': '0.1.1', 'pri': 1, 'ts': '1755354022782', 'tzm': 480, 'ver': '0.0.1', 'wkVer': '0.1.54'}}
2025-08-16 14:20:23.087 WARNING (MainThread) [deebot_client.message] Could not parse getWaterInfo: b'{"body":{"data":{"customAmount":30,"enable":1,"mopCount":2,"sideMop":0,"sweepType":1,"type":1}},"header":{"fwVer":"1.42.2","hwVer":"0.1.1","pri":1,"ts":"1755354022782","tzm":480,"ver":"0.0.1","wkVer":"0.1.54"}}'
2025-08-16 14:20:43.824 WARNING (MainThread) [deebot_client.message] Could not parse getWaterInfo: {'customAmount': 30, 'enable': 1, 'mopCount': 2, 'sideMop': 0, 'sweepType': 1, 'type': 1}
Traceback (most recent call last):
  File "/workspaces/deebot-client/deebot_client/message.py", line 254, in __handle_body_data
    response = cls._handle_body_data(event_bus, data)
  File "/workspaces/deebot-client/deebot_client/message.py", line 298, in _handle_body_data
    return cls._handle_body_data_dict(event_bus, data)
           ~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
  File "/workspaces/deebot-client/deebot_client/commands/json/water_info.py", line 38, in _handle_body_data_dict
    event_bus.notify(WaterAmountEvent(WaterAmount(int(data["amount"]))))
                                                      ~~~~^^^^^^^^^^
KeyError: 'amount'
2025-08-16 14:20:43.825 WARNING (MainThread) [deebot_client.message] Could not parse getWaterInfo: {'data': {'customAmount': 30, 'enable': 1, 'mopCount': 2, 'sideMop': 0, 'sweepType': 1, 'type': 1}}
2025-08-16 14:20:43.825 WARNING (MainThread) [deebot_client.message] Could not parse getWaterInfo: {'body': {'data': {'customAmount': 30, 'enable': 1, 'mopCount': 2, 'sideMop': 0, 'sweepType': 1, 'type': 1}}, 'header': {'fwVer': '1.42.2', 'hwVer': '0.1.1', 'pri': 1, 'ts': '1755354043516', 'tzm': 480, 'ver': '0.0.1', 'wkVer': '0.1.54'}}
2025-08-16 14:20:43.825 WARNING (MainThread) [deebot_client.message] Could not parse getWaterInfo: b'{"body":{"data":{"customAmount":30,"enable":1,"mopCount":2,"sideMop":0,"sweepType":1,"type":1}},"header":{"fwVer":"1.42.2","hwVer":"0.1.1","pri":1,"ts":"1755354043516","tzm":480,"ver":"0.0.1","wkVer":"0.1.54"}}'

I'm dumping everything here in the hope someone can help :)

@Crocmagnon
Copy link
Contributor Author

Crocmagnon commented Aug 16, 2025

Did some cleaning to remove stuff that generated errors/warnings in logs but I feel like we miss some controls in HA given what is described in the file (see screenshots above).
I'd be glad to get some help as I have very little understanding of the codebase for now.

Still one error though:

Command "setTrueDetect" was not successfully. body={'code': 20011, 'msg': 'format error'}

@edenhaus
Copy link
Member

pre-commit.ci autofix

@edenhaus
Copy link
Member

I'm happy to help but please be patient as I'm not online 24/7 :)
the customamount will be fixed with #1100

About the Turedetect error, please enable debug logs and change the settings in the app and afterwards please analyse the changes in the command. Probably the api changed again

@Crocmagnon
Copy link
Contributor Author

Crocmagnon commented Aug 16, 2025

I apologize if I came across as pushy, that wasn’t the intention at all!
I’m thankful for the time you spend on this project 🙏🏻

Controls

I feel like we miss some controls in HA given what is described in the file (see screenshots above).

I didn't see the elephant in the room: the vacuum entity was there all along 🤦🏻‍♂️

True detect

About the Truedetect error, please enable debug logs and change the settings in the app and afterwards please analyse the changes in the command

2025-08-17 06:08:42.578 DEBUG (MainThread) [deebot_client.mqtt_client] Got message: topic=iot/atr/onTrueDetect/3536f043-d16b-4cd1-826f-cf3cb81bc135/ilt3k8/SHljynrM/j, payload=b'{"body":{"data":{"enable":1,"level":0}},"header":{"fwVer":"1.42.2","hwVer":"0.1.1","pri":1,"ts":"1755410921699","tzm":480,"ver":"0.0.1","wkVer":"0.1.54"}}'
2025-08-17 06:08:42.578 DEBUG (MainThread) [deebot_client.device] Try to handle messagz onTrueDetect: b'{"body":{"data":{"enable":1,"level":0}},"header":{"fwVer":"1.42.2","hwVer":"0.1.1","pri":1,"ts":"1755410921699","tzm":480,"ver":"0.0.1","wkVer":"0.1.54"}}'
2025-08-17 06:08:42.578 DEBUG (MainThread) [deebot_client.messages] Falling back to legacy way for onTrueDetect

So it looks like there's a second attribute expected: level. The value can be 0 ("High sensitivity" in the app) or 1 ("Standard").

I suggest mapping it to an enum on our side:

  • enable=0, level=any -> Off
  • enable=1, level=1 -> Standard
  • enable=1, level=0 -> High sensitivity

And when sending:

  • Off -> enable=0, level=0
  • Standard -> enable=1, level=1
  • High sensitivity -> enable=1, level=0

This has the disadvantage of resetting the level value when switching to off, which may lead to an inconsistent experience when using both Ecovacs app and HA. On the other hand, it simplifies controls in HA.

I tried implementing that but it touches more than the single robot I'm trying to implement and I got lost in the woods. I prefer leaving that to you, if that's OK. In the meantime, I'll remove the setting from this robot.

Map

2025-08-17 07:18:38.086 DEBUG (MainThread) [deebot_client.authentication] Success calling api url=https://portal-eu.ecouser.net/api/iot/devmanager.do, params={'mid': 'ilt3k8', 'did': '3536f043-d16b-4cd1-826f-cf3cb81bc135', 'td': 'q', 'u': 'jhokgrg68109464b', 'cv': '1.67.3', 't': 'a', 'av': '1.3.1'}, json={'cmdName': 'getMapSubSet', 'payload': {'header': {'pri': '1', 'ts': 1755415117.9739, 'tzm': 480, 'ver': '0.0.50'}, 'body': {'data': {'mid': '615378137', 'msid': '2013947799', 'type': 'ar', 'mssid': '6'}}}, 'payloadType': 'j', 'td': 'q', 'toId': '3536f043-d16b-4cd1-826f-cf3cb81bc135', 'toRes': 'SHljynrM', 'toType': 'ilt3k8'}, response={'ret': 'ok', 'resp': {'body': {'code': 20003, 'msg': 'rcp not support'}, 'header': {'fwVer': '1.42.2', 'hwVer': '0.1.1', 'pri': 1, 'ts': '1755415117700', 'tzm': 480, 'ver': '0.0.1', 'wkVer': '0.1.54'}}, 'id': 'ZQiL', 'payloadType': 'j'}
2025-08-17 07:18:38.086 DEBUG (MainThread) [deebot_client.event_bus] Event is the same! Skipping (FirmwareEvent(version='1.42.2'))
2025-08-17 07:18:38.086 ERROR (MainThread) [deebot_client.message] Handler for message getMapSubSet: {'code': 20003, 'msg': 'rcp not support'} returned no response. This is a bug should not happen. Please report it.
2025-08-17 07:18:38.086 WARNING (MainThread) [deebot_client.message] Could not parse getMapSubSet: {'body': {'code': 20003, 'msg': 'rcp not support'}, 'header': {'fwVer': '1.42.2', 'hwVer': '0.1.1', 'pri': 1, 'ts': '1755415117700', 'tzm': 480, 'ver': '0.0.1', 'wkVer': '0.1.54'}}
2025-08-17 07:18:38.086 WARNING (MainThread) [deebot_client.message] Could not parse getMapSubSet: {'body': {'code': 20003, 'msg': 'rcp not support'}, 'header': {'fwVer': '1.42.2', 'hwVer': '0.1.1', 'pri': 1, 'ts': '1755415117700', 'tzm': 480, 'ver': '0.0.1', 'wkVer': '0.1.54'}}
2025-08-17 07:18:38.086 WARNING (MainThread) [deebot_client.command] Could not parse getMapSubSet: {'ret': 'ok', 'resp': {'body': {'code': 20003, 'msg': 'rcp not support'}, 'header': {'fwVer': '1.42.2', 'hwVer': '0.1.1', 'pri': 1, 'ts': '1755415117700', 'tzm': 480, 'ver': '0.0.1', 'wkVer': '0.1.54'}}, 'id': 'ZQiL', 'payloadType': 'j'}

There are still error logs about the map, I don't know what to do about them and the map doesn't load. Do you have ideas?

Water

Should I leave water level capabilities in place even if they don't work, pending #1100 ?

Overall

I disabled map, water, and true detect to get a good first version of this robot. At least it will be detected in Home Assistant and will allow triggering cleaning which is, in my opinion, what 80% of users need.

We could defer the water and true detect features to a second iteration. The water level is already being fixed in #1100 and I feel like we have the information we need for True Detect; we "just"™ need to implement it.

I feel like the map is a bigger thing though, maybe yet another new undocumented API.

I added some TODOs in the comments to reflect these points.

Let me know how you want to proceed 🙂

@Crocmagnon Crocmagnon force-pushed the feat/x9-pro-omni branch 5 times, most recently from 61ac2bc to ac94a66 Compare August 17, 2025 07:58
@Crocmagnon Crocmagnon marked this pull request as ready for review August 17, 2025 08:01
@Crocmagnon Crocmagnon changed the title feat: support x9 pro omni following x8 omni feat: support x9 pro omni Aug 18, 2025
@edenhaus edenhaus changed the title feat: support x9 pro omni Add support for X9 Pro Omni (ilt3k8) Aug 19, 2025
Copy link

codecov bot commented Aug 20, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 93.77%. Comparing base (d4ed2cd) to head (cb4b17c).
⚠️ Report is 2 commits behind head on dev.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##              dev    #1102      +/-   ##
==========================================
+ Coverage   93.72%   93.77%   +0.04%     
==========================================
  Files         131      132       +1     
  Lines        5020     5058      +38     
  Branches      327      327              
==========================================
+ Hits         4705     4743      +38     
  Misses        252      252              
  Partials       63       63              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link

codspeed-hq bot commented Aug 20, 2025

CodSpeed Performance Report

Merging #1102 will not alter performance

Comparing Crocmagnon:feat/x9-pro-omni (cb4b17c) with dev (d4ed2cd)

Summary

✅ 6 untouched benchmarks

@edenhaus edenhaus added the pr: new-feature PR, which adds a new feature label Aug 20, 2025
@@ -148,6 +148,7 @@ class LifeSpan(StrEnumWithXml):
HAND_FILTER = "handFilter", "HandFilter"
DUST_CASE_HEAP = "dustCaseHeap", "DustCaseHeap"
STATION_FILTER = "spHeap", "SpHeap"
WATER_SINK = "waterSink", "WaterSink"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After I bumped the library version in HA, we need to support it in HA by adding translations there.
Can you please do it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, would you be able to point me to the instructions? I’ve never done that yet.

Also I’ll have to find out how to translate that 😛

@edenhaus edenhaus merged commit 46a6e81 into DeebotUniverse:dev Aug 20, 2025
27 checks passed
@Crocmagnon Crocmagnon deleted the feat/x9-pro-omni branch August 20, 2025 12:11
@Sanji78
Copy link

Sanji78 commented Aug 27, 2025

Pls check this:
#832

I managed to add the water level from 1 to 50.

@Sanji78
Copy link

Sanji78 commented Aug 28, 2025

@Crocmagnon

@Crocmagnon
Copy link
Contributor Author

Crocmagnon commented Aug 28, 2025

@Sanji78 water level should be ok with #1100
I won’t have time to work more on this in the foreseeable future. Please don’t @ me, especially on a merged PR.

@shmuelzon
Copy link
Contributor

@Crocmagnon I have an X9 Pro (not OMNI) lwmdoj that I've linked your ilt3k8.
In my case, the vacuum always appears in the docked state and I was wondering if it's the same as your vacuum or something unique to my model. I've tried to debug it a bit and see that the getCleanInfo_V2 message always contains {'state': 'idle', 'trigger': 'none'} and doesn't change while it's cleaning. It does send the same message (with idle) when it's emptying itself while working but I don't see another message when it's back to cleaning.
Is your vacuum sending the correct cleaning info?
Thanks in advance!

@DeebotUniverse DeebotUniverse locked as resolved and limited conversation to collaborators Sep 3, 2025
@edenhaus
Copy link
Member

edenhaus commented Sep 3, 2025

Please don't comment on merged PRs if they were merged weeks ago. @shmuelzon Crocmagnon, just comment above your comment that he doesn't want to be pinged. Please respect his decision.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
pr: new-feature PR, which adds a new feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants