botslab360
Async Python client for Botslab / 360 robot vacuums.
This project provides an unofficial Python interface for selected 360 robot vacuum cleaners and is intended as a reusable library for integrations such as Home Assistant.
Features
Currently implemented:
- Qihoo
Q/Tsession authentication - Optional headless Qihoo email/password authentication
- Automatic
qidderivation - Smart Home login and session handling
- Automatic Smart Home SID refresh
- Device discovery
- Robot status retrieval
- Robot station network-information retrieval
- TCP / push protocol communication
- AES decryption of push messages
- Current room discovery from the robot map
- Single-room and multi-room cleaning
- Start cleaning
- Pause cleaning
- Resume cleaning
- Return to dock
- Locate robot
Device control and room/map support have been verified with:
- 360 S9-P using the 360Robot backend
Other models may work but have not yet been verified.
Installation
pip install botslab360
Python 3.10 or newer is required.
Authentication
The existing authentication path uses Qihoo 360 account session tokens:
QT
These tokens can be obtained from an authenticated 360 web session.
They must be treated like credentials.
Never publish or log:
QTqidsidpushKey
Alternatively, the library can obtain Q/T with an email/password QUC login.
There are two separate account backends, selected explicitly with
AuthBackend. They are never tried as automatic fallbacks for each other.
For a Botslab / CloudSmart account, the existing regional backend remains the
default. Omitting backend is equivalent to AuthBackend.BOTSLAB, and omitting
region continues to select eu1:
from botslab360 import AuthBackend, Botslab360Client, DeviceIdentity
identity = DeviceIdentity.generate()
client = Botslab360Client.from_credentials(
"user@example.com",
"YOUR_PASSWORD",
backend=AuthBackend.BOTSLAB,
region="eu1",
device_identity=identity,
)
For an account from the original 360Robot application, select the non-regional
backend. Passing region with this backend is rejected:
client = Botslab360Client.from_credentials(
"user@example.com",
"YOUR_PASSWORD",
backend=AuthBackend.ROBOT360,
device_identity=identity,
)
After creating a new identity, store its mid, android_id, and m2 values
in the application's secure configuration and reconstruct the same
DeviceIdentity for later logins. These identifiers are not account secrets,
but they should not be rotated on every login.
The library does not solve captchas automatically. authenticate() raises
CaptchaRequired with image bytes and a challenge object. Present the image
to the user, collect the code without logging it, then explicitly call
continue_authentication(challenge, code). Each retry is caller initiated.
from botslab360 import CaptchaRequired
try:
session = await client.authenticate()
except CaptchaRequired as exc:
show_captcha_to_user(exc.challenge.image)
captcha_code = await read_captcha_code_without_logging()
session = await client.continue_authentication(
exc.challenge,
captcha_code,
)
On success, both methods return a ready SmartSession; callers never need to
handle Q, T, or qid themselves.
Basic usage
import asyncio
from botslab360 import Botslab360Client
async def main() -> None:
q = "YOUR_Q_TOKEN"
t = "YOUR_T_TOKEN"
async with Botslab360Client(q, t) as client:
await client.authenticate()
devices = await client.get_devices()
for device in devices:
print(device.name)
print(device.model)
status = await client.get_status(device.id)
print(f"Battery: {status.battery}%")
print(f"State: {status.state}")
print(f"Charging: {status.charging}")
asyncio.run(main())
For real applications, do not hard-code credentials. Load them securely from configuration or environment-specific secret storage.
Robot control
async with Botslab360Client(q, t) as client:
await client.authenticate()
devices = await client.get_devices()
robot = devices[0]
await client.start_cleaning(robot)
await client.pause(robot)
await client.resume(robot)
await client.return_to_dock(robot)
await client.locate(robot)
Room cleaning
Room cleaning always fetches the current map before validating and sending the selection. Room IDs are device- and map-specific; do not hard-code IDs without first reading the current room list.
rooms = await client.get_rooms(robot)
for room in rooms:
print(room.id, room.name, room.vertices)
await client.clean_rooms(robot, [1])
Pass multiple IDs to clean several rooms in one request:
await client.clean_rooms(robot, [1, 6])
When supplied by the robot, Room.vertices is the room polygon in the vendor's
map coordinate system (integer millimetres, original point order). Missing or
malformed polygons are exposed as None; raw MapInfo data is not exposed.
The Android room-attribute UI defines one or two cleaning passes, four suction modes, and three mopping water levels. Optional settings can override these verified attributes for selected rooms in one cleaning request:
from botslab360 import (
RoomCleaningSettings,
RoomFanMode,
RoomWaterLevel,
)
await client.clean_rooms(
robot,
[1],
room_settings={
1: RoomCleaningSettings(
clean_times=2,
fan_mode=RoomFanMode.STRONG,
water_pump=RoomWaterLevel.MEDIUM,
)
},
)
These settings apply only to the selected cleaning run. Omitted settings keep
the current values from the freshly fetched room map, including existing
vendor values and unrelated fields. The supported suction values are quiet,
auto (shown as Standard mode), strong (shown as Powerful mode), and max.
Water levels are 1 (low), 2 (medium), and 3 (high). An existing vendor
waterPump=0 value is preserved when not overridden, but 0 is not exposed as
an "off" choice because that meaning has not been confirmed.
Room.mode preserves the optional raw SweepArea.mode vendor string. Analysis
of the Android app found carpet-related values such as mode_big_carpet and
mode_tiny_carpet; this field is not a verified room sweep/mop selector. The
deprecated RoomCleaningMode compatibility enum and
RoomCleaningSettings.mode field must not be used for new code. Setting
RoomCleaningSettings.mode is rejected rather than writing an unverified value
to a cleaning request.
The Android app also has a separate SweepStrategy.cleanMode field with partial
evidence for mop and sweep values, but its relationship to room-cleaning
requests has not yet been verified.
Status information
Depending on the robot model, status information may include:
- Battery level
- Robot state
- Charging state
- Fan mode
- Cleaned area in square metres
- Cleaning time in seconds
- Error code
- Online state
Example:
Device: 360 Saugroboter
Model: S9-P
Battery: 100 %
State: fullcharge
Charging: True
Fan mode: strong
Cleaned area: 5
Cleaning time: 157
Error code: 0
Network information
The robot can report its current station network identity through the public
API. Missing vendor fields are returned as None, and MAC addresses are
normalized to lowercase colon-separated form.
network_info = await client.get_network_info(robot)
print(network_info.station_ip)
print(network_info.station_mac)
print(network_info.station_signal)
Treat SSIDs as potentially sensitive when displaying or logging
network_info.station_ssid.
Session handling
The library distinguishes between the Qihoo account session and the Smart Home session.
Conceptually:
Q + T
↓
qid
↓
Smart Home login
↓
sid + pushKey
↓
Device communication
If the Smart Home SID expires, the library performs one automatic re-authentication attempt using the existing Q and T tokens.
If the underlying Qihoo account session is no longer valid, the caller must provide new Q and T tokens.
The email/password path first obtains Q/T from QUC and then uses this same
Smart Home login path. The newer signed /v1 API is not used.
Development
Clone the repository:
git clone https://github.com/placix/python-botslab360.git
cd python-botslab360
Create a virtual environment:
python -m venv .venv
Activate it on Windows:
.\.venv\Scripts\Activate.ps1
Install in editable mode:
python -m pip install -e .
Install test dependencies:
python -m pip install -e ".[test]"
Run the test suite:
pytest
Files under diagnostics/ are development and protocol-verification tools.
Normal applications should use the public Botslab360Client API instead.
Project status
The library is currently under active development.
The current focus is providing a clean protocol layer that can later be used by a native Home Assistant integration.
Planned future work may include:
- Additional robot models
- Persistent push connection
- Fan speed control
- Zone cleaning
- Additional map features
Security
Authentication and session values must be treated as secrets.
Do not include real credentials in:
- bug reports
- screenshots
- logs
- test fixtures
- Git commits
Acknowledgements
python-botslab360 is an independent Python project and is not affiliated
with or maintained by TA2k or the ioBroker.botslab360 project.
The headless 360/Botslab QUC authentication flow in this project is based in
part on protocol research and implementation work by TA2k in
ioBroker.botslab360, in
particular its
lib/quc.js
implementation. Relevant parts of the protocol were additionally verified
against the decompiled Android application where possible. The Python
implementation and public API in this project were developed independently.
See ATTRIBUTION.md for license and attribution details.
License
MIT
Links
Release files for botslab360 0.5.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| botslab360-0.5.0.tar.gz | 78.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| botslab360-0.5.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 116.6 kB
Release files / botslab360-0.5.0.tar.gz
| Download URL | botslab360-0.5.0.tar.gz |
|---|---|
| Size | 78.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
1eef55fa5cf76522b724f4aba36be51a005cacb0d35006aaf52447e9f7f6f77d
|
|
BLAKE2b-256 checksum How to use checksums |
46b7f87e45d1560e7c65578c8751fc5ffd10f54e6fd188799e9921f36ea08a68
|
| 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 29, 2026.
Transparency logRelease files / botslab360-0.5.0-py3-none-any.whl
| Download URL | botslab360-0.5.0-py3-none-any.whl |
|---|---|
| Size | 38.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5edf47923cf2c7340a4108e43beeb23b3d4657b0b1e4c506f04f8aa17b061bb7
|
|
BLAKE2b-256 checksum How to use checksums |
9c908efabfbf0f5b85c14b3cdcc78076d43dd8ec4254df68caf7cc9170ed230c
|
| 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 29, 2026.
Transparency log