whiskerless
Un-cloud your Whisker devices. Fully-local MQTT control and telemetry for the Whisker Litter-Robot 4 — no cloud account, no internet round-trip, no third-party servers. Your robot talks to your broker, and that's it.
Primary repository: developed at forgejo.bryantserver.com/SisyphusMD/whiskerless. The GitHub copy is a read-only mirror (HACS installs from it). Please file issues and pull requests on GitHub — the Forgejo repository does not take external issues.
Status: beta. The local protocol was recovered by reverse-engineering and validated against a real robot. Re-provisioning, telemetry, and settings are proven on hardware. The discrete actions (clean cycle, power, empty, resets) are intentionally left out — see What's not here.
Why
Out of the box, a Litter-Robot 4 only works through Whisker's AWS cloud: every status update and every button press makes a round-trip to the internet, and Whisker actively blocks third-party clients. whiskerless cuts the cloud out entirely. The robot keeps its firmware; you just re-point its MQTT trust + broker at your own, over its own BLE provisioning channel — no teardown, no UART, no reflash, and fully reversible.
You get:
- a Home Assistant integration (HACS) built to the Platinum quality bar — fully local, push-first, fully typed;
- a
whiskerlessCLI + Python library to provision, monitor, read, and control a robot directly; - a complete, public protocol reference — the first published map of the LR4 local MQTT protocol.
How it works (30 seconds)
BLE (one-time) re-point trust + broker runtime (forever after)
your laptop ───► CA + host + topics over protocomm ───► robot ──MQTT/TLS──► your broker ──► Home Assistant
The robot stores all of its cloud identity in NVS and exposes esp-idf
protocomm provisioning over BLE with no PIN. whiskerless writes your CA into
its root-CA slot and your broker IP as its host, then commits. From then on the
robot connects to your broker over TLS and speaks plain JSON — requestState,
settings writes, and a live telemetry stream. Full detail in
docs/how-it-works.md.
Install
Home Assistant (HACS)
- HACS → ⋮ → Custom repositories → add
https://github.com/SisyphusMD/whiskerlessas an Integration. - Install Whiskerless, restart Home Assistant.
- Make sure Home Assistant's MQTT integration is connected to your broker.
- Provision each robot onto that broker (below). It then appears on its own under Settings → Devices & Services as a Discovered device — click Add and give it a name. No broker details or serials to type.
See docs/setup/ for the broker, certificate, and discovery details.
The "app" — no Python needed (for provisioning)
Re-provisioning happens over Bluetooth from a computer near the robot. Grab the build for your OS from the releases page — Forgejo (primary) or GitHub (mirror):
-
macOS — download the signed installer for your chip (
whiskerless-macos-arm64.pkgfor Apple Silicon,whiskerless-macos-x86_64.pkgfor Intel), double-click to install, then run it in any terminal — it prompts for everything:whiskerless provisionIt's signed and notarized by Apple, so there's no "unidentified developer" warning. The first time it scans, macOS asks to let your terminal use Bluetooth — allow it. To update later, just download the newer
.pkgand double-click — it installs over the old one in place. -
Linux — download
whiskerless-linux-x86_64and run it:chmod +x ./whiskerless-linux-x86_64 ./whiskerless-linux-x86_64 provision
-
Windows — no standalone binary, but the PyPI CLI works natively —
bleakdrives Windows' built-in Bluetooth:uvx whiskerless provision
(Don't run the Linux binary under WSL: WSL can't reach the Bluetooth adapter, so provisioning won't work there.)
Prefer not to install anything? uvx whiskerless provision runs it one-shot.
CLI / library (PyPI)
- One-shot, no install:
uvx whiskerless provision - CLI on your PATH:
pipx install whiskerless - Library + BLE re-provisioning:
pip install 'whiskerless[ble]'
Quickstart (CLI)
Re-provision the robot onto your broker (one-time, over BLE; prompts for anything
you omit — --host-ip is your broker's address):
whiskerless provision --serial LR4Cxxxxxx --host-ip <broker-ip> --ca ca.crt --wifi-ssid MyIoT
Watch it:
whiskerless monitor --serial LR4Cxxxxxx --host <broker-ip> --ca ca.crt
Read its decoded state:
whiskerless state --serial LR4Cxxxxxx --host <broker-ip> --ca ca.crt
Change a setting (writes, then reads back to confirm):
whiskerless set night-light-mode auto --serial LR4Cxxxxxx --host <broker-ip> --ca ca.crt
Safety first
This library talks straight to a robot's controller, and some opcodes can reset it or, in the worst case, brick a control board. So it guards every send:
- Four opcodes are refused unconditionally (
0xA3,0xA4,0xAC,0xAD— reset / main-board-OTA orchestrator, globe-motor OTA, flash erase, hardware reset). No flag lets them through. - No motor command is exposed. No opcode is yet proven to drive the globe — the byte once shipped as "clean cycle" turned out to reset the robot — so the motor gate sits empty until a real trigger is confirmed.
- Untraced / control-band / calibration writes are refused unless you override them on purpose.
The guard lives in safety.py and both the CLI and
the integration funnel through it — see docs/devices/litter-robot-4/.
What's not here
The clean cycle, power on/off, the empty cycle, and the panel/drawer resets are
deliberately omitted. Reverse-engineering could not pin their exact
register+value to safe, actionable confidence — the firmware that dispatches those
inbound actions lives in a bootloader region absent from every public image, and the
byte once shipped as "clean cycle" was proven on a live robot to reset the unit, not
cycle it. Shipping the candidates as guesses would risk dangerous control-band
writes. They're tracked as open items with a clear path to close them — see the
reverse-engineering writeup,
docs/devices/litter-robot-4/compatibility.md,
and the issue templates. Contributions welcome.
Repository layout
whiskerless/
├─ src/whiskerless/ # the pip library (codec, MQTT, BLE, safety, CLI)
│ └─ devices/litter_robot_4/ # LR4 protocol: codec, commands, state model, link
├─ custom_components/whiskerless/ # the Home Assistant integration (depends on the lib)
├─ docs/ # protocol reference + setup + recovery guides
├─ examples/ # example automations
└─ tests/ # codec / safety / command / integration tests
Documentation
- How it works · Reverse-engineering writeup · Recovery
- Setup: MQTT broker · Certificates · Home Assistant
- LR4 protocol: protocol · commands · registers · compatibility
Adding another Whisker device
The library is structured so a new robot drops in under
src/whiskerless/devices/<x>/ (codec + commands + state model) and
custom_components/whiskerless/devices/<x>.py, reusing the shared MQTT transport,
BLE provisioning, and safety guard. See CONTRIBUTING.md.
License
MIT. Not affiliated with or endorsed by Whisker. "Litter-Robot" is a trademark of its respective owner; this project is independent and interoperates with hardware you own.
Metadata
Release files for whiskerless 0.1.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| whiskerless-0.1.3.tar.gz | 87.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| whiskerless-0.1.3-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 129.2 kB
Release files / whiskerless-0.1.3.tar.gz
| Download URL | whiskerless-0.1.3.tar.gz |
|---|---|
| Size | 87.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d6dd6d8cb36fa749970f1af06ee2822e2824a275c3917f691064f6eb2099013c
|
|
BLAKE2b-256 checksum How to use checksums |
1f9728ce244c0462e515fab973a2ad74d45f91a6b399ef6eb2187f5b6f0200b6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.13
|
Release files / whiskerless-0.1.3-py3-none-any.whl
| Download URL | whiskerless-0.1.3-py3-none-any.whl |
|---|---|
| Size | 42.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ee7e93b92acc43ac24434962323c19518bf0faba819dfb101080f57b33e0a5dc
|
|
BLAKE2b-256 checksum How to use checksums |
fb56d7e937f47f899cc09d6aa90df3f0f0aaa31b9512e6d3a27a0089749cb7e8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.13
|