# Datacat Collect metrics from Whisker Litter Robot devices and submit to Datadog. Datacat connects to the Whisker API (used by Litter-Robot and Feeder-Robot devices) and periodically collects metrics, submitting them to Datadog for monitoring and alerting. ## Supported Devices - **Litter-Robot 3** - Original connected litter box - **Litter-Robot 4** - Newer model with additional sensors - **Feeder-Robot** - Automatic pet feeder ## Features - Collects metrics from all connected robots every 5 minutes (configurable) - Fetches activity history to detect cat usage events - Collects insight data (cycle counts, daily averages) - Submits metrics to Datadog via DogStatsD - Emits Datadog events for state changes (cat usage, drawer full, offline, errors) - Supports pet profile metrics (weight, health status, visit count) - Dry-run mode for testing without submitting metrics - Configuration via environment variables or YAML file ## Installation ### Using UV (recommended) ```bash # Clone the repository git clone https://github.com/yourusername/datacat.git cd datacat # Install with UV uv sync # Run uv run python -m datacat ``` ### Using pip ```bash pip install . datacat ``` ### Using Docker ```bash # Build the image docker build -t datacat . # Run with environment variables docker run -d \ -e WHISKER_USERNAME=your-email@example.com \ -e WHISKER_PASSWORD=your-password \ -e DATADOG_API_KEY=your-api-key \ datacat ``` ## Configuration Datacat can be configured via environment variables, a YAML config file, or both. Environment variables take precedence over config file values. ### Environment Variables | Variable | Description | Required | |----------|-------------|----------| | `WHISKER_USERNAME` | Whisker account email | Yes | | `WHISKER_PASSWORD` | Whisker account password | Yes | | `DATADOG_API_KEY` | Datadog API key | Yes | | `DATADOG_APP_KEY` | Datadog application key | No | | `DATADOG_SITE` | Datadog site (default: `datadoghq.com`) | No | | `DATACAT_POLL_INTERVAL` | Polling interval in seconds (default: `300`) | No | | `DATACAT_INCLUDE_PETS` | Include pet metrics (default: `true`) | No | | `DATACAT_EMIT_EVENTS` | Emit Datadog events (default: `true`) | No | | `DATACAT_COLLECT_ACTIVITY` | Fetch activity history (default: `true`) | No | | `DATACAT_COLLECT_INSIGHTS` | Fetch insight data (default: `true`) | No | | `DATACAT_API_DELAY` | Delay between API calls in seconds (default: `1.0`) | No | | `DATACAT_ACTIVITY_LOOKBACK` | Only emit events for activities within N minutes (default: `10`) | No | | `DATACAT_METRIC_PREFIX` | Metric prefix (default: `litterrobot`) | No | | `DATACAT_CONFIG_FILE` | Path to YAML config file | No | ### Config File (YAML) ```yaml whisker: username: "your-email@example.com" password: "your-password" datadog: api_key: "your-datadog-api-key" app_key: "your-datadog-app-key" # optional site: "datadoghq.com" metric_prefix: "litterrobot" collector: poll_interval_seconds: 300 include_pets: true emit_events: true collect_activity_history: true collect_insights: true api_call_delay_seconds: 1.0 activity_lookback_minutes: 10 ``` ## Usage ```bash # Run continuously (default) datacat # Run with config file datacat -c config.yaml # Run once and exit datacat --once # Dry run (log metrics instead of submitting) datacat --dry-run # Verbose logging datacat -v ``` ## Metrics ### Litter Robot Metrics (LR3 & LR4) | Metric | Type | Description | |--------|------|-------------| | `litterrobot.online` | Gauge | 1 if online, 0 if offline | | `litterrobot.waste_drawer_level` | Gauge | Drawer fullness (0-100%) | | `litterrobot.cycle_count` | Gauge | Cycles since last reset | | `litterrobot.cycle_capacity` | Gauge | Max cycles before full | | `litterrobot.waste_drawer_full` | Gauge | 1 if drawer is full | | `litterrobot.is_sleeping` | Gauge | 1 if in sleep mode | | `litterrobot.wait_time_minutes` | Gauge | Clean cycle delay | | `litterrobot.night_light_enabled` | Gauge | Night light status | | `litterrobot.panel_lock_enabled` | Gauge | Panel lock status | | `litterrobot.power_status` | Gauge | 2=AC, 1=DC, 0=NC | ### Insight Metrics (from Activity History) | Metric | Type | Description | |--------|------|-------------| | `litterrobot.insight.total_cycles` | Gauge | Total cycles in last 30 days | | `litterrobot.insight.average_cycles` | Gauge | Average daily cycles | | `litterrobot.insight.cycles_today` | Gauge | Cycles completed today | ### Litter Robot 4 Additional Metrics | Metric | Type | Description | |--------|------|-------------| | `litterrobot.litter_level` | Gauge | Litter level (0-100%) | | `litterrobot.litter_level_calculated` | Gauge | Calculated litter level from ToF sensor | | `litterrobot.pet_weight` | Gauge | Last recorded cat weight (lbs) from robot scale | | `litterrobot.scoops_saved` | Gauge | Environmental savings counter | | `litterrobot.wifi_rssi` | Gauge | WiFi signal strength (dBm) | | `litterrobot.night_light_brightness` | Gauge | Brightness level | | `litterrobot.hopper_enabled` | Gauge | Hopper status | | `litterrobot.lifetime_cycles` | Count | Total lifetime clean cycles | | `litterrobot.odometer_power_cycles` | Count | Total power cycles | | `litterrobot.odometer_empty_cycles` | Count | Total empty cycles | | `litterrobot.dfi_trigger_count` | Count | Drawer full indicator triggers | | `litterrobot.cat_detected` | Gauge | 1 if cat currently detected | ### Feeder Robot Metrics | Metric | Type | Description | |--------|------|-------------| | `feederrobot.food_level` | Gauge | Food level (0-100%) | | `feederrobot.gravity_mode_enabled` | Gauge | Gravity mode status | | `feederrobot.meal_insert_size` | Gauge | Meal insert size (cups) | ### Pet Metrics | Metric | Type | Description | |--------|------|-------------| | `litterrobot.pet.weight` | Gauge | Pet weight from profile (lbs) | | `litterrobot.pet.estimated_weight` | Gauge | User-entered estimated weight | | `litterrobot.pet.last_weight_reading` | Gauge | Last sensor weight reading | | `litterrobot.pet.is_healthy` | Gauge | Health status | | `litterrobot.pet.is_active` | Gauge | Active status | | `litterrobot.pet.age` | Gauge | Pet age | | `litterrobot.pet.visits_24h` | Gauge | Litter box visits in last 24 hours | ### Tags All metrics include the following tags: - `robot_id` - Unique robot identifier - `robot_serial` - Robot serial number - `robot_name` - User-defined robot name - `robot_model` - Robot model (Litter-Robot 3, Litter-Robot 4, Feeder-Robot) - `status` - Current robot status (for litter robots) Pet metrics include: - `pet_id` - Unique pet identifier - `pet_name` - Pet name - `pet_type` - Pet type (cat/dog) ## Events Datacat emits Datadog events for important state changes. Events are sourced from both real-time state changes and activity history polling. ### Cat Usage Events | Event | Alert Type | Description | |-------|------------|-------------| | Cat used litter box | Info | Cat detected and weighed (LR4 includes weight) | | Cat detected | Info | Cat is using the litter box | ### Cycle Events | Event | Alert Type | Description | |-------|------------|-------------| | Clean cycle started | Info | Cleaning cycle has begun | | Clean cycle complete | Info | Cleaning cycle finished | | Litter dispensed | Info | Litter hopper dispensed (LR4 with hopper) | ### Warning Events | Event | Alert Type | Description | |-------|------------|-------------| | Drawer full | Warning | Waste drawer needs emptying | | Drawer almost full | Warning | 1-2 cycles remaining | | Robot went offline | Warning | Lost connection to robot | | Bonnet removed | Warning | Bonnet has been removed | | On battery backup | Warning | Running on DC power | | Pinch detected | Warning | Pinch was detected | | Food level low | Warning | Feeder below 20% | ### Error Events | Event | Alert Type | Description | |-------|------------|-------------| | Cat sensor fault | Error | Cat sensor has a fault | | Over torque fault | Error | Motor over torque detected | | Dump position fault | Error | Dump position fault | | Home position fault | Error | Home position fault | ### Success Events | Event | Alert Type | Description | |-------|------------|-------------| | Robot back online | Success | Robot reconnected | ## Development ```bash # Install with dev dependencies uv sync # Run linter uv run ruff check src/ # Run formatter uv run ruff format src/ ``` ## Disclaimer This project uses the unofficial [pylitterbot](https://github.com/natekspencer/pylitterbot) library to communicate with the Whisker API. The API is reverse-engineered and may break at any time. Use at your own risk. ## License MIT