Skip to content

paluras/Smart_Litter_Box

Repository files navigation

Why I made this?

I've been blessed with two lovely cats that both seem to have urinary problems. One of them we had to rush to the vet because he had his bladder clogged and was not able to piss anymore. The main symptom was him visiting the litter box and not doing his thing anymore, just struggling, shaking, etc. Now the test results hint that the other cat seems to have the same issue.

The other alternatives were quite expensive or did not ship to my location.

Total project cost was approx $30

You can improve this project by replacing the one load cell in the middle with 4 smaller ones on each corner, might be a bit more expensive and more dificult to wire it up but the stability of the scale will be much better.

This README won't go into details on how to solder or wire the hardware, there are tons of tutorials online and you can read the documentation on each one of them.

Smart Litter Box

A cat litter box monitoring system that tracks visits, weight, waste output, and health patterns for your cats. Configure any number of cats via a single environment variable.

An ESP32-C3 microcontroller with a load cell measures weight changes in real time, publishes events via MQTT, and a Node.js backend processes the data, identifies which cat visited, tracks health metrics, and stores everything in InfluxDB. A React dashboard provides live monitoring, charts, and alerts.

Architecture

ESP32-C3 + HX711 load cell + SW-420 vibration sensor
    │
    │  MQTT (litter/events, litter/commands)
    ▼
Mosquitto broker (Docker)
    │
    ▼
Express backend (Docker)
    ├── Cat identification (weight-based, auto-adjusting ranges)
    ├── Health alert engine (6 alert types)
    ├── Visit tracking + weight history
    ├── Litter saturation tracking
    │
    ├──► InfluxDB (Docker) — 90-day retention
    │
    └──► REST API
            │
            ▼
       React dashboard (Vite)
       ├── TanStack Query (live polling)
       ├── Chart.js (4 chart types)
       └── shadcn/ui + Tailwind CSS

Hardware

Component Model Purpose
Microcontroller ESP32-C3-MINI-1 WiFi + MQTT + sleep management
Load cell + HX711 amplifier Weight measurement
Vibration sensor SW-420 Wake-from-sleep trigger
Power 4x AA batteries (6V) → 5V pin Portable power via AMS1117-3.3 regulator

Wiring

This is just how i did it, you can wire them differently, just make sure you also modify the esp32 code as well.

Component Pin
HX711 DOUT GPIO 10
HX711 SCK GPIO 1
SW-420 DO GPIO 2

Cat Identification

Cats are identified by their weight during a visit. The ESP32 collects up to 10 weight samples and uses the median to determine cat weight.

Cats are configured via the CATS environment variable in .env:

CATS=piscot:Piscot:4900:4400:5600,bulion:Bulion:6240:5600:7300
#     id:displayName:expectedWeightG:weightMinG:weightMaxG

Each entry defines a cat's ID, display name, expected weight, and the weight range used for identification. You can configure any number of cats, the dashboard and backend adapt automatically.

The boundaries between adjacent weight ranges auto-adjust: the midpoint between each cat's rolling average (last 5 visits) becomes the new boundary.

Health Alerts

The backend continuously monitors for 6 types of health concerns:

Alert Trigger
Low waste 2+ consecutive visits with < 20g waste
Long duration Visit duration > 3x the cat's rolling average
High frequency 4+ visits within 2 hours
No visit No visit for significantly longer than normal interval
Weight change > 300g gained or lost over a week
Litter full Accumulated waste exceeds historical average per clean cycle

MQTT Protocol

Events (ESP32 → Backend): litter/events

{"status": "CAT_ENTERED",        "value": 5100.0}
{"status": "VISIT_COMPLETE",     "waste_g": 45.2, "cat_weight_g": 4920.0, "duration_s": 38, "samples": 12}
{"status": "CLEANING_DONE",      "value": 0}
{"status": "MINOR_ACTIVITY",     "value": 250.0}
{"status": "LITTER_BOX_REMOVED", "value": -3000.0}
{"status": "HEARTBEAT",          "value": 45.0}
{"status": "SYSTEM_START",       "value": 0}
{"status": "SYSTEM_RESTART",     "value": 0}
{"status": "WAKE_UP",            "value": 0}
{"status": "FALSE_TRIGGER",      "value": 0}
{"status": "GOING_TO_SLEEP",     "value": 0}

Commands (Backend → ESP32): litter/commands

Command Effect
TARE Recalibrate scale zero (re-tare with current weight as baseline)

REST API

Method Endpoint Description
GET /api/state Live state, alerts, litter saturation, cat configs
GET /api/stats/:cat Today's visits, total waste, avg duration, weight
GET /api/weight/:cat 30-day weight history with rolling average
GET /api/history/:cat Last N visits (default 20)
GET /api/clean/history Clean history + current saturation
GET /api/patterns/:cat 7-day visit frequency + timestamps
POST /api/clean Mark litter as manually cleaned
POST /api/tare Remote scale recalibration via MQTT

Dashboard

The React frontend provides:

  • Status Bar — sensor online/offline/sleeping indicator, current scale weight, last heartbeat
  • Cat Cards — per-cat daily stats (visits, waste, duration, weight) with alert badges
  • Charts — waste per visit (bar), weight over time (line), litter saturation (line), visit time distribution (stacked bar)
  • Event Log — scrolling list of recent events
  • Litter Status — fullness progress bar, accumulated waste, visits since clean, "Mark as Cleaned" and "Recalibrate Scale" buttons
  • Dark mode toggle with localStorage persistence

Polling intervals: state every 5s, stats every 30s, history every 1m, charts every 5m.

Power & Sleep

The ESP32 uses light sleep to conserve battery:

  1. Vibration sensor (SW-420) triggers a GPIO interrupt → ESP32 wakes up
  2. Connects to WiFi and MQTT, publishes WAKE_UP
  3. Monitors the scale for cat visits
  4. After 30 seconds of inactivity, publishes GOING_TO_SLEEP and enters light sleep
  5. If no cat was detected, publishes FALSE_TRIGGER before sleeping

False visit protection after cleaning:

  • 10-second cooldown after a clean event
  • Visits shorter than 15 seconds are discarded
  • Cat weight must be at least 2,000g to count

Setup

Prerequisites

  • Docker and Docker Compose
  • Node.js 20+ (for frontend dev server)
  • Arduino IDE or PlatformIO (for ESP32 flashing)

1. Start the infrastructure

cp .env.example .env
# Edit .env — configure your cats in the CATS variable

docker-compose up -d

This starts Mosquitto (MQTT broker), InfluxDB, and the backend.

2. Start the frontend (development)

cd frontend
npm install
npm run dev

The dashboard will be available at http://localhost:5173.

3. Flash the ESP32

Open arduinoCodeExample/esp32.c++ in Arduino IDE. Update the network settings:

const char* WIFI_SSID     = "YourWiFi";
const char* WIFI_PASSWORD  = "YourPassword";
const char* MQTT_SERVER    = "192.168.x.x"; // your server IP

Install the required libraries:

  • PubSubClient (MQTT)
  • HX711 (load cell)

Flash to the ESP32-C3. On first boot, place the litter box on the scale — the system will tare automatically.

Scale Calibration

If the scale readings drift or the litter box is repositioned:

  1. Make sure only the litter box is on the scale (no cats)
  2. Click "Recalibrate Scale" on the dashboard
  3. The ESP32 will re-tare and save the new zero offset

A dedicated calibration sketch is available at arduinoCodeExample/calibrate.c++ for finding the correct CALIBRATION_FACTOR with a known weight.

Environment Variables

Variable Default Description
INFLUXDB_ORG smartlitter InfluxDB organization
INFLUXDB_BUCKET litter InfluxDB bucket name
INFLUXDB_TOKEN InfluxDB admin token
INFLUXDB_USERNAME admin InfluxDB admin user
INFLUXDB_PASSWORD InfluxDB admin password
INFLUXDB_URL http://localhost:8086 InfluxDB connection URL
MQTT_BROKER mqtt://localhost:1883 MQTT broker URL
MQTT_TOPIC litter/events MQTT event topic
CATS (see below) Cat config: id:displayName:expectedWeightG:minG:maxG comma-separated
VITE_API_URL http://localhost:3000 Frontend API base URL

Project Structure

smartLitterBox/
├── docker-compose.yml
├── .env
├── mosquitto/config/mosquitto.conf
├── backend/
│   ├── Dockerfile
│   ├── package.json
│   └── src/
│       ├── server.ts              # Entry point: MQTT + Express
│       ├── env.ts                 # dotenv loader
│       ├── types.ts               # Shared types
│       ├── catIdentification.ts   # Weight-based cat ID
│       ├── state.ts               # In-memory live state
│       ├── eventHandler.ts        # MQTT event processing
│       ├── healthAlerts.ts        # Health alert checks
│       ├── influx.ts              # InfluxDB read/write
│       └── routes.ts              # REST API routes
├── frontend/
│   ├── package.json
│   ├── vite.config.ts
│   └── src/
│       ├── main.tsx               # App entry + QueryClient
│       ├── App.tsx                # Layout
│       ├── api/client.ts          # API fetch functions
│       ├── types/index.ts         # Frontend types
│       ├── hooks/
│       │   ├── useQueries.ts      # TanStack Query hooks
│       │   ├── useEventLog.ts     # Event log state
│       │   └── useTheme.ts        # Dark mode
│       └── components/
│           ├── StatusBar.tsx       # Sensor status
│           ├── CatCard.tsx         # Per-cat stats
│           ├── Charts.tsx          # 4 Chart.js charts
│           ├── EventLog.tsx        # Recent events
│           ├── LitterStatus.tsx    # Litter saturation
│           └── ThemeToggle.tsx     # Dark mode toggle
└── arduinoCodeExample/
    ├── esp32.c++                  # ESP32 firmware
    └── calibrate.c++              # Scale calibration tool

Tech Stack

Layer Technology
Microcontroller ESP32-C3 (Arduino/C++)
Message broker Mosquitto 2.0 (MQTT)
Backend Express + TypeScript (Node.js 20)
Database InfluxDB 2.7 (90-day retention)
Frontend React 19 + Vite 7
UI shadcn/ui + Tailwind CSS 4
Charts Chart.js 4 + react-chartjs-2
Data fetching TanStack Query 5
Containerization Docker Compose

Testing done by Bulion and Piscot

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors