feat: add GOAT A3000 LiDAR support (cr0e4u / 51rcxt)#1641
Conversation
6c9551e to
98dd55b
Compare
98dd55b to
97de52b
Compare
97de52b to
1564899
Compare
1564899 to
4961c40
Compare
4961c40 to
d52c36e
Compare
c590334 to
cedd3f3
Compare
cedd3f3 to
5f21556
Compare
|
Thanks for putting this together — this is the full implementation the Some context that may help: I opened #1538 (the initial Happy to help:
Is the #1515 merge the main thing holding this back? If a maintainer can advise on the preferred sequencing (land #1515 / #1624 first, or fold the |
Add support for the Ecovacs GOAT A3000 LiDAR mower (cr0e4u) and its Pro variant (51rcxt). New hardware definitions: - deebot_client/hardware/cr0e4u.py: full capability definition for the GOAT A3000 LiDAR including CleanMower, CleanMowerArea, CapabilityMap, blade + lens-brush life-span, and all mower-specific settings - deebot_client/hardware/51rcxt.py: delegates to cr0e4u (identical FW) New command: - deebot_client/commands/json/mow.py: CleanMowerArea sends the cleanMower command with a specific zone_id for targeted area mowing New message handlers: - deebot_client/messages/json/mow.py: OnMI + OnArI handlers reassemble chunked LZMA zone-polygon payloads and fire MapSubsetEvent / MapChangedEvent so the HA integration can render the zone map - deebot_client/messages/json/mower_telemetry.py: OnPos, OnCleanInfo, and OnStats handle mower-specific push telemetry (position, mow state, and progress statistics) mapping to PositionsEvent, StateEvent, and StatsEvent respectively Updated: - deebot_client/messages/json/__init__.py: register OnMI, OnArI, OnPos, OnCleanInfo, and OnStats in the MESSAGES dispatch table
5f21556 to
5fb408d
Compare
|
Thanks so much for jumping in — your hardware context is exactly what we need. A few things: Yes, the #1515 dependency is resolved in this PR. CleanMower is now defined directly in commands/json/clean.py and exported from the package, so this PR is fully self-contained and mergeable on its own. When you get a chance to test on the live 51rcxt, the most useful things to validate would be: getMI → onMI/onArI chunk flow: does the map actually render in HA after startup? Thanks again! I am excited to get this all supported. |
| # deebotPos is a dict; chargePos can be a list or dict | ||
| if isinstance(raw, dict): | ||
| items: list[Any] = [raw] | ||
| else: | ||
| items = raw | ||
|
|
| serial: int = int(data.get("serial", 0)) | ||
| index: int = int(data.get("index", 0)) | ||
| mid: str = str(data.get("mid", "1")) | ||
| info: str = str(data.get("info", "")) |
| dec = lzma.LZMADecompressor(lzma.FORMAT_RAW, None, [filter_props]) | ||
| full_bytes = dec.decompress(compressed, uncompressed_len) | ||
| except Exception as exc: |
| class CleanMower(Clean): | ||
| """Auto-mow command for lawn mower devices (GOAT A3000 LiDAR and similar). | ||
|
|
||
| Uses the ``clean`` endpoint with a V2-style ``content`` dict, matching | ||
| the protocol confirmed via traffic analysis of the GOAT A3000 (cr0e4u): | ||
|
|
||
| .. code-block:: json | ||
|
|
||
| {"act": "start", "content": {"type": "auto"}} | ||
| {"act": "stop", "content": {"type": ""}} | ||
| """ | ||
|
|
||
| def _get_args(self, action: CleanAction) -> dict[str, Any]: | ||
| content: dict[str, str] = {} | ||
| args = {"act": action.value, "content": content} | ||
| match action: | ||
| case CleanAction.START | CleanAction.RESUME: | ||
| content["type"] = CleanMode.AUTO.value | ||
| case CleanAction.STOP | CleanAction.PAUSE: | ||
| content["type"] = "" | ||
| return args | ||
|
|
| Note: ``onStats`` pushes are handled by the existing | ||
| :class:`~deebot_client.messages.json.stats.OnStats` handler, which | ||
| already supports the mower payload shape (``area`` + ``time`` fields). | ||
|
|
Summary
Adds support for the Ecovacs GOAT A3000 LiDAR robotic mower (hardware class
cr0e4u) and its Pro variant (51rcxt).All payloads and protocols confirmed via MITM traffic analysis of live device communication.
Changes
New hardware definitions
deebot_client/hardware/cr0e4u.py— Full capability definition for the GOAT A3000 LiDAR:CleanMowerfor auto-mow start/stop/pauseCleanMowerAreafor zone-targeted mowingCapabilityMapwithGetMIas the startup map-load triggerdeebot_client/hardware/51rcxt.py— The GOAT A3000 LiDAR Pro shares identical firmware and capabilities; delegates tocr0e4u.New commands (
deebot_client/commands/json/mow.py)CleanMowerArea— SendscleanMowerwith a zonetypeandvaluefor targeted area mowing.GetMI— SendsgetMIto trigger the mower to stream its full zone map via chunkedonMI/onArIMQTT pushes. This is what the Ecovacs app sends on every connect to load the map.New message handlers
deebot_client/messages/json/mow.py—OnMIandOnArI:lzma._decode_filter_propertiesused with# noqa: SLF001)MapSubsetEventfor each zone polygon (ROOMS) and no-go zone (NO_MOP_ZONES)MapChangedEventwhen a full batch is assembledOnArIuses the same handler asOnMI(identical wire protocol)deebot_client/messages/json/mower_telemetry.py— Three push telemetry handlers:OnPos— GPS position/heading push →PositionsEventOnCleanInfo— Mow state push (working/charging/idle) →StateEventOnStats— Mow progress push (area m², time s) →StatsEventUpdated
deebot_client/messages/json/__init__.py— RegistersOnMI,OnArI,OnPos,OnCleanInfo, andOnStatsin theMESSAGESdispatch table.Tests
tests/hardware/test_init.py— Addscr0e4utotest_get_static_device_infoand a fullcr0e4uentry totest_capabilities_event_extractionwith the complete expected event→command mapping.Protocol notes
The GOAT A3000 uses a request-triggered push model for zone map data, distinct from both standard vacuums and the device's own auto-pushed telemetry:
getMI→ mower streams chunkedonMI/onArILZMA pushes →OnMI/OnArI→MapSubsetEventonMapTraceduring mowing → handled by #1567 (OnMapTrace→MapTraceEvent)onPoson each GPS fix →OnPos→PositionsEventonCleanInfoon state change →OnCleanInfo→StateEventonStatsperiodically →OnStats→StatsEventChunked LZMA format used by
onMI/onArI:Related PRs
CleanMowertoclean.pyOnMapTracepush handler for live mow trace data51rcxtdefinition from Add support for GOAT A3000 LiDAR Pro (51rcxt) #1538 — replaces that minimal definition with the full mower capability set including map support