TL;DR
A start, pause, resume, or dock call is considered successful as soon as the mower answers a separate status request. That proves Bluetooth communication worked, but it does not prove the command was accepted or that the mower changed state.
Problem
The command path writes the control payload, waits only DEFAULT_CHUNK_DELAY (30 ms), discards queued notifications, sends a separate status query, and returns the first 0x80 status response.
Relevant code:
The reverse-engineering notes already explain why a follow-up status query was added: the mower does not emit a dedicated response notification for normal control writes. However, the current implementation conflates “received a status packet” with “the requested action happened.”
Why it happens
The status request is independent from the preceding command. Several failure modes still produce a valid 0x80 response:
- the ATT write completed but the mower ignored the application command;
- the command was accepted but the state transition takes longer than 30 ms;
- the status request is processed before the control action;
- a weak connection delivers the status query while the preceding command was not acted upon;
- the mower reports an intermediate or unchanged state before movement starts.
In all of these cases, pyGrouw returns normally and consumers such as Home Assistant treat the service call as successful.
Current behavior
- Any valid follow-up status packet completes the command call.
- The returned state is not checked against the requested action.
- There is no distinction between:
- command write completed;
- command delivery uncertain;
- command accepted;
- requested state observed.
- The 30 ms timing is global and not based on mower behavior.
Expected behavior
The API should not claim confirmed success solely because a status packet arrived.
A robust result should distinguish at least:
- written: GATT write completed;
- confirmed: an expected post-command state was observed;
- unconfirmed/indeterminate: communication succeeded, but the requested effect could not be verified;
- failed: connection/write/response failed.
For bounded confirmation, the library can poll status until an action-specific predicate is met or a deadline expires. Examples:
start / resume: mowing mode observed;
pause: stopped/idle state observed away from the station;
dock: returning mode or station state observed.
Because protocol state transitions may be delayed or contain intermediate modes, this should use a documented timeout and polling interval rather than one fixed 30 ms sleep.
Impact
This is a direct explanation for user-visible behavior such as:
- Home Assistant shows the service call as successful but the mower does nothing;
- state appears unchanged immediately after a click;
- users click repeatedly because the first command appears ineffective;
- delayed queued commands later look random.
The problem becomes more likely near range boundaries and during Bluetooth proxy handoff.
Suggested direction
Introduce a typed command result and action-specific confirmation policy. Preserve a low-level method for callers that only want write delivery, but make the high-level mower helpers explicit about whether the action was actually observed.
Do not blindly resend after an indeterminate post-write failure; verify current state first to avoid duplicate or contradictory commands.
Acceptance criteria
- A test where the mower returns an unchanged
0x80 status does not report the command as confirmed.
- A delayed expected state can be observed through bounded follow-up polling.
- Timeout produces a clear unconfirmed/indeterminate result rather than silent success.
- Consumers can distinguish transport success from mower-state confirmation.
- Existing status polling remains quiet and does not reintroduce the authentication beep.
TL;DR
A start, pause, resume, or dock call is considered successful as soon as the mower answers a separate status request. That proves Bluetooth communication worked, but it does not prove the command was accepted or that the mower changed state.
Problem
The command path writes the control payload, waits only
DEFAULT_CHUNK_DELAY(30 ms), discards queued notifications, sends a separate status query, and returns the first0x80status response.Relevant code:
DEFAULT_CHUNK_DELAYis 30 msasync_command()uses that follow-up status flow for every control commandGrouwMower.async_command()treats the returned status as the successful command resultThe reverse-engineering notes already explain why a follow-up status query was added: the mower does not emit a dedicated response notification for normal control writes. However, the current implementation conflates “received a status packet” with “the requested action happened.”
Why it happens
The status request is independent from the preceding command. Several failure modes still produce a valid
0x80response:In all of these cases, pyGrouw returns normally and consumers such as Home Assistant treat the service call as successful.
Current behavior
Expected behavior
The API should not claim confirmed success solely because a status packet arrived.
A robust result should distinguish at least:
For bounded confirmation, the library can poll status until an action-specific predicate is met or a deadline expires. Examples:
start/resume: mowing mode observed;pause: stopped/idle state observed away from the station;dock: returning mode or station state observed.Because protocol state transitions may be delayed or contain intermediate modes, this should use a documented timeout and polling interval rather than one fixed 30 ms sleep.
Impact
This is a direct explanation for user-visible behavior such as:
The problem becomes more likely near range boundaries and during Bluetooth proxy handoff.
Suggested direction
Introduce a typed command result and action-specific confirmation policy. Preserve a low-level method for callers that only want write delivery, but make the high-level mower helpers explicit about whether the action was actually observed.
Do not blindly resend after an indeterminate post-write failure; verify current state first to avoid duplicate or contradictory commands.
Acceptance criteria
0x80status does not report the command as confirmed.