This release is a pre-release and may not be stable for production use.
yarbo-local
Local-first tooling and, later, the asyncio library behind a Home Assistant integration for Yarbo robots. It talks to the anonymous MQTT broker the robot runs on your LAN and to nothing else. No Yarbo account, no vendor servers, no telemetry.
Status: pre-alpha. Phase 0 validated the protocol on real hardware (firmware 3.14.11) and produced the knowledge base in protocol/: 23 commands verified with captures, the rest marked as candidates that cannot be sent. The library core is in place: a registry-gated session, typed state, the map, plan control (start, pause, resume, stop, return to dock, each verified against the robot), a fixture-driven simulator and a small client. It is on PyPI as yarbo-local. The Home Assistant integration (yarbo-local-ha) shows and controls the robot, and carries its own map card, which draws the map, the robot and plan progress.
What is here
| Path | Purpose |
|---|---|
src/yarbo_local/client.py |
YarboRobot: connect, read typed state, and run the verified reads. |
src/yarbo_local/session.py |
The protocol layer: reconnect, reply correlation, encoding choice, wake and controller rules. |
src/yarbo_local/registry.py |
The command allowlist loaded from protocol/commands.yaml. Forbidden names cannot be sent. |
src/yarbo_local/models.py |
RobotState and the map, plan and GNSS parsers. No I/O. |
src/yarbo_local/transport.py |
aiomqtt transport plus an in-memory fake for tests. |
src/yarbo_local/simulator.py |
A robot built from fixtures, for tests and for developing without hardware. |
src/yarbo_local/resolve.py |
Address resolution: last address, DNS name, subnet scan. |
src/yarbo_local/fieldmap.py |
Builds protocol/fields.yaml from the curated seed and the fixtures. |
src/yarbo_local/studio/ |
The Studio: aiohttp server and Lit UI (docs/studio.md). |
src/yarbo_local/codec.py |
zlib-or-plain JSON codec with the firmware rule and an observed-encoding fallback. |
src/yarbo_local/capture.py |
sniff: subscribe to snowbot/+/# and write every message to JSONL, optionally redacted. |
src/yarbo_local/probe.py |
probe: send one allowlisted command, show the correlated reply and the telemetry deltas. |
src/yarbo_local/discover.py |
discover: find brokers carrying snowbot traffic, identified by the serial in their topics. |
src/yarbo_local/dump.py |
dump: summarise a capture, including the full DeviceMSG key inventory. |
src/yarbo_local/sitecheck.py |
sitecheck: check a site with one or several robots, reads only, and write a report that is safe to share (docs/multi-robot.md). |
src/yarbo_local/redact.py |
Serial, MAC, IP, coordinate and Wi-Fi redaction for shareable fixtures. |
protocol/ |
The knowledge base: commands.yaml, fields.yaml, codes.yaml, fixtures/. |
docs/phase0.md |
The twelve questions Phase 0 answers, with the exact commands. |
Quick start
git clone https://github.com/yarbo-local/yarbo-local
cd yarbo-local
uv sync --extra dev
uv run yarbo-local discover 192.168.40.0/24
uv run yarbo-local sniff 192.168.40.23 --out captures/idle.jsonl
uv run yarbo-local dump captures/idle.jsonl --keys --app
uv run yarbo-local probe 192.168.40.23 get_device_msg
probe only sends commands on a short allowlist of reads plus the wake-up command. It will not send anything that moves the robot, changes the map, or touches settings.
Using the library
import asyncio
from yarbo_local import YarboRobot
async def main() -> None:
async with YarboRobot.for_host("192.168.50.184") as robot:
state = await robot.snapshot()
print(state.activity, state.battery, state.head_name)
for plan in await robot.plans():
print(plan.id, plan.name)
robot.on_state(lambda s: print("changed:", s.activity))
await asyncio.sleep(30)
asyncio.run(main())
Rules the session enforces, on purpose:
- Only commands in
protocol/commands.yamlcan be sent. Names in itsforbiddensection are not entries and can never be sent, with or without flags. - A command whose status is
candidateis refused unless the session was opened withallow_candidates=True. The Home Assistant integration never does that; the Studio does. - A command with
risk: confirmneedsconfirmed=Trueon the call. - The wake command and the controller role are used only when the command's flags say they are needed, and the controller is itself still a candidate.
- Outbound encoding follows the robot's firmware, or what it has been seen sending, so a robot on 3.9 or later never silently drops a plaintext command.
- The connection loop never returns on a dropped broker; it backs off with jitter and reconnects.
The same CLI can show what the library sees, stand up a fake robot from a fixture for development without hardware, and open the Studio, a local web UI for watching the protocol, documenting fields and saving fixtures (see docs/studio.md):
uv run yarbo-local status yarbo.localdomain --watch 30
uv run yarbo-local sim protocol/fixtures/3.14.11/get_device_msg-asleep.jsonl --broker 127.0.0.1
uv run yarbo-local studio yarbo.localdomain
Can't see the base station in your router or controller?
You won't. The base station bridges the rover's HaLow link onto your LAN behind a locally administered MAC that never associates with an access point or asks your DHCP server for an address. It picks a static address for itself, inside your DHCP pool, and it has no management page. Network controllers such as UniFi list clients by association or wired port, so the base station simply does not exist to them, even while it answers on ports 1883, 8883 and 22.
Do not spend an afternoon on this. Scan the subnet instead:
uv run yarbo-local discover 192.168.1.0/24 --wait 8
Every host carrying Yarbo traffic is listed with the serial it carries and its DNS name, if it has one. A robot is identified by its own topics and nothing else; the tool reads no ARP table and runs no other program. The rover and the base station both answer, with the same data. Then protect yourself from the address collision Yarbo set up for you: either shrink your DHCP pool so it starts above the base station's address, or put the Yarbo Wi-Fi association on an isolated VLAN so the whole bridge moves out of your main network.
Safety and privacy
The robot's broker has no authentication. Anyone on its network segment can drive it. Put the robot on its own VLAN, allow only the machine running this tooling (and later Home Assistant) to reach port 1883, and think deliberately about whether the robot should have internet access at all. Captures contain your serial number, coordinates and network details; use --redact and review the file before sharing it.
Have more than one robot?
Nobody on the project does. One command tells us what we cannot find out ourselves, without sharing a serial, an address or a position: see docs/multi-robot.md.
Contributing protocol knowledge
Read protocol/README.md. A command becomes verified only with a fixture showing the request and the reply on real hardware, with the firmware version recorded. Pull requests that add knowledge without evidence are asked for a capture.
Releasing
Releases are published to PyPI by GitHub Actions through trusted publishing, with a manual approval and no token anywhere. See docs/releasing.md.
License and trademark
MIT. Protocol facts were assembled from the vendor's MIT-licensed SDK, from python-yarbo, home-assistant-yarbo, the jtubb and briangann forks of the vendor integration, and the steves2j map editor; see protocol/commands.yaml for per-entry sources. Yarbo is a trademark of its owner. This project is not affiliated with, endorsed by, or supported by Yarbo.
Metadata
Release files for yarbo-local 0.1.0.dev1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| yarbo_local-0.1.0.dev1.tar.gz | 388.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| yarbo_local-0.1.0.dev1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 513.4 kB
Release files / yarbo_local-0.1.0.dev1.tar.gz
| Download URL | yarbo_local-0.1.0.dev1.tar.gz |
|---|---|
| Size | 388.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
39296405a6d446b1462891e0c944b72925d0a00834e98a19b10092913d46cce1
|
|
BLAKE2b-256 checksum How to use checksums |
f05ba769cec74f212e91a1f3bb7fb00f78c01dec316885f632f923d089e710e5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 26, 2026.
Transparency logRelease files / yarbo_local-0.1.0.dev1-py3-none-any.whl
| Download URL | yarbo_local-0.1.0.dev1-py3-none-any.whl |
|---|---|
| Size | 125.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
06d82a1a862436112ea6493b63fa846e6edfb7b1303ef652e28ff5c91d53289b
|
|
BLAKE2b-256 checksum How to use checksums |
555d88e5b92151e2caf868122e1c6e3b94a50404a8f6a555578a865850301dd8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 26, 2026.
Transparency log