feat(mower): handle onChargeInfo and onScheduleTaskInfo state pushes#1647
feat(mower): handle onChargeInfo and onScheduleTaskInfo state pushes#1647nord- wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Pull request overview
Adds dedicated JSON message handlers for GOAT mower unsolicited MQTT state pushes (onChargeInfo, onScheduleTaskInfo) so mower StateEvent updates are produced without relying on legacy get* fallbacks, addressing stuck state transitions (scheduled mowing and return-to-dock).
Changes:
- Added
OnChargeInfohandler to map mower return/dock transitions (goCharging→RETURNING,idle→DOCKED). - Added
OnScheduleTaskInfohandler and refactored clean-info parsing into a sharedhandle_clean_info()used by both pushes andGetCleanInfo. - Registered new handlers in the JSON message dispatch table and added unit tests for the new mappings/ignored cases.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
deebot_client/messages/json/charge_state.py |
New onChargeInfo push handler mapping charge-related state to StateEvent. |
deebot_client/messages/json/clean_info.py |
New onScheduleTaskInfo push handler + shared handle_clean_info() parser used by GetCleanInfo. |
deebot_client/messages/json/__init__.py |
Registers OnChargeInfo and OnScheduleTaskInfo in MESSAGES dispatch. |
deebot_client/commands/json/clean.py |
Refactors GetCleanInfo message parsing to delegate to handle_clean_info(). |
tests/messages/json/test_charge_state.py |
New tests validating OnChargeInfo mappings and ignored states. |
tests/messages/json/test_clean_info.py |
New tests validating OnScheduleTaskInfo mappings and ignored states. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
GOAT mowers report their state via three unsolicited messages, but only onCleanInfo was handled (through the legacy get-command fallback). onChargeInfo (return-to-dock / work complete) and onScheduleTaskInfo (scheduled mow) fell through to "Unknown message" and were dropped, so the lawn_mower entity stayed on "docked" during scheduled mows and never returned to docked/returning after a run. Add dedicated message handlers: - OnChargeInfo: state "goCharging" -> RETURNING, "idle" -> DOCKED - OnScheduleTaskInfo: same payload shape as onCleanInfo, reuses the shared clean-info parser The clean-info state parsing is moved out of GetCleanInfo into a shared handle_clean_info() in messages/json/clean_info.py (commands -> messages, matching the existing import direction); GetCleanInfo now delegates to it. Verified against debug logs from a GOAT O1200 LiDAR Pro (class 2i0fns).
f8a648f to
7c2c524
Compare
If you explain exactly what needs to be done step by step, I could run some tests and then provide feedback. In case I need to use MQTT for testing, but I'm sorry, I can't help you. :( |
I'd like a review so that the PR can be approved. Right now, the integration does not work for GOAT mowers, as stated in the PR description:
|
Summary
GOAT mowers report their activity state via three unsolicited MQTT messages, but only one of them is currently handled:
onCleanInfoget*fallback (getCleanInfo)onScheduleTaskInfoUnknown messageonChargeInfoUnknown messagegetChargeInfoandgetScheduleTaskInfoare not in the legacy_LEGACY_USE_GET_COMMANDallow-list and have no dedicated handler, so both messages fall through toUnknown message. As a result thelawn_mowerentity:dockedduring a scheduled mow (theonScheduleTaskInfopush is dropped), andreturning/dockedafter a run (theonChargeInfopush is dropped) — state only refreshes via agetChargeStatepoll on reconnect.This is the library side of home-assistant/core#168621 (GOAT status stuck on "docked").
Root cause (from device debug logs)
Captured from a GOAT O1200 LiDAR Pro (class
2i0fns, fw 1.9.16) over a full dock → mow → dock cycle:onScheduleTaskInfocarries the exact same payload shape asonCleanInfo;onChargeInfocarries a top-levelstateofgoCharging/idle.Changes
messages/json/charge_state.py(new) —OnChargeInfo:stategoCharging→RETURNING,idle→DOCKED.messages/json/clean_info.py(new) —OnScheduleTaskInfo, plus a sharedhandle_clean_info()holding the clean-info →StateEventparsing.commands/json/clean.py—GetCleanInfonow delegates tohandle_clean_info(). The parsing moved fromcommandsintomessages, matching the existingcommands → messagesimport direction (a top-levelmessages → commandsimport would be circular). Behaviour is unchanged. Note: othercommandsre-usemessageshandlers via class inheritance (e.g.GetBattery(OnBattery)); a shared function is used here becauseGetCleanInfokeeps its command base class and only needs the parsing — happy to restructure to a class-based shape if preferred.messages/json/__init__.py— register the two new handlers.State is derived from
state(what the device is doing), nottrigger:statemotionStatecleanworkingCLEANINGcleanpausePAUSEDcleangoChargingRETURNINGgoChargingRETURNINGidleDOCKEDTests
New
tests/messages/json/test_charge_state.pyandtest_clean_info.pycover every mapping plus the ignored / unknown-state cases.GetCleanInfo's existing test is unchanged and still passes (the refactor is behaviour-preserving).Relation to other GOAT work
Complementary to, and deliberately non-overlapping with, the in-flight GOAT PRs:
OnCleanInfo/OnPos/OnMI/OnArI— this PR does not touchonCleanInfoand only adds the two state messages no other open PR covers.CleanMower) is the start-command side; this is the state-readback side.Happy to rebase or consolidate the shared clean-info parsing with #1641 once the merge order is clear.