Cats are independent creatures. They eat and drink as they please. But how often? And while we’re at it, when do they use the litterbox? Wouldn’t it be cool to get a notification when it’s time to clean the litter?
Cats monitor their humans all day long, so we thought it was time we used some clever tech to return the favour. Besides, we needed a break from monitoring things like MySQL, LEMP, Zookeeper or Kafka.
Disclaimer: Here at Server Density we do Server Monitoring. If you are looking for Pet Monitoring products, you will need to look elsewhere. We think sen.se mother is a versatile presence monitoring platform. If you are looking for a metrics platform (IoT style), then specific products like Xively and dweet.io, for alerting, might fit the bill.
Monitor Cats with Raspberry Pi and Bluetooth Low Energy
We wanted to monitor when our cats used the food tower. We also wanted to know when they drunk from the water fountain, and when they paid a visit to the litterbox.
We had a couple of .one Chipolos lying around (much appreciated swag from HostingCon in Amsterdam). We also had a few unused Raspberry Pi model 1 units. So we decided to implement our monitoring solution using Bluetooth Low Energy. The same could be achieved with an Arduino Nano or Micro and a HM-10 BLE module (for a cost of less than $10), but we decided to reuse what we already had.
We implemented presence monitoring by measuring the RSSI (Received Signal Strength Indication) and we identified the devices by their MAC address. Note that there is no credential authentication going on, and our MAC addresses can be spoofed. For the purposes of monitoring our cats we decided this was an acceptable risk profile.
There’s been some discussion as to whether RSSI is a good parameter for proximity measurement. RSSI is vendor dependant, i.e. each chip vendor can implement it in a different way and your mileage will vary. In our case we just needed to determine if our cat was “very close” or “too far”. For the purposes of this binary requirement, RSSI was an okay solution.
The Gear
- 2 x Bluetooth Low Energy tag devices. We used Chipolo because we had them. There are plenty of other options.
- 3 x Raspberry Pi. Ours were model 1. We added an inexpensive Wi-Fi and Bluetooth 4.0 dongles (you need Bluetooth version 4.0 for Low Energy support).
The Setup
We installed Raspbian on each of the Raspberry devices. This provides a Debian based system and everything we needed was easy to install.
Although we have a complete Node.JS library (node-Chipolo), we decided to use bluepy for interacting with the Chipolo devices. Bluepy runs on Linux. It’s a Python library that provides an interface to Bluetooth Low Energy devices. If you want to do this on Android, you may want to have a look at the Android Beacon Library.
To install bluepy we ran the following:
$ sudo apt-get install build-essential libglib2.0-dev libdbus-1-dev git $ git clone https://github.com/IanHarvey/bluepy.git $ cd bluepy/bluepy $ make
We then installed some additional dependencies:
$ sudo apt-get install python-numpy byobu
The Python code
We crafted a small Python script that does a 50 second long Bluetooth scan. It identifies the configured devices and, based on the RSSI reading, feeds the following values to our Server Density dashboard:
- 0 if we couldn’t find the device. The cat could be anywhere.
- 1 if the device is reachable but “not close”. The cat is probably snoozing somewhere.
- 2 if the device is “close”. The cat is probably drinking, eating, or using the litterbox. The reading doesn’t specify which facility the cat is using (if at all). A future iteration could employ weight or humidity sensors to do just that.
Now, let’s go through the most important bits of our code, starting with the devices we are looking to discover. You can see the cat’s name followed by an array for storing the RSSI values for each scan:
devices = ( {'name': 'charol', 'addr': 'DE:AD:BE:EF:00:01', 'values': [] }, {'name': 'oliver', 'addr': 'DE:AD:BE:EF:00:02': [] })
This following class method defines what happens when each device is discovered:
class ScanReport2SD(btle.DefaultDelegate): def handleDiscovery(self, dev, isNewDev, isNewData):
Then comes the report() method. This is where all the reporting happens. If the array is empty (i.e. we didn’t discover the device) we send 0 to Server Density:
if list == []: data[name] = 0
If we receive actual values, then we calculate the 85th percentile in order to filter out atypical values. Based on our experiments with Bluetooth dongles and Chipolo devices, we determined that a RSSI = -60 was a good enough threshold in determining whether the cat was “very close” or not.
else: # percentile85 has given good results to filter out cat/signal movement percentile = numpy.percentile(numpy.array(list), 85) # we reset values d['values'] = [] # -60 is the rssi thershold we consider in place if percentile > -60: data[name] = 1 if percentile >= -60: data[name] = 2
We then write the results of those calculations on a JSON file for the Server Density agent to pick up and forward to our service:
f = open('/tmp/CatSpy.json', 'w') f.write(json.dumps(data)) f.close()
Finally, here is the main loop. All it does is scan for 50 seconds (using the bluepy library) before invoking the report() method:
if __name__ == "__main__": scanner = btle.Scanner().withDelegate(ScanReport2SD()) print ("Scanning for devices...") while True: scanner.scan(50) report()
As you can see, all it takes is a few lines of code. Obviously this is a mere proof of concept, not a production ready implementation.
Let’s now download the script and configure the devices’ MAC addresses.
$ cd ~/bluepy/test $ wget https://raw.githubusercontent.com/bencer/scripts/master/catspy/gatos.py $ vi gatos.py
And run it inside a byobu or with nohup, that way it keeps running even when we disconnect (we were too lazy to implement a proper daemon):
$ sudo python gatos.py
Last bit would be to configure the Server Density plugin that forwards the metrics dumped into the JSON file to our monitoring dashboard:
$ sudo mkdir -p /usr/local/share/sd-plugins $ wget https://raw.githubusercontent.com/bencer/sd-agent-plugins/json/JSON/JSON.py && sudo mv JSON.py /usr/local/share/sd-plugins/ $ sudo vi /etc/sd-agent/config.cfg: plugin_directory: /usr/local/share/sd-plugins/ $ sudo vi /etc/sd-agent/plugins.cfg [JSON] path: '/tmp'
The Results
![]() |
![]() |
Charol is our fatty happy grey tabby. He is bossy, especially with our dogs. He loves sitting atop his tree and “monitor” everything and everyone. | Oli is a happy ginger, playful and loving. He is a purring machine and always has something important to say. |
SAFETY NOTICE: If you run this project (or any exercise involving pets) please do not use strings or laces to attach anything on your pet. To avoid potential injury, make sure you use safe, purpose-built cat collars and follow these safety tips.
The following graphs illustrate Oli’s and Charol’s activity over the last 24 hours.
Most activity appears to happen around meal times (which is to be expected). We noticed Charol made a few more visits to the food tower (no wonder he weighs 7kg).
We knew our cats didn’t drink much water, and the water fountain readings confirmed that. Charol visited the fountain a bit more than Oli. That’s probably because Charol eats more dry food than Oli. The water fountain is further out in a corner, that explains the occasional 0 readings, when the device was unreachable.
As the litterbox readings confirm, our cats don’t use the toilet that often. Given that the litterbox is in the toilet upstairs, we have a few 0 readings as well.
Summary
Setting up this exercise took us a few days. It doesn’t take an enormous amount of time or effort, and it certainly doesn’t cost a lot, to monitor things beyond servers.
What about you? Have you monitored anything worth sharing? Do you have any ideas for things (animate or inanimate) you could monitor in the future? Let us know in the comments.
The post How to Monitor Cats appeared first on Server Density Blog.