Emotion Catcher+ Bathroom Electricity Minder

Originally I wanted to make a GSR sensor and connect data from my self. I was just going to wirewrap the sensor to the XBee and use a lithium coin battery and wear it. I tried it in many different ways but the connections were not secure.

So I had to go with the bulkiest possible(most durable) version(below):

It was pretty heavy but I spent 10 hours in it, mostly sleeping.

The data I collected was fluctuating a lot so for the sake of accuracy, aesthetics and time, I had to put this project in the back burner.

Instead I collected data from our bathroom. By using my towel spy from the previous bathroom project, I collected data that was triggered by a light sensor, indicating wether the bathroom was occupied.

I calculated how much “time=money ” we spend merely by being in the bathroom based on our ConEd Bill.

( 0.0003 cents/sec lighting a 100watts bulb). I saved the data as string on a text file and visualized it realtime:

I have used three 9V batteries and finally got a wall charger and added my arduino in the box via which I supplied the device with power cause I didn’t have another XBee USB cable.

For me this visualization was  very effective based on the reactions of my roommates. Seeing numbers directly seems to have an impact on the user.

I had many many disconnections over the course of three days.

The reasons were:

-battery died.

-someone dropped the towel.

-my computer shut down.

-my coordinator Xbee got disconnected.

-overwrote the collected data by rerunning the Processing sketch.

Things I have learned:

-Don’t rely on a computer, use an ethernet shield or a data logger via arduino to collect the data.

-Power up the device with a wall charger (have an extra XBee cable to attach the device to it!)

-Secure the device firmly so it wont get disconnected in anyway.

Here is a demo video of the process:

and Here is the code:


/* * Draws a set of thermometers for incoming XBee Sensor data * by Rob Faludi http://faludi.com + hilal koyuncu March 2011 */
import processing.serial.*; import com.rapplogic.xbee.api.ApiId;import com.rapplogic.xbee.api.PacketListener;import com.rapplogic.xbee.api.XBee;import com.rapplogic.xbee.api.XBeeResponse;import com.rapplogic.xbee.api.zigbee.ZNetRxIoSampleResponse;
String version = "1.03";String mySerialPort = "/dev/tty.usbserial-A600ezGM";
XBee xbee = new XBee();
int error=0;int secs;int mins;int hours;float cents;ArrayList thermometers = new ArrayList();
PFont font;

///to save the data//
int counter;String[] veri;
void setup() {  size(1024, 768);   smooth();   font =  loadFont("AtomicClockRadio-100.vlw");  textFont(font);
 ///to save data//  veri = new String[259200];  counter = 0;  /////////////////
 PropertyConfigurator.configure(dataPath("")+"log4j.properties");
 // Print a list in case the selected one doesn't work out  println("Available serial ports:");  println(Serial.list());  try {    // opens your serial port defined above, at 9600 baud    xbee.open(mySerialPort, 9600);  }  catch (XBeeException e) {    println("** Error opening XBee port: " + e + " **");    println("Is your XBee plugged in to your computer?");    println("Did you set your COM port in the code near line 20?");    error=1;  }}
void draw() {  background(0);
 if (error == 1) {    fill(0);    text("** Error opening XBee port: **\n"+      "Is your XBee plugged in to your computer?\n" +      "Did you set your COM port in the code near line 20?", width/3, height/2);  }
 SensorData data = new SensorData(); // create a data object  data = getData(); // put data into the data object  //data = getSimulatedData(); // uncomment this to use random data for testing
 // check that actual data came in:  if (data.value >=0 && data.address != null) {
 // check to see if a thermometer object already exists for this sensor    int i;    boolean foundIt = false;    for (i=0; i <thermometers.size(); i++) {      if ( ((Thermometer) thermometers.get(i)).address.equals(data.address) ) {        foundIt = true;        break;      }    }
 // process the data value into a Celsius temperature reading for    // LM335 with a 1/3 voltage divider    //   (value as a ratio of 1023 times max ADC voltage times     //    3 (voltage divider value) divided by 10mV per degree    //    minus zero Celsius in Kevin)    float temperatureCelsius = (data.value/1023.0*1.2*3.0*100)-273.15;    println(" temp: " + round(temperatureCelsius) + "˚C");
 // update the thermometer if it exists, otherwise create a new one    if (foundIt) {      ((Thermometer) thermometers.get(i)).temp = temperatureCelsius;    }    else if (thermometers.size() < 10) {      thermometers.add(new Thermometer(data.address,35,450,      (thermometers.size()) * 75 + 40, 20));      ((Thermometer) thermometers.get(i)).temp = temperatureCelsius;    }
 // draw the thermometers on the screen    for (int j =0; j<thermometers.size(); j++) {      ((Thermometer) thermometers.get(j)).render();    }  }} // end of draw loop

// defines the data objectclass SensorData {  int value;  String address;}

// defines the thermometer objectsclass Thermometer {  int sizeX, sizeY, posX, posY;  int maxTemp = 40; // max of scale in degrees Celsius  int minTemp = -10; // min of scale in degress Celcisu  float temp; // stores the temperature locally  String address; // stores the address locally
 Thermometer(String _address, int _sizeX, int _sizeY,   int _posX, int _posY) { // initialize thermometer object    address = _address;    sizeX = _sizeX;    sizeY = _sizeY;    posX = _posX;    posY = _posY;  }////////////////////////////the section I wrote////////////////////////////////  void render() { // draw bulb       float displayTemp = round( temp);    if (temp > maxTemp) {      displayTemp = maxTemp + 1;    }    if ((int)temp < minTemp) {      displayTemp = minTemp;    }    // convert data    float light = ( 1 - ( (displayTemp-minTemp) / (maxTemp-minTemp) ));    //////////////////light off/////////////////    if (temp>-162) {       fill(125);      stroke(1);      ellipse(width/2,height/3+130,60,60);      ellipse(width/2,height/3+110,80,60);
 stroke(1);      fill(150);      ellipse(width/2,height/3+80,120,80);      noStroke();      ellipse(width/2,height/3,200,200);    }     else {//////////////////light on/////////////////      fill(125);      stroke(1);      ellipse(width/2,height/2+30,60,60);      ellipse(width/2,height/2+10,80,60);
 stroke(1);      fill(255,255,0);      ellipse(width/2,height/2-20,120,80);      noStroke();      ellipse(width/2,height/2-100,200,200);      secs+=1;      cents+=0.0003;    }           //////////convert secs to mins mins to hours/////////    if (secs==60)    {      secs=0;      mins+=1;      if (mins==60) {        hours+=1;      }    }
 textSize(50);      fill(255,0,0);//////////data display////////////////////////////      text(hours,100, height-200);       text(":",180, height-200);      text(mins,220, height-200);        text(":",300, height-200);      text(secs,340, height-200);
//////////unit display///////////////////////////      textSize(30);      text("TIME",180, height-130);      textSize(50);      fill(0,255,0);      text(cents,width-400, height-200);      textSize(30);      text("MONEY",width-330, height-130);
/////to save the data to text file///////////////      println(counter + "" + round(temp));      veri[counter] = counter + "," +  round(temp)+","+ hours +" hours"+ "," + mins+" minutes"+ ","+ secs+" secs"+","+cents;      counter++;      saveStrings("lightconsumption.txt", veri);    }  }/////////////////////////////////////////////////

 // used only if getSimulatedData is uncommented in draw loop  //  SensorData getSimulatedData() {    SensorData data = new SensorData();    int value = int(random(750,890));    String address = "00:13:A2:00:12:34:AB:C" + str( round(random(0,9)) );    data.value = value;    data.address = address;    delay(200);    return data;  }
 // queries the XBee for incoming I/O data frames   // and parses them into a data object  SensorData getData() {
 SensorData data = new SensorData();    int value = -1;      // returns an impossible value if there's an error    String address = ""; // returns a null value if there's an error
 try {			      // we wait here until a packet is received.      XBeeResponse response = xbee.getResponse();      // uncomment next line for additional debugging information      //println("Received response " + response.toString());
 // check that this frame is a valid I/O sample, then parse it as such      if (response.getApiId() == ApiId.ZNET_IO_SAMPLE_RESPONSE         && !response.isError()) {        ZNetRxIoSampleResponse ioSample =           (ZNetRxIoSampleResponse)(XBeeResponse) response;
 // get the sender's 64-bit address        int[] addressArray = ioSample.getRemoteAddress64().getAddress();        // parse the address int array into a formatted string        String[] hexAddress = new String[addressArray.length];        for (int i=0; i<addressArray.length;i++) {          // format each address byte with leading zeros:          hexAddress[i] = String.format("%02x", addressArray[i]);        }
 // join the array together with colons for readability:        String senderAddress = join(hexAddress, ":");         print("Sender address: " + senderAddress);        data.address = senderAddress;        // get the value of the first input pin        value = ioSample.getAnalog0();        print(" analog value: " + value );         data.value = value;      }      else if (!response.isError()) {        println("Got error in data frame");      }      else {        println("Got non-i/o data frame");      }    }    catch (XBeeException e) {      println("Error receiving response: " + e);    }    return data; // sends the data back to the calling function  }