Saturday, December 29, 2012

Electric Imp Tweeting Cat Door

Objective:
  • Using the Electric Imp,  create a rig to 'tweet' whenever activity is sensed on a cat door.
  • Create a real time graph of the activity here.
For those not interested in the build details, Kelso helped with this short video of @OurCatDoor in action:
-----
We have two cats (Zena and Kelso) that were eager to get online.  When they are not helping out in the labs (example pic) they like to walk through a cat door and relax on the screened in sun porch where they can enjoy food, drink, and take a bathroom break.

Tweeting cat doors are nothing new to The Net.  However, when I saw the Electric Imp I thought it could be a different way to tackle the problem and learn a few things along the way.  Let's take you through the process.

To start you are going to need an Electric Imp and an "April" Imp Breakout Board.  Oh, and a cat or two...



The Electric Imp is a pretty cool piece of kit.  It looks like a SD Card, but it is really a Cortex-M3 processor with WiFi on board.  Damn!  An onboard mini USB connector is used only to power the device; not for data.
-----
The Electric Imp is useless until you get it established with a wireless network.  As mentioned above, the USB is not used for data.  So how do you program it?  With light from the screen of an app that is run on your iPhone or Android.  You enter your WiFi SSID (and security paswords if needed) and the app sends "flashes" to the screen that are picked up by the Imp to program it.  The process works surprisingly well.
----
The physical I/O for the project is pretty straight forward.  All that is needed is a magnetic reed switch to sense if the cat door flap has opened.  A blue LED is used as a visual clue for ON/OFF and switch detection.  After deciding how to map the Imp's GPIO for the project, the schematic is embarrassingly simple:
-----
After soldering headers to the April breakout board a connector was repurposed making the connection setup clean and simple.
-----
The real challenge is in the software and the cross platform integration (Imp to WhiskeyTangoHotel.com webserver to Sen.se to Twitter) and that process was not trivial, but I'll take you through that as well.
-----
Now that you have the Imp all wired up and connected to a WiFi network, how do you program it?  Remember again that the USB is just for power.  The Imp is programmed in Squirrel through your browser (I used Chrome) from the Electric Imp website.  To me, Squirrel has a "C" type feel to it.  You work through a screen called "The Planner" to code up your project behind "nodes".  These "nodes" can be connected with "noodles" for flow control.  Here is the Imp planner screenshot of my finished project.  Note that you can't see the source code here as it is embedded under the "blue node".  I'll show my source code below later.
-----
In The Planner above, the Imp runs the code under the BLUE box and passes output to the GREEN box.  The code in the BLUE box has the Imp doing a few basic things:  1) turn on a blue LED to let everyone know the Imp is powered and 2) monitoring a magnetic reed switch on the cat door.  If the cat door is opened the reed switch opens contact.  The Imp will 'see' the switch change and 3) blink the blue LED off to provide a visual confirmation and 4) pass the text string to be "tweeted" to the green box.

So what's in the green box?  When the green box is called a PHP script is executed on the WhiskeyTangoHotel.com webserver.  From this point, we leave the Electric Imp world and enter the Sen.se world.  
-----
Sen.se is one cool place.  Their goal is to assist in internet connectivity of personal devices.  They have widgets, tools, applications, channels and a few other things that I barely understand. One of the widgets found there helps with broadcasting to Twitter.  So, the PHP script in the green box above passes the string the cat wanted to "tweet" to the Sen.se Twitter app and the final result is achieved; a cat walking through a door unknowingly Tweeting a message to the world.  

Presto!  Even without opposable thumbs, the ability to type, speak English, read, or boot a computer our cats are online. 
-----
A few closing comments... I found the current Electric Imp user community to be pretty small. That said, the project wouldn't have come off without help from Electric Imp forums.  Most notable are "brendandawes" and "Hugo" who were my two main enablers.  Hugo is actually the CEO/Co-Founder of Electric Imp and I was pretty impressed that he is so involved.  Also,  I do wonder how the project would have gone with a near cost equivalent Raspberry PI.  I never really got comfortable with the fact that all my Electric Imp code was not stored locally.  I also wish there were more examples on the web to build a knowledge base from.   But, the Electric Imp package is crazy small and tight with low power draw so that is a huge plus.  In all I can't complain, the project works great and taught me a lot.  I don't have any experience with the Raspberry PI anyway, so any judgement will have to wait. 
-----
If you are still with us, here is some source code for your reading pleasure:
-----
Code Under the "Blue" Box Electric Imp Planner

/*
Tweeting Cat Door
Dec 2012
www.WhiskeyTangoHotel.Com

Read switch on PIN7 and GND
    Normally Open or Normally Closed can be adjusted in swEvent function
Blue LED PIN9 to V3V is ON if the code in running
    Blinks off for 0.5 secs when door switch dectected
*/

hardware.pin9.write(0); // LED ON, active LOW
local channelOutput = [ OutputPort("Ch 1", "string")]; // String var that gets sent to PHP script

//Watchdog code below send Ping to Imp server every xx secs
//I added this because the Imp was not Tweeting all switch closures and
//power up/down seems to correct it.  Assuming lost cost with Imp server?
function watchdog() {
  imp.wakeup(120,watchdog);  //xxx is seconds between pings
  server.log("WD ping");
}
watchdog();
//End of my watchdog code experiment

// function swEvent handles looking for action on the door switch
function swEvent() {    
        local d = date();  // Date info not sent to twitter.  Used only for planner debug
        local min = d["min"];
        local hour = d["hour"];
        local sec = d["sec"];
        local state = hardware.pin7.read();
        if (state == 0) {   // "1" Tweets when switch opens (for a NC swtich).  "0" Tweets when switch closes (for a NO swtich).
     
        // Select Random Msg.  Increase %xx as number of random msgs increases
            local r = math.rand()%4;   // generate random number (min val is 0.  max val is %xxx in Decimal)
   
            if (r == 3) {
                channelOutput[0].set("Random message for r = 3 here");
            }
         
            if (r == 2) {
                channelOutput[0].set("Random message for r = 2 here");
            }
         
            if (r == 1) {
                channelOutput[0].set("Random message for r = 1 here");
            }
         
            if (r == 0) {
                channelOutput[0].set("Random message for r = 0 here.");
            }
        // end Random Msg selecton
     
        // Blink the LED Off to show a door swing detected
        hardware.pin9.write(1);  // LED OFF
        imp.sleep(0.5)          // 500mS delay
        hardware.pin9.write(0);  //  LED back ON
     
        server.show("r="+r+" @ "+hour+":"+min+":"+sec);  //echo to the Imp Planner status the generated RANDOM# and time.  Used for debug.
        }   // end if state ==0 (or state ==1 depending on NO or NC switch type)
       
        imp.sleep(1.0);  // switch settle time of x.x seconds (keep greater that 0.5)    
        server.log(state);  //  echo switch state (O or 1) to planner window for debug      
}  // End function swEvent

// Configure pin 9 as an open drain output with internal pull up
// Configure pin 7 as switch
hardware.pin9.configure(DIGITAL_OUT_OD_PULLUP);
hardware.pin7.configure(DIGITAL_IN_PULLUP, swEvent);

imp.configure( "TCD w-Blink", [], channelOutput);
------
PHP Script called from Green Box in the Electric Imp Planner:
<?php
$feed_id = "sen.seAsignedXXX.XXXXXX";
$api_key = "sen.seAssignedXXX.XXXXXX";
if(isset($_POST['value'])) {
$data = array("feed_id" => $feed_id, "value" => $_POST['value']);                                                                    
$data_string = json_encode($data);                                                                                   
$ch = curl_init('http://api.sen.se/events/?sense_key='.$api_key);                                                                      
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");                                                                     
curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);                                                                  
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);                                                                      
curl_setopt($ch, CURLOPT_HTTPHEADER, array(                                                                          
    'Content-Type: application/json',                                                                                
    'Content-Length: ' . strlen($data_string))                                                                       
);                                                                                                                   
$result = curl_exec($ch);
}
?>
-----
Link back: Hack a Day
Link back: Hacked Gadgets
-----