Introduction: Give Your Cat Twitter Powers

Give your cat a Twitter account and have her post updates automatically whenever she sits down on her bed or when she leaves her bed. In addition, capture pictures of your cat when she's on her bed and upload those as well so you can keep tabs on her antics while you're away from home.

In this instructable, I'll walk you through the process of
  • building a cat sensor out of a simple momentary switch, foam core and foam strips
  • reading the cat sensor on your Mac or PC using Arduino and Processing
  • automatically posting status updates to Twitter when your cat takes a nap or wakes back up
  • taking pictures of your cat on the bed with a webcam and uploading the pictures to a webserver

Want to see a twittering cat in action? Follow @zooooey on Twitter.

This instructable is inspired by Tom Igoe's Networked Cat Project in the book "Making Things Talk"

Step 1: Theory / Overview

The overall plan is as follows: We'll first build a cheap "cat sensor". To read that sensor from a PC, we'll use an Arduino board running Firmata firmware. To take pictures of your cat, we'll capture still images from a web cam stream. All the logic will be handled in Processing. We'll use existing libraries to send Twitter updates whenever your cat sits down or leaves the bed. When the cat is on the bed, we'll capture still shots and upload those to a web server using FTP. We'll then add links to the pictures to the Twitter messages.

Here's the shopping/scavenging list, from most to least expensive:
  • 1 old laptop or PC with internet connection. Mac or PC will both work fine; Linux will be trickier - you're on your own there with video capture support.
  • 1 webcam
  • 1 Arduino board + USB cable
  • 1 momentary switch
  • stranded wire (I like 24AWG)
  • 1 sheet of foamcore
  • some springy sheet material (e.g. Foamies sheets)

Tools: Just the basics
  • soldering iron
  • xacto knife
  • hot glue gun

Step 2: Build a Cat Sensor

We want to detect when your cat is gets in the bed and when she leaves the bed.
The cheapest way to do so is with a momentary switch. Most switches you can pick up at an electronics supply store are much too small; we'll need to increase the surface area of the switch and make sure that the weight of the cat bed itself does not actuate the switch.

Here's a quick way to do so:

  • Solder two stranded wires onto the terminals of your momentary switch. Allow enough wire length to reach from the cat bed to wherever you plan to stash your computer.
  • Cut a strip of foamcore (12"x2" maybe), score it in the middle, then fold in half at the hinge. The upper half will be your lever. Cut a switch-sized hole in the bottom part. Hot glue the switch in, then glue a supporting piece of foamcore underneath to give more support to the switch.
  • To add some spring force to the lever that keeps it open normally, cut some short pieces of "Foamies" foam strip, or some other springy material, and glue into open end between lever and base.

Then slide the switch underneath your cat bed. The switch should not be actuated by the weight of the bed alone, but should be actuated whenever you apply light pressure with your hand in various parts of the bed.

Alternatives:
  • Tom Igoe shows how to detect a cat using Force Sensitive Resistors mounted between two plates of thin plywood in his book Making Things Talk.

Step 3: Connect Your Cat Sensor to Arduino, and Arduino to Your PC

We'll use an Arduino board to sense the state of your cat sensor. Instead of writing code for the Arduino board directly, we'll keep all of our logic on the PC in Processing. One easy way to make that possible is to load the Firmata firmware onto the Arduino board, since there is a nice Firmata-based library in Processing. You'll find StandardFirmata under Sketchbook->Examples->Library-Firmata->StandardFirmata on Arduino0015.

Once you've uploaded the firmware, it's time to put the circuit together. There really isn't much to it - we'll use an internall pull-up resistor in the chip, so all you need to do is plug the ends of the two wires you soldered onto your switch into your Arduino board: one goes to ground, another to a digital input (I'll assume #2 in the rest of the tutorial).

Alternatives:
Since all we need is a single bit of discrete input, we could also achieve this with any other USB I/O interface such as a USB Bit Whacker or even a Keyboard breakout board.

Step 4: Set Up Processing

To program the logic of your twittering cat, we'll use Processing.

To make our programming job easier, we'll use a number of different libraries inside Processing.

  • Download the Arduino library for Processing from http://www.arduino.cc/playground/Interfacing/Processing. Extract the zip file to your Processing libraries directory - on the Mac this is in ~/Documents/Processing/libraries/arduino (I had to create libraries subfolder by hand since there was no other library installed yet.) Restart Processing and check under Sketch->Import Library... You should see an Arduino entry.
  • To post twitter updates, download the twitter4j library from http://yusuke.homeip.net/twitter4j/en/index.html. Extract to some place you'll remember. We'll only need the file twitter4j-2.0.0.jar (your version may vary). Later on, we'll add that jar file to our Processing sketch through Sketch->Add file. This copies the jar file into a "code" subdirectory of your sketch. (It won't show up as a library).
  • To post images via FTP, download edftpj library from http://www.enterprisedt.com/products/edtftpj/. You'll later add the jar file lib/edtftpj.jar to your sketch. There's more documentation about using this jar in processing at http://processing.org/hacks/hacks:ftp
  • If you're on Windows, you'll need to download and install WinVDIG 1.01 (version matters!) so the Processing video capture library can grab frames from your webcam. Download from http://www.eden.net.nz/7/20071008/

Step 5: Detect Switch State in Processing

When your cat first jumps on the bed or moves around a bunch, our switch values will probably bounce between on and off for a while. To avoid firing off lots of spurious update messages, we'll "debounce" our switch by requiring that the value has stabilized for a number of iterations before we fire any events.

Here's Processing code that initializes Arduino and checks the switch state in its main loop:

import cc.arduino.*;import processing.serial.*;// Detect Arduino switch state from Processing// via Firmata, with debouncing//-----ARDUINO VARS--------------------Arduino arduino;int matPin = 2; // which input pin are we connected to?int matCounter=0; // counter for debouncing switch inputint bounceLimit=100; //debouncing limitint curMatState = Arduino.HIGH; //current switch stateint lastMatState = Arduino.HIGH; //last switch stateint lastMatEvent = Arduino.LOW; //last event we firedvoid setup() {  // ARDUINO  arduino = new Arduino(this, Arduino.list()[0]); // v2    arduino.pinMode(matPin, Arduino.INPUT); //set input pin  arduino.digitalWrite(matPin, Arduino.HIGH); //enable pull-up}void draw() {  // read current mat state  pollMatState();  // wait a bit  delay(10);}// Read current mat state with debounce timer and toggle check// calls fireMatEvent() when state of mat changed and has been stable for a whilevoid pollMatState() {  curMatState = arduino.digitalRead(matPin);     if(curMatState == lastMatState) {      //still in same state - incrase bounce counter      if(matCounter < bounceLimit) {        matCounter++;      } else if (matCounter==bounceLimit) {        //we've debounced enough and are ready to fire        if(lastMatEvent != curMatState) {          //only fire if this event is difft from last one          fireMatEvent(curMatState);          lastMatEvent = curMatState;        }        matCounter++;      } else if (matCounter > bounceLimit) {        // event already fired - do nothing      }     } else {       //restart count      matCounter=0;    }    lastMatState = curMatState;}// Fire a new mat state change eventvoid fireMatEvent(int state) {  if(state==Arduino.LOW) {    println("cat is off mat");  } else {    println("cat is on mat");  }   }

Step 6: Send a Twitter Update

Sending a Twitter update is very easy with the help of the Twitter4j library.
Here's the minimum code to post a status update from Processing. You'll have to add the twitter4j jar file that you downloaded earlier to your Processing sketch though the Sketch->Add File menu.

// Send a status update to Twitter via the twitter4j API// You have to add the twitter4j-x.x.x.jar file to your sketch via Sketch->Add FileString twitterID = "XXX"; //your twitter IDString twitterPassword = "XXX"; //your twitter passwordvoid setup(){}void draw(){  //send new tweet on mouse click  if(mousePressed) {    sendTweet("Updating my status from Processing.");  }}// Send the tweet passed in as String argumentvoid sendTweet(String msg) {    //construct a new twitter object    Twitter twitter = new Twitter(twitterID,twitterPassword);      try {      Status status = twitter.update(msg);      System.out.println("Updated the status to [" + status.getText() + "].");    } catch (Exception e) {      e.printStackTrace();    }}

To make the updates more interesting, you'll probably want a whole set of alternative status messages that you can switch between. Take into account whether your cat is on or off the bed. How long she's been there. What time of day it is. Etc...

Step 7: Capture an Image When the Cat Gets Into Bed

To get started with image capture, look at the Processing example File->Example->Libraries->Video (Capture)->GettingStartedCapture. Make sure you install the WinVDIG component mentioned in step 4 if you're on a Windows PC.

Here's a Processing example that, on Mouseclick, captures a video frame and saves it to file in your sketch's data directory.

// Capture an image from an attached webcam and save it to a unique filenameimport processing.video.*;import java.text.SimpleDateFormat;import java.util.Date;Capture cam;void setup() { size(320,240);  // use the default camera  cam = new Capture(this, 320, 240);   }void draw(){}void mousePressed() {  captureImage(makeFilename());}// Capture an image and save it under the passed in filename// in the sketch data directoryString captureImage(String filename) {    if (cam.available() == true) {      cam.read();      image(cam,0,0);      save(dataPath(filename));      println("Captured "+filename);      return filename;    } else {      println("Camera not (yet?) ready.");      return null;    }}  // Create a unique filename based on date & time// @see http://javatechniques.com/blog/dateformat-and-simpledateformat-examples/String makeFilename() {   Date now = new Date();  SimpleDateFormat format =            new SimpleDateFormat("yyyyMMdd-HHmmss");  return (format.format(now)+".jpg");}

Step 8: Upload the Image Via FTP

To upload our captured image on, we'll use FTP. This is the most straightforward solution to make the images accessible to others on the web, but it does require having access to a server that can accept FTP uploads and serve those files to web browsers.

The FTP code I use is taken verbatim from http://processing.org/hacks/hacks:ftp so I suggest you take a look at that page.

Alternatives:
  • we could also upload the picture using the TwitPic API, but would have to encode the image and generate an HTTP POST request, for which Processing unfortunately doesn't have good library support.
  • We could also post the image to Flickr, using one of the available Flickr API wrappers in Java such as flickrj. I've found Flickr authentication to be a drag though.
  • Finally, to prevent your password from being sent around in plain text, you may wish to use SFTP instead of FTP. Daniel Shiffman has a nice SFTP library for Processing.

Step 9: Putting It All Together.

Now we have all the different pieces, and just need to glue them together in one single Processing sketch - I've attached the complete processing sketch to this step.

You'll have to provide your own twitter and FTP account data to make it work. Otherwise, happy cat-twittering.