Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ Keep the following in mind:

- **Credentials**: Never hard-code passwords, API keys, or serial numbers in code.
Use environment variables or a secrets manager. The RSA public key extracted from
the APK is not sensitive and can be committed; private keys and passwords must not be.
the public RSA key is not sensitive and can be committed; private keys and passwords must not be.

- **Network exposure**: The Yarbo EMQX broker listens on port 1883 (plaintext) on
the local network. Do **not** expose this port to the internet. Restrict access
Expand Down
10 changes: 5 additions & 5 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Contributing to python-yarbo

Thanks for your interest in contributing! python-yarbo is a community library
built on reverse-engineered protocol knowledge — every contribution matters.
built on community protocol documentation — every contribution matters.

## Table of Contents

Expand Down Expand Up @@ -149,13 +149,13 @@ pytest --cov=yarbo --cov-report=term-missing tests/

## Protocol Knowledge

python-yarbo is built on reverse-engineered protocol knowledge. If you discover
python-yarbo is a community project. If you discover
new commands, topics, or payload formats, please:

1. Document them in the related issue or PR
2. Add them to `src/yarbo/const.py` (topics) or as methods on the client
3. Reference the source of discovery (packet capture, APK analysis, etc.)
4. Cross-reference with `yarbo-reversing/docs/COMMAND_CATALOGUE.md`
3. Reference the source of discovery (hardware testing, protocol observation, etc.)
4. Cross-reference with existing protocol documentation

### Key protocol facts

Expand All @@ -165,4 +165,4 @@ new commands, topics, or payload formats, please:
- Light keys: `led_head`, `led_left_w`, `led_right_w`, `body_left_r`, `body_right_r`, `tail_left_r`, `tail_right_r`
- Values are integers 0–255, **not** booleans

See [`yarbo-reversing`](https://github.com/markus-lassfolk/yarbo-reversing) for full protocol docs.
See [protocol documentation](docs/index.md) for full protocol docs.
20 changes: 7 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)

Python library for **local and cloud control** of [Yarbo](https://yarbo.com/) robot
mowers and snow blowers — built from reverse-engineered protocol knowledge.
mowers and snow blowers — a community-developed project.

> **Status**: Alpha (0.1.0) — local MQTT control is functional and confirmed working
> on hardware. Cloud API is partially functional (JWT auth migration in progress).
Expand Down Expand Up @@ -117,7 +117,7 @@ async def main():
async with YarboCloudClient(
username="your@email.com",
password="yourpassword",
rsa_key_path="/path/to/rsa_public_key.pem", # from APK
rsa_key_path="/path/to/rsa_public_key.pem", # see keys/README.md
) as client:
robots = await client.list_robots()
for robot in robots:
Expand Down Expand Up @@ -225,8 +225,7 @@ Recommendations:

## Protocol Notes

This library was built from reverse-engineering the Yarbo Flutter app and
live packet captures. Key protocol facts:
Key protocol facts (community-observed):

- **MQTT broker**: Local EMQX (port 1883). Use `yarbo discover` (scans host networks) or
`yarbo discover --subnet <CIDR>` to find Rover/DC endpoints; IPs are DHCP-assigned.
Expand All @@ -239,7 +238,7 @@ live packet captures. Key protocol facts:
`BatteryMSG.capacity`, `StateMSG.working_state`, `RTKMSG.heading`,
`CombinedOdom.x/y/phi`
- **Not yet implemented**: Local REST API (port 8088) and TCP JSON (port 22220)
are documented in `yarbo-reversing` but not implemented here
are not yet implemented here

## Debug and troubleshooting

Expand Down Expand Up @@ -299,17 +298,13 @@ yarbo status --broker 192.168.1.1 --sn ABC123 --report-mqtt

From Python you can capture and send a dump yourself using `report_mqtt_dump_to_glitchtip` from `yarbo.error_reporting`, and `client.get_captured_mqtt()` when the client was created with `mqtt_capture_max > 0` (see `YarboLocalClient` and `MqttTransport` parameters).

See [`yarbo-reversing`](https://github.com/markus-lassfolk/yarbo-reversing) for:
- Full [command catalogue](https://github.com/markus-lassfolk/yarbo-reversing/blob/main/docs/COMMAND_CATALOGUE.md)
- [Light control protocol](https://github.com/markus-lassfolk/yarbo-reversing/blob/main/docs/LIGHT_CTRL_PROTOCOL.md)
- [API endpoints](https://github.com/markus-lassfolk/yarbo-reversing/blob/main/docs/API_ENDPOINTS.md)
- [MQTT protocol reference](https://github.com/markus-lassfolk/yarbo-reversing/blob/main/docs/MQTT_PROTOCOL.md)
See [protocol documentation](docs/index.md) for additional protocol details.

Copilot AI Mar 1, 2026

Copy link

Choose a reason for hiding this comment

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

The link text suggests docs/index.md contains protocol details, but docs/index.md currently only has general navigation/quick start and no protocol-specific references. Either add/restore protocol documentation links/content there, or adjust this sentence so it doesn't imply protocol docs exist at that location.

Suggested change
See [protocol documentation](docs/index.md) for additional protocol details.
See the [documentation](docs/index.md) for additional details and usage information.

Copilot uses AI. Check for mistakes.

## Related Projects

| Project | Description |
|---------|-------------|
| [`yarbo-reversing`](https://github.com/markus-lassfolk/yarbo-reversing) | Protocol RE: Frida scripts, MITM setup, APK tools |
| [`home-assistant-yarbo`](https://github.com/markus-lassfolk/home-assistant-yarbo) | Home Assistant integration (coming soon) |
| [`PSYarbo`](https://github.com/markus-lassfolk/PSYarbo) | PowerShell module (same protocol, same architecture) |

## License
Expand All @@ -318,5 +313,4 @@ MIT — see [LICENSE](LICENSE).

## Disclaimer

This library was built by reverse engineering. It is not affiliated with or endorsed by
Yarbo. Use at your own risk. Do not expose your robot's MQTT broker to the internet.
This is a community project, not affiliated with or endorsed by Yarbo. Use at your own risk. Do not expose your robot's MQTT broker to the internet.
5 changes: 2 additions & 3 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@ Python library for local and cloud control of Yarbo robot mowers via MQTT.
## Navigation

- [API Reference](api.md)
- [Protocol Details](https://github.com/markus-lassfolk/yarbo-reversing/blob/main/docs/COMMAND_CATALOGUE.md)
- [Light Control Protocol](https://github.com/markus-lassfolk/yarbo-reversing/blob/main/docs/LIGHT_CTRL_PROTOCOL.md)
- [API Endpoints](https://github.com/markus-lassfolk/yarbo-reversing/blob/main/docs/API_ENDPOINTS.md)
- [GitHub Repository](https://github.com/markus-lassfolk/python-yarbo)
- [PSYarbo PowerShell module](https://github.com/markus-lassfolk/PSYarbo)
- [CHANGELOG](../CHANGELOG.md)
- [CONTRIBUTING](../CONTRIBUTING.md)

Copilot AI Mar 1, 2026

Copy link

Choose a reason for hiding this comment

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

docs/index.md removed the protocol-detail links (command catalogue, light control protocol, API endpoints), but other docs/metadata now refer to this page as "protocol documentation". Either reintroduce protocol-detail navigation here (possibly pointing to in-repo docs) or update those references so users don't lose the protocol entry point.

Suggested change
## Protocol documentation
This page is the entry point for the Yarbo protocol documentation. For low-level details about the MQTT and cloud protocols, see:
- [Command catalogue](protocol/command-catalogue.md)
- [Light control protocol](protocol/light-control.md)
- [Cloud API endpoints](protocol/cloud-api.md)

Copilot uses AI. Check for mistakes.
Expand Down
5 changes: 2 additions & 3 deletions examples/cloud_login.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@

Requires:
pip install "python-yarbo[cloud]"
RSA public key from the Yarbo APK (assets/rsa_key/rsa_public_key.pem)
See: https://github.com/markus-lassfolk/yarbo-reversing
RSA public key PEM file (see src/yarbo/keys/README.md for how to obtain it)

Usage:
python examples/cloud_login.py --username you@example.com --password secret \\
Expand Down Expand Up @@ -72,7 +71,7 @@ async def main(username: str, password: str, key_path: str | None) -> None:
ap.add_argument(
"--key",
default=os.environ.get("YARBO_RSA_KEY_PATH"),
help="Path to RSA public key PEM (from APK)",
help="Path to RSA public key PEM (see keys/README.md)",
)
args = ap.parse_args()

Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ Repository = "https://github.com/markus-lassfolk/python-yarbo"
"Bug Tracker" = "https://github.com/markus-lassfolk/python-yarbo/issues"
Documentation = "https://github.com/markus-lassfolk/python-yarbo#readme"
Changelog = "https://github.com/markus-lassfolk/python-yarbo/blob/main/CHANGELOG.md"
"yarbo-reversing" = "https://github.com/markus-lassfolk/yarbo-reversing"
"Protocol Documentation" = "https://github.com/markus-lassfolk/python-yarbo/blob/main/docs/index.md"

Copilot AI Mar 1, 2026

Copy link

Choose a reason for hiding this comment

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

[project.urls] adds a "Protocol Documentation" link pointing to docs/index.md, but that page doesn't currently contain protocol documentation (only general docs). Consider either pointing this URL at the actual protocol docs location (if any) or renaming/removing the entry to avoid misleading package metadata.

Suggested change
"Protocol Documentation" = "https://github.com/markus-lassfolk/python-yarbo/blob/main/docs/index.md"

Copilot uses AI. Check for mistakes.

[tool.hatch.build.targets.wheel]
packages = ["src/yarbo"]
Expand Down
4 changes: 2 additions & 2 deletions src/yarbo/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
yarbo — Python library for local and cloud control of Yarbo robot mowers.

Yarbo makes autonomous snow blowers and lawn mowers controlled via local MQTT.
This library was built from reverse-engineering the Yarbo Flutter app and
probing the protocol with live hardware captures.
This is a community-developed library for the Yarbo protocol, built through
hardware testing and protocol documentation.

Quick start (async)::

Expand Down
2 changes: 1 addition & 1 deletion src/yarbo/_codec.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
The robot firmware checks the firmware version (>= 3.9.0, MIN_ZIP_MQTT_VERSION)
before decompressing. All current firmware versions use zlib compression.

Reference: Blutter ASM analysis of the Flutter app's MqttPublish class.
Reference: Community protocol documentation for the Yarbo MQTT interface.
"""

from __future__ import annotations
Expand Down
11 changes: 5 additions & 6 deletions src/yarbo/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,11 @@
before transmission (despite OAEP references in the Dart code — confirmed by
live testing that PKCS1v15 is the actual padding used).

The RSA public key is bundled in the Yarbo app APK at:
The RSA public key can be obtained from the Yarbo app and placed at:
``assets/rsa_key/rsa_public_key.pem``
Comment on lines +9 to 10

Copilot AI Mar 1, 2026

Copy link

Choose a reason for hiding this comment

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

The docstring says the RSA public key can be "placed at" assets/rsa_key/rsa_public_key.pem, which reads like a destination path. That path is inside the mobile app package; consider rewording to clarify it's the location within the app package (and point to src/yarbo/keys/README.md for how the library expects the PEM to be provided).

Suggested change
The RSA public key can be obtained from the Yarbo app and placed at:
``assets/rsa_key/rsa_public_key.pem``
The RSA public key can be obtained from the Yarbo mobile app; within the app
package it is stored at ``assets/rsa_key/rsa_public_key.pem``. See
``src/yarbo/keys/README.md`` for how this library expects the PEM to be
provided.

Copilot uses AI. Check for mistakes.

References:
yarbo-reversing/yarbo/auth.py — original synchronous implementation
yarbo-reversing/docs/API_ENDPOINTS.md — endpoint documentation
Protocol documentation (API endpoint reference)
"""

from __future__ import annotations
Expand Down Expand Up @@ -45,7 +44,7 @@ class YarboAuth:
base_url: REST API gateway base URL.
username: User email address.
password: Plaintext password (encrypted before transmission).
rsa_key_path: Path to the RSA public key PEM extracted from the APK.
rsa_key_path: Path to the RSA public key PEM.
If not provided, falls back to the vendored key in the
package (if available).
session: Existing ``aiohttp.ClientSession`` to reuse.
Expand Down Expand Up @@ -83,7 +82,7 @@ def _default_key_path() -> Path:
.. warning::
The vendored key at ``src/yarbo/keys/rsa_public_key.pem`` is a
**placeholder** — cloud auth will fail until it is replaced with
the real key extracted from the Yarbo APK.
the real key (see keys/README.md for instructions).

See ``src/yarbo/keys/README.md`` for extraction instructions, or
supply the real key path via ``rsa_key_path`` at construction time.
Expand Down Expand Up @@ -181,7 +180,7 @@ def _load_public_key(self) -> object:
except FileNotFoundError as exc:
raise YarboAuthError(
f"RSA public key not found at {self._key_path}. "
"Extract it from the Yarbo APK: assets/rsa_key/rsa_public_key.pem"
"Obtain the key and place it at: assets/rsa_key/rsa_public_key.pem"
) from exc
Comment on lines 181 to 184

Copilot AI Mar 1, 2026

Copy link

Choose a reason for hiding this comment

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

The FileNotFoundError message says "Obtain the key and place it at: assets/rsa_key/rsa_public_key.pem". assets/... is the location inside the Yarbo app package, not a path the library reads from; this is likely to confuse users. Suggest changing the message to (a) point at the expected PEM path (rsa_key_path or the vendored yarbo/keys/rsa_public_key.pem) and (b) reference keys/README.md for where to obtain it from the app.

Copilot uses AI. Check for mistakes.
except ImportError as exc:
raise YarboAuthError(
Expand Down
7 changes: 3 additions & 4 deletions src/yarbo/cloud.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,10 @@
The Yarbo backend is actively migrating from plain JWT Bearer tokens to
AWS SigV4 (IAM/Cognito) auth. Many endpoints that previously accepted JWT
now return 403. Endpoints marked ✅ work with Bearer auth.
See yarbo-reversing/yarbo/client.py for a full status inventory.
See the protocol documentation for a full endpoint status inventory.

References:
yarbo-reversing/yarbo/client.py — synchronous reference implementation
yarbo-reversing/docs/API_ENDPOINTS.md — endpoint documentation
Protocol documentation (API endpoint reference)
"""

from __future__ import annotations
Expand Down Expand Up @@ -51,7 +50,7 @@ class YarboCloudClient:
username: User email address.
password: Plaintext password.
base_url: Override the REST gateway base URL.
rsa_key_path: Path to the RSA public key PEM (extracted from APK).
rsa_key_path: Path to the RSA public key PEM (see keys/README.md).
"""

def __init__(
Expand Down
2 changes: 1 addition & 1 deletion src/yarbo/cloud_mqtt.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
Transport: TLS 1.2+, server certificate validated when ``tls_ca_certs`` is supplied.

References:
yarbo-reversing/docs/MQTT_PROTOCOL.md — protocol reference
Protocol documentation (MQTT protocol reference)
Tencent TDMQ MQTT documentation — broker configuration
"""

Expand Down
11 changes: 5 additions & 6 deletions src/yarbo/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@
All topic templates, port numbers, and default values used by the
local and cloud MQTT transports.

Discovery sources:
- Blutter ASM analysis of the Flutter app (libapp.so)
- Live packet captures on the local EMQX broker (use discover() for broker IP)
- yarbo-reversing/docs/COMMAND_CATALOGUE.md
Protocol sources:
- Protocol observations on the local EMQX broker (use discover() for broker IP)
- Protocol documentation (command catalogue)

Transport support matrix
------------------------
Expand Down Expand Up @@ -82,11 +81,11 @@
TOPIC_LEAF_LOG_FEEDBACK = "log_feedback"
TOPIC_LEAF_A_PROPERTY_1 = "a_property_1_feedback"

# Live-confirmed telemetry leaves (zlib JSON ~1-2 Hz)
# Observed telemetry leaves (zlib JSON ~1-2 Hz)
TOPIC_LEAF_DEVICE_MSG = "DeviceMSG"
"""Full telemetry payload: BatteryMSG, StateMSG, RTKMSG, CombinedOdom, etc."""

# Live-confirmed heartbeat leaf (plain JSON ~1 Hz)
# Observed heartbeat leaf (plain JSON ~1 Hz)
TOPIC_LEAF_HEART_BEAT = "heart_beat"
"""Heartbeat: plain JSON ``{"working_state": 0|1}``.
NOTE: ``heart_beat`` is NOT zlib-compressed — the codec's plain-JSON
Expand Down
4 changes: 1 addition & 3 deletions src/yarbo/discovery.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@
DC is recommended when both are present (stays connected via HaLow when Rover leaves WiFi).

Reference:
yarbo-reversing/yarbo/mqtt.py — MQTT_BROKER constant
yarbo-reversing/scripts/local_ctrl.py — DEFAULT_BROKER
docs/BROKER_ROLES.md — MAC↔role reference
Protocol documentation (MQTT broker details and MAC/role reference)
"""

from __future__ import annotations
Expand Down
15 changes: 2 additions & 13 deletions src/yarbo/keys/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,10 @@ Cloud login (`YarboCloudClient`) requires the real key to encrypt the password.

## How to get the real key

The actual public key is bundled inside the Yarbo Android APK at:
The actual public key can be obtained from the Yarbo app package and placed at:

```
assets/rsa_key/rsa_public_key.pem
```

### Extract from APK

```bash
# 1. Download the Yarbo APK (from Google Play via apkpure or your device)
# 2. Unzip it (APKs are ZIP archives)
unzip yarbo.apk -d yarbo_unpacked

# 3. Copy the key
cp yarbo_unpacked/assets/rsa_key/rsa_public_key.pem /path/to/python-yarbo/src/yarbo/keys/
src/yarbo/keys/rsa_public_key.pem
```
Comment on lines +11 to 15

Copilot AI Mar 1, 2026

Copy link

Choose a reason for hiding this comment

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

src/yarbo/keys/rsa_public_key.pem is a repo-relative path; for users installing from PyPI there is no src/ directory. Consider either (1) documenting the installed path (.../site-packages/yarbo/keys/rsa_public_key.pem) if you want to support vendoring, or (2) recommending the runtime rsa_key_path approach as the primary method and framing the vendoring path as "when working in the repository".

Copilot uses AI. Check for mistakes.

### Supply at runtime (alternative)
Expand Down
Loading
Loading