Ruby on Rails

Worfcam: A Basic Rails App to Track Your Pets

I would like to introduce my side project, Worfcam, which I’ve been building for more than six months. Worfcam is a way to see what your pets are doing while you’re away. You can visit the site at

Worf resting: An image captured with Worfcam.
Worfcam started when my fiancé and I went on a trip and left our cat, Worf, home alone for a few nights.  Don’t worry, someone stopped by each day. We wanted to be able to check on him any time we wanted. The first few versions were extremely basic: I pointed a webcam at my computer chair, where Worf likes to sit. The next one was a cron job on a Raspberry Pi, which took a photo and served it via a local nginx server. I left it at this for a few months.

The current version of Worfcam started when a hackathon was announced and I started planning what we have today. The hackathon was cancelled, but Worfcam wasn’t.

Worfcam is built from two parts, server and nodes. Each node currently is a Raspberry Pi that has the camera module. Each node takes a photo once a minute and send the photos to the server. Users can sign in and see the current photo, along with the last two days of photos.

Worf, Kurn and Jadzia resting: Image captured with Worfcam.
There are six active nodes right now, which have processed over 600,000 photos. All of the photos in this post were taken by Worfcam.

Server side

The server side of Worfcam is a basic Rails app with Sidekiq for background processing. I’m using Bootstrap with a material design theme over top of it. Photos are stored in Google Cloud Storage. I’ve placed a cache in front of Google Cloud Storage for quick reads.

The fun part of the server side is how it is hosted. Everything is hosted inside the Google Container Engine with Kubernetes. I have nginx, PostgreSQL, Redis, two Rails processes, and a sidekiq process at the moment. Here is output from my kubectl get pods:

$ kubectl get pods

NAME               READY     STATUS    RESTARTS   AGE

nginx-x2vwd        1/1       Running   0          22d

postgres-kze9e     1/1       Running   0          21d

rails-app-8kcoa    1/1       Running   0          3d

rails-app-f4c7t    1/1       Running   0          3d

redis-sx4tz        1/1       Running   0          21d

sidekiq-zijvp      1/1       Running   0          3d

I have a build script that deploys to kubernetes and does a rolling restart. Everything has a replication controller to make sure that if the pod dies, a new one will be put in its place.


Each node consists of a Raspberry Pi, the camera module, a wifi adapter, an 8GB sd card, and a power supply. I have a gist that includes links to all of the parts. One of the nice things about the Raspberry Pi is that any of the Pi’s work except for the Zero, which won’t work because it doesn’t have a camera port. Once they are more broadly available I want to investigate using USB cameras.

I use Arch Linux as my OS, specifically the ARM version. I prefer Arch because it is very minimal and uses systemd. With systemd I can easily start the Worfcam process and make sure it stays alive.

Kurn seen in the window: An image captured with Worfcam
The software that takes photos is written in Python and uses picamera. Other Python packages I use are requests and apscheduler. Requests is an HTTP client that has a simple interface, and apscheduler is a job scheduler that can run jobs similar to cron.

The node software is very simple, with most of it related to updating itself when I post a newer version. I based this on Capistrano’s folder structure.

Try out Worfcam

Worfcam is still in its early stages, but I am getting close to expanding beyond friends and family. If you are interested in being an alpha tester, please let me know and register your interest on!

You've successfully subscribed to SmartLogic Blog
Great! Next, complete checkout for full access to SmartLogic Blog
Welcome back! You've successfully signed in.
Unable to sign you in. Please try again.
Success! Your account is fully activated, you now have access to all content.
Error! Stripe checkout failed.
Success! Your billing info is updated.
Error! Billing info update failed.