Tracking cat's activity patterns in a litter box with Raspberry Pi
Tags: raspberrypi, node, typescript, go
Published: 2020-01-06 20:08:10

## Liza Is Busy

I don't remember exactly how did I come up with that strange idea about getting a statistic about that kind of my cat's life activities. A couple of years ago I bought Raspberry Pi 2 for other project which I never finished and all this time I was looking for where else I could use it. And at some point I decided to make a device that will track my cat's toilet activities (When? For how long?). The idea seemed interesting to me because it was simple in terms of required hardware, didn't require a lot of code and I like working with data visualization. Plus it's pure fun :)

As you can guess from the heading my cat's name is Liza. There she is:

![Alt Liza](https://thepracticaldev.s3.amazonaws.com/i/dain27yz571ajmq25qrv.jpg)


##Hardware

- Closed litter box with door
- Raspberry Pi 2
- Magnet sensor with wires and connectors

A device itself is very simple. I put a magnet sensor on the litter box door and connected it to GPIO on Raspberry Pi board.

![Alt Litter Box](https://thepracticaldev.s3.amazonaws.com/i/9c6a2ojseujpfa63w4ys.jpg)

## Software

I split it into 3 different applications:
- monitor (listens for events from the sensor and puts them into a database)
- server (HTTP server which connected to the database and provides event data)
- UI (web application which displays events)

Source code https://github.com/ampext/lizaisbusy

### Monitor

It was a first step. I needed a code (application) that would listens to the sensor connected to board's GPIO and writes all events (when sensor is open or closed) to SQLite database. I decided to build a prototype with Node.js and JavaScript. After it was done, I didn't find any reason to rewrite it with more suitable language. The only thing which is annoying me is `node_modules` installation. It takes some time on Raspberry Pi to build `sqlite` and `pigpio` from C sources because JavaScript packages are just wrappers around native libraries.

### Server

A simple HTTP server written with Go. It reads raw events from the database and aggregates it into timeline events.

### UI

The most interesting part for me. It's built with TypeScript and React. In addition it uses `d3` but only for `d3-scale` package. It fetches events, groups them by day and displays as timeline charts. 

Each day represented as a series of vertical lines (events). Line position depends on event time and thickness depends on event duration. UI is responsive and supports light and dark themes.

You can try a demo with static data here https://ampext.ru/lizaisbusy/preview.html

![Alt UI](https://thepracticaldev.s3.amazonaws.com/i/ukk73sp0fxsucp1beiu3.png)

## How it works

I created two systemd services: one for monitor app and another one for HTTP server. The monitor application writes every magnet sensor state change into SQLite database. Those events are quite low level (it's just sensor state with timestamp) and can not be used for visualization. HTTP server (connected to the same database) aggregates those events into timeline events and sends to the client. Each timeline event represented by event type (currently only one), time and duration. Frontend application fetches events for last 100 days, groups them by day and renders into multiple SVG charts.

## Issues

The main issue for now is how to distinguish "normal" events when cat is inside litter box and a case when I'm cleaning it up. The solution might be a special button that will prevent events to be fired. Also I believe it's possible to filter out such events on software side because series of events during cleaning should have a different pattern.

Also, I have a lot of ideas about small UI improvements like tooltips, vertical guideline for mouse hover, zooming. It's a big field for experiments.

## What did I learn from statistics?

- Liza starts using the toilet in the morning between 6am and 8am.
- The first time usually is the longest and takes 3-5 minutes. 
- Later during the day it takes about 1 minute.
- She does it 3-4 times a day.
- The last time happens about 10pm.