DIY – Smart Home: Part 1

I’ll be doing a series on smartifying your house. What better way to start this series that with the most important device in man’s modern history, the toilet? Then we’ll take a look generally at the bathroom and see what else we can wire up in order to provide ourselves with some interesting albeit funny data. After conquering the bathroom, we’ll move on to something a little more complex, the kitchen. Finally, we’ll cap the series off with something that everyone with a smartphone should be able to do…check the garage door! We’ll also get into a little iphone development and program an app that will allow us to close the garage door remotely! But first, the toilet…

The idea…

Back when twitter was still learning to fly, I thought it would be funny to make a toilet tweet. I also thought it would be interesting to know how many times a day I use the toilet and how many gallons of water I was using. So I build a simple device to keep track. However, it wasn’t very useful or reliable and with Twitter’s adoption of oAuth Authentication, my feed went the way of the buffalo. Let’s revisit the idea and make some modest improvements in order to get some more information about our bathroom habits and have some fun tweeting about it in the process.

Getting started…

First off, we’ll need to know the basics. We’ll be using an ultrasonic range finder hooked up to an ethernet enabled arduino. We’ll also do some serverside programming in order to monitor out toilet and ultimately tweet every time we use our toilet. The rangefinder will act as a detection sensor and also provide us some useful information about the person’s position when they use the toilet, without the privacy invasion of a camera.

Materials…

  • ultrasonic rangefinder from parallax (available at radio shack)
  • Arduino
  • Ethernet shield
  • copper wire
  • led
  • bread board
  • server hosting / LAMP enabled

Wiring…

The first step is to hook everything up and begin running a test program to make sure everything is set up properly. We’ll start by attaching the range finder to our toilet:

Next, we’ll run the wires from the range finder to the arduino/ethernet module hooked up wherever it’s conventient:

Finally, we’ll run power to the arduino and upload the example program for range finders provided with the arduino software package:

Once we’re able to output some serial data that shows we are taking accurate measurements, it’s time to modify code…

Coding…

We need to modify this example program a bit to include the ethernet shield and to notify an address on our server as soon as we’ve tripped our sensor. We’ll start by importing some libraries and getting our setup function working:

#include 
#include 

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = {  0x99, 0xA9, 0xDA, 0x00, 0x99, 0x99 };
byte ip[] = { 192,168,1,177 };
//byte server[] = { 173,194,33,104 }; // Google
byte server[] = { 11,222,33,44 }; // your server IP address

// Initialize the Ethernet client library
// with the IP address and port of the server 
// that you want to connect to (port 80 is default for HTTP):
Client client(server, 80);

long inches = 11;

void setup() {

// sonar pins
//pinMode(13, OUTPUT); // blue
//pinMode(12, OUTPUT); // green

// reset pin
pinMode(9, OUTPUT); // resest
pinMode(7, OUTPUT); // ping pin

// start the Ethernet connection:
  Ethernet.begin(mac, ip);
  // start the serial library:
  Serial.begin(9600);
  
  //digitalWrite(9, LOW);

}

void loop()
{
  Serial.println("pinging...");
  // send a sonar ping
  pingSonar();
}

Next we’ll add some custom functions:

void pingSonar() {
  // establish variables for duration of the ping, 
  // and the distance result in inches and centimeters:
  long duration, inches, cm;
  
  const int pingPin = 7;

  // The PING))) is triggered by a HIGH pulse of 2 or more microseconds.
  // Give a short LOW pulse beforehand to ensure a clean HIGH pulse:
  pinMode(pingPin, OUTPUT);
  digitalWrite(pingPin, LOW);
  delayMicroseconds(2);
  digitalWrite(pingPin, HIGH);
  delayMicroseconds(5);
  digitalWrite(pingPin, LOW);

  // The same pin is used to read the signal from the PING))): a HIGH
  // pulse whose duration is the time (in microseconds) from the sending
  // of the ping to the reception of its echo off of an object.
  pinMode(pingPin, INPUT);
  duration = pulseIn(pingPin, HIGH);

  // convert the time into a distance
  inches = microsecondsToInches(duration);
  
  String inchesStr = inches;
  
  Serial.println("ping returned: "+ inchesStr +"...");
  
  // show LED colors
  if(inches < 30 ) {
    // then the person is sitting
     callServer(inchesStr, "sonar");
     responseLoop();
     //delay(120000);
  } else {
    // do nothing...
  }
  //cm = microsecondsToCentimeters(duration);
  
  //Serial.print(inches);
  //Serial.print("in, ");
  //Serial.print(cm);
  //Serial.print("cm");
  Serial.println();
  delay(3000);
}

void responseLoop () {
  for(int i = 0; i < 1200; i++) {
       // delay the timer
                        // BEGIN IF STATEMENTS FROM LOOP
                          
                        // if there are incoming bytes available 
                        // from the server, read them and print them:
                        if (client.available()) {
                          //while(client.available()) {
                            char c = client.read();
                            Serial.print(c);
                          //}
                          //delay(120000);
                        }
     delay(1);
        
   } // end for loop
                      
    // if the server's disconnected, stop the client:
    if (!client.connected()) {
      Serial.println();
      Serial.println("disconnecting.");
      client.stop();
      //i = 120000;
      //digitalWrite(9, LOW);
      //delay(120000);
      // do nothing forevermore:
      
      delay(560000);
       
    }
      // END IF STATEMENTS FROM LOOP
        
}

void callServer (String inchesStr, String type) {
  // reset pin nine
  /*digitalWrite(9, HIGH);
  delay(100);
  digitalWrite(9, LOW);
  delay(100);
  digitalWrite(9, HIGH);*/
  // define some vars
  
  String str = "http://example.com/path_to/process.php?measurement="+ inchesStr +"&type=" + type;
  
   
  // give the Ethernet shield a second to initialize:
  delay(1000);
  Serial.println("connecting...");

  // if you get a connection, report back via serial:
  if (client.connect()) {
    Serial.println("connected");
    Serial.println("Calling: "+ str);
    
    // Make a HTTP request:
    client.println("GET "+ str +" HTTP/1.0");
    client.println();
    
    
  } 
  else {
    // kf you didn't get a connection to the server:
    Serial.println("connection failed:" + str);
    //digitalWrite(9, LOW);
    //callServer(inchesStr, type);
    //delay(120000);
  } 
  
  
}

long microsecondsToInches(long microseconds)
{
  // According to Parallax's datasheet for the PING))), there are
  // 73.746 microseconds per inch (i.e. sound travels at 1130 feet per
  // second).  This gives the distance travelled by the ping, outbound
  // and return, so we divide by 2 to get the distance of the obstacle.
  // See: http://www.parallax.com/dl/docs/prod/acc/28015-PING-v1.3.pdf
  return microseconds / 74 / 2;
}

long microsecondsToCentimeters(long microseconds)
{
  // The speed of sound is 340 m/s or 29 microseconds per centimeter.
  // The ping travels out and back, so to find the distance of the
  // object we take half of the distance travelled.
  return microseconds / 29 / 2;
}

After we're done with our arduino, we'll need to create a script that will collect information about our toilet usages and also notify twitter when we're using it. We'll also need to set up a database where we can store this information. Let's create the database now:

CREATE TABLE IF NOT EXISTS `readings` (
  `id` int(11) NOT NULL auto_increment,
  `measurement` varchar(255) NOT NULL,
  `sensor_type` varchar(255) NOT NULL,
  `time` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=96 ;

Now let's create a script that will search for a $_GET request and update the database and twitter when it receives the proper information:

<?php
/*
	Written By: Mike Newell
	mike@iwearshorts.com
	http://iwearshorts.com/
	
	No license - Feel free to copy!
*/
if(isset($_GET['measurement'])) {
	require_once('lib/db.php');
	require_once('lib/TwitPic.php');
	$inches = intval($_GET['measurement']);
	
	if($inches < 16) {
		$activity = "sitting";
		$searchStr = "sitting+on+toilet";
	} else {
		$activity = "standing";
		$searchStr = "standing+at+urinal";
	}
	
    /*
    	GET CONTENTS OF TOILETS DIRECTORY
    */
    if ($handle = opendir('./toilets')) {
	    echo "Directory handle: $handlen";
	    echo "Files:n";
		$images = array();
	    /* This is the correct way to loop over the directory. */
	    while (false !== ($file = readdir($handle))) {
	        //echo "$filen";
	        $images[] = $file;
	    }
	
	    closedir($handle);
	}
	
	// select a random image
	$count = count($images);
	
	for($i = 0; $i < $count; $i++) {
		$imageNum = mt_rand(1, $count);
		
		$selectedImageSrc = $images[$imageNum];
	}
	
	echo 'toilets/'.$selectedImageSrc;
    
    
    /*
    NEW TWITPIC API
	 * All of this info is needed only for API calls that
	 * require authentication. However, if the API call doesn't
	 * require authentication and you provide the information anyways,
	 * it won't make a difference.
	 */
	$api_key = ""; // your TwitPic API key (http://dev.twitpic.com/apps)
	$consumer_key = ""; // your Twitter application consumer key
	$consumer_secret = ""; // your Twitter application consumer secret
	$oauth_token = ""; // the user's OAuth token (retrieved after they log into Twitter and auth there)
	$oauth_secret = ""; // the user's OAuth secret (also from Twitter login)
	
	/*
	 * The TwitPic() constructor can be left blank if only
	 * doing non-auth'd API calls
	 */
	$twitpic = new TwitPic($api_key, $consumer_key, $consumer_secret, $oauth_token, $oauth_secret);
	
	try {
		/*
	  * Uploads an image to TwitPic AND posts a tweet
	  * to Twitter.
	  *
	  * NOTE: this still uses v2 of the TwitPic API. This means that the code makes 2 separate
	  * requests: one to TwitPic for the image, and one to Twitter for the tweet. Because of this,
	  * understand this call may take a bit longer than simply uploading the image.
	  */
	  $resp = $twitpic->uploadAndPost(array('media'=>'toilets/'.$selectedImageSrc, 'message'=>"Someone is ".$activity." at Mike's toilet right now!"));
	  print_r($resp);
	} catch(TwitPicAPIException $e) {
		echo $e->getMessage();
	}
    
    
	//$connection->post('statuses/update', array('status' => "Guess the activity! Someone is using Mike's toilet "));
	// set the values to variables
	$measurement = $_GET['measurement'];
	$type = $_GET['type'];
	// store the value in a database
	$db = new DBconnect("localhost", "user_name", "password", "database_name");
	$result = $db->query("INSERT INTO readings (measurement, sensor_type) VALUES ('$measurement', '$type')");
	if($result) {
		echo "successful.";
	} else {
		echo "unsuccessful input.";
	}
} else {
	echo "get request with measurement not present";
}
?>

We also need a twitter class that will handle pictures. I chose to use twitpic, you can download the library here.

We'll also need a small database class to manage input and output from our database. Download the demo at the bottom of the page to get it.

Once we've properly initialized everything, it's just a matter of getting the proper api keys from twit pic and twitter. Make sure to enter your database connection information into the new class, modify the arduino code with your server's specific IP address and path to the process.php file wherever you decide to store it on your server. You'll also need to make sure and have HTTP_OAuth and HTTP_Request2 installed on your server.

Download the demo!

9 thoughts on “DIY – Smart Home: Part 1

  1. Hello,

    In order to be fully Web-2.0 compliant, you should also post some pictures of your excrements on Facebook or Flickr.

  2. Hey dude, I just wondered whether you outsource your link building or whether you do it yourself? I used to do my own but I started outsourcing it and I’ve had some excellent results and it only costs me a fraction of what I used to spend doing it myself (if you consider how much time I spent doing it etc.). I use these guys link building plans: http://LinkBlasts.com

Leave a Reply

Your email address will not be published. Required fields are marked *