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 }









Reply