Skip to content

Control commands are reported successful without confirming that the mower acted #13

Description

@Bjorkan

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:

  1. the ATT write completed but the mower ignored the application command;
  2. the command was accepted but the state transition takes longer than 30 ms;
  3. the status request is processed before the control action;
  4. a weak connection delivers the status query while the preceding command was not acted upon;
  5. 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.

Activity

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

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions