Install camera support for Litter-Robot 5 Pro
mainWebRTC live streaming requires the optional aiortc dependency. Install it using the camera extra:
pip install pylitterbot[camera]pip install pylitterbot[camera]repository·main·Indexed 41 days ago
https://github.com/natekspencer/pylitterbotAn unofficial Python API for controlling Whisker automated products, including Litter-Robot 3, 4, and 5, and Feeder-Robot. It provides classes for account authentication, robot control, activity and insight tracking, and a CameraClient for LR5 Pro camera management. Additionally, it includes an MCP (Model Context Protocol) server to enable AI-driven robot control via natural language assistants.
WebRTC live streaming requires the optional aiortc dependency. Install it using the camera extra:
pip install pylitterbot[camera]pip install pylitterbot[camera]Install the core package using pip:
pip install pylitterbotTo include the MCP (Model Context Protocol) server for AI assistant integration, install with the [mcp] extra:
pip install pylitterbot[mcp]Alternatively, you can clone the repository and use uv sync to set up the environment.
The MCP server allows AI assistants like Claude to control your robots via natural language.
Running the server:
pylitterbot-mcpOR
python -m pylitterbot.mcpClaude Desktop Configuration:
Add the following to your claude_desktop_config.json. Note that credentials are stored in plaintext; ensure your config file has restricted file permissions.
{
"mcpServers": {
"litter-robot": {
"command": "python",
"args": ["-m", "pylitterbot.mcp"],
"env": {
"LITTER_ROBOT_USERNAME": "your@email.com",
"LITTER_ROBOT_PASSWORD": "your_password"
}
}
}
}To interact with your robots, use the Account class. You must provide your Whisker account credentials to connect to the API. It is recommended to use an async context and ensure you call disconnect() to clean up the connection.
By default, account.connect(load_robots=True) will load all robots associated with your account. You can also filter for specific robot families by passing a list of classes to the robot_types argument in the Account constructor.
import asyncio
from pylitterbot import Account, LitterRobot4, LitterRobot5
username = "Your username"
password = "Your password"
async def main():
# Filter for specific robot types during initialization
account = Account(robot_types=[LitterRobot4, LitterRobot5])
try:
# Connect and load robots
await account.connect(username=username, password=password, load_robots=True)
print("Robots:")
for robot in account.robots:
print(robot)
finally:
# Always disconnect
await account.disconnect()
if __name__ == "__main__":
asyncio.run(main())To play recorded video clips, you must use the signed details provided by CameraClient.get_video_playback(clip_id). The hls_url provided in a standard VideoClip is unsigned and will result in a 403 error.
How to use:
get_video_playback(clip_id) to get a VideoPlayback object.hls_url attribute for the playlist URL..m3u8 playlist and its segments, you must include the cookie_header in your HTTP request.The LitterRobotSession implements a transparent authentication layer. When you call a request method like .get() or .post():
is_token_valid().skip_auth is not set to True), it automatically calls refresh_tokens() to renew the session.get_bearer_authorization().Authorization: Bearer <token> header into the request.500 status with a JSON body containing type: "InvalidCommandException", the session raises a pylitterbot.exceptions.InvalidCommandException with the developer message.The LitterRobotSession class is the primary entry point for interacting with the Litter-Robot cloud API. It manages authentication via Cognito, handles token refreshing automatically, and provides helper methods for HTTP requests.
It can be used as an asynchronous context manager to ensure the underlying aiohttp.ClientSession is closed correctly.
To use it, you can either initialize it with existing tokens or use the .login(username, password) method to authenticate with credentials.
from pylitterbot.session import LitterRobotSession
async def main():
# Using as an async context manager
async with LitterRobotSession() as session:
# Login with credentials
await session.login("your_email@example.com", "your_password")
# Perform requests
data = await session.get("https://api.litter-robot.com/v2/robots")
print(data)
import asyncio
asyncio.run(main())Once you have a robot instance from account.robots, you can perform various actions and modify settings.
Common Robot Methods:
start_cleaning(): Initiates a clean cycle.refresh(): Updates the robot's current state.reset_settings(): Resets the robot to default settings.set_panel_lockout(bool): Enables or disables the control panel.set_night_light(bool): Toggles the night light.set_power_status(bool): Toggles power.set_sleep_mode(bool): Toggles sleep mode.set_wait_time(int): Sets the wait time.set_name(str): Updates the robot's name.get_activity_history(): Retrieves recent activity.get_insight(): Retrieves robot insights.# Example: Starting a clean cycle
await robot.start_cleaning()The MCP server exposes several tools categorized by function:
Status and Info
get_robotsget_robot_statusget_activity_historyget_insightget_petsCommands
start_cleaningreset_robotgive_snackset_power_statusSettings
set_nameset_night_lightset_night_light_brightnessset_night_light_modeset_panel_lockoutset_wait_timeset_sleep_modeCompound Operations
fleet_overview: Prioritized status across all robots with alerts.clean_all_ready: Start cleaning on all robots in READY state.sync_settings: Copy one robot's settings to all others of the same model.pet_usage_report: Activity data across all robots with pet info.maintenance_forecast: Estimate when each robot needs emptying.household_digest: Time-bounded summary of all activity.troubleshooting_report: Diagnostic bundle for a robot with errors.robot_comparison: Compare settings and metrics across robots.The CameraStream class enables WebRTC live streaming. It requires the aiortc package. Use it as an asynchronous context manager to ensure resources are cleaned up.
Usage Pattern:
CameraStream with a CameraClient instance.on_video_frame(callback), on_audio_frame(callback), or on_connection_state_change(callback).await stream.wait_for_connection() to block until the stream is active.Example:
async with CameraStream(camera_client) as stream:
stream.on_video_frame(my_video_handler)
await stream.wait_for_connection()
# ... frames delivered via callback ...async with CameraStream(camera_client) as stream:
stream.on_video_frame(my_video_handler)
await stream.wait_for_connection()
# ... frames delivered via callback ...The GlobeMotorFaultStatus enum tracks errors related to the globe motor. Use GlobeMotorFaultStatus.from_raw(raw_string) to convert API string responses into enum members. This method is robust: it handles PascalCase, strips common prefixes like MTR_ or MOTOR_, and ensures the FAULT_ prefix is present.
from pylitterbot.enums import GlobeMotorFaultStatus
# Converting raw API strings
status = GlobeMotorFaultStatus.from_raw("MTR_PINCH") # Returns GlobeMotorFaultStatus.FAULT_PINCH
status = GlobeMotorFaultStatus.from_raw("overtorque") # Returns GlobeMotorFaultStatus.FAULT_OVERTORQUE_AMP (via regex/normalization)
status = GlobeMotorFaultStatus.from_raw("UNKNOWN_ERR") # Returns GlobeMotorFaultStatus.FAULT_UNKNOWNThe SleepSchedule class allows you to manage and query the sleep/activity windows for a device. It supports parsing schedules from raw API data (dictionaries or lists), creating schedules from timestamps, and checking if a specific time falls within a sleep window.
Key capabilities:
SleepSchedule objects.get_window(dt) to find the start and end datetime of the current sleep period.is_active(dt) to determine if the device is currently in a sleep state at a given time.get_day(day).from datetime import datetime, timedelta, timezone
from pylitterbot.sleep_schedule import SleepSchedule, DayOfWeek
# Example: Parsing a schedule from a dictionary
raw_data = {
"MONDAY": {"sleepTime": 1320, "wakeTime": 360, "isEnabled": True},
"TUESDAY": {"sleepTime": 1320, "wakeTime": 360, "isEnabled": True}
}
schedule = SleepSchedule.parse(raw_data)
# Check if currently in sleep mode
if schedule.is_active():
print("Device is sleeping")
# Get the specific time window for the current sleep period
window = schedule.get_window()
if window:
start, end = window
print(f"Sleeping from {start} to {end}")