FridgeHound - The Smart Tupperware
Authors
Orlando G. Rodriguez
Pedro Henrique R. Pinto
Description
Have you ever forgot something on the fridge and by time you opened it the food had gone bad? Or maybe you opened a tupperware and wasn't too sure if the food was still good? Well, you are not alone. The average american household wastes around 25% of the food they purchase. This was the main reason why we decide to create FridgeHound. FridgeHound is a Smart Tupperware that uses the mq-135 gas sensor to track your food. With an easy to use interface you can store different type of foods and the sensor will estimate how much time you have left. We also added a thermometer so you can keep track of your fridge's temperature. The best part is that you can access all this information from a web application anywhere you go. The gas sensor and thermometer send information via serial usb to a Raspberry Pi 2, which sends that information to our web application's database. This way, you always have the most up to date information anywhere you go.
Hardware Components
mbed![]() | Gas Sensor (MQ-135)![]() | Temperature Sensor (TMP-36)![]() |
uLCD-144-G2![]() | Pushbuttons![]() | Raspberry Pi 2 ![]() |
Pin-out Connections
Gas Sensor (MQ-135)
| mBed | SD |
|---|---|
| p15 | out |
| GND | GND |
| Vout | Vcc |
| VU | 5v |
Temperature sensor (TMP-36)
| mBed | MQ-135 |
|---|---|
| Gnd | Gnd |
| Vout | 3.3V |
| P18 | Out |
uLCD Connections
| mBed | uLCD |
|---|---|
| Vu | 5V |
| Gnd | Gnd |
| Tx=p9 | RX |
| Rx=p10 | TX |
| P11 | Reset |
Up Pushbutton Connections
| mBed | Up Pushbutton |
|---|---|
| P8 | P1 |
| Gnd | P2 |
Down Pushbutton Connections
| mBed | Up Pushbutton |
|---|---|
| P28 | P1 |
| Gnd | P2 |
Left Pushbutton Connections
| mBed | Up Pushbutton |
|---|---|
| P29 | P1 |
| Gnd | P2 |
Right Pushbutton Connections
| mBed | Up Pushbutton |
|---|---|
| P24 | P1 |
| Gnd | P2 |
Select Pushbutton Connections
| mBed | Up Pushbutton |
|---|---|
| P20 | P1 |
| Gnd | P2 |
Homepage Pushbutton Connections
| mBed | Up Pushbutton |
|---|---|
| P19 | P1 |
| Gnd | P2 |
USB Serial Connection
| mBed | Raspberry Pi |
|---|---|
| USB mini Out | USB 2.0 In |
Demo
Web Application:
mbed Application:
Mbed Program
main.cpp
#include "mbed.h"
#include "uLCD_4DGL.h"
uLCD_4DGL uLCD(p9, p10, p11); // serial tx, serial rx, reset pin;
AnalogIn sensor(p15);
DigitalIn pbUp(p8);
DigitalIn pbLeft(p29);
DigitalIn pbDown(p28);
DigitalIn pbRight(p24);
DigitalIn pbSelect(p20);
DigitalIn pbBackToMenu(p19);
AnalogIn LM61(p18);
Serial pc(USBTX, USBRX);
int main()
{
pbUp.mode(PullUp);
pbLeft.mode(PullUp);
pbDown.mode(PullUp);
pbRight.mode(PullUp);
pbSelect.mode(PullUp);
pbBackToMenu.mode(PullUp);
int phase = 0;
int option = 1;
bool image_change = true;
int daysRemaining = -1;
int timer = 0;
bool foodStored = false;
float tempC, tempF;
float sensorData = 0.0;
int foodType = 9;
int counter = 0;
uLCD.media_init();
uLCD.set_sector_address(0x003B, 0x8000);
uLCD.display_image(0, 0);
wait(3.0);
phase = 1;
while (1) {
sensorData = sensor.read();
//Logic that reduces the timer variable every second.
switch (phase) {
//Phase 1: Main Menu
case 1:
switch (option) {
case 0: //Reset food option selected
if(image_change == true){
uLCD.media_init();
uLCD.set_sector_address(0x003B, 0x81C7);
uLCD.display_image(0, 0);
image_change = false;
}
//Load main menu select reset food
if (pbSelect == 0) { //Selected this option
phase = 2;
image_change = true;
}
break;
case 1: //Add food option selected
//Load main menu add food
if(image_change == true){
uLCD.media_init();
uLCD.set_sector_address(0x003B, 0x8208);
uLCD.display_image(0, 0);
image_change = false;
}
if (pbSelect == 0) {
phase = 3; //Move to food addition phase
option = 0;
image_change = true;
}
break;
case 2: //Check status option selected
//Load main menu check status
if(image_change == true){
uLCD.media_init();
uLCD.set_sector_address(0x003B, 0x8186);
uLCD.display_image(0, 0);
image_change = false;
}
if (pbSelect == 0) {
phase = 5;
image_change = true;
}
}
if (pbRight == 0) { //press right button
option += 1;
option = option % 3;
image_change = true;
}
if (pbLeft == 0) { //press left button
option -= 1;
image_change = true;
if (option < 0) {
option = 2;
}
}
//More things happen in the main menu
break;
//Phase 2: Food Reset Stage
case 2:
//Load "food was reset" image
uLCD.media_init();
uLCD.set_sector_address(0x003B, 0x89A6);
uLCD.display_image(0, 0);
wait(3.0);
phase = 1;
option = 0;
foodStored = false;
daysRemaining = -1;
foodType = 9;
break;
//Phase 3: Food Addition Stage
case 3:
switch (option) {
case 0: //Load first option
if(image_change == true){
uLCD.media_init();
uLCD.set_sector_address(0x003B, 0x8820);
uLCD.display_image(0, 0);
image_change = false;
}
if (pbSelect == 0) {
option = 0; //Here we will put the number of days expected for this type of food
phase = 4;
image_change = true;
foodType = 0;
}
break;
case 1: //Load second option
if(image_change == true){
uLCD.media_init();
uLCD.set_sector_address(0x003B, 0x875D);
uLCD.display_image(0, 0);
image_change = false;
}
if (pbSelect == 0) {
option = 0; //Here we will put the number of days expected for this type of food
phase = 4;
image_change = true;
foodType = 1;
}
break;
case 2: //Load third option
if(image_change == true){
uLCD.media_init();
uLCD.set_sector_address(0x003B, 0x8965);
uLCD.display_image(0, 0);
image_change = false;
}
if (pbSelect == 0) {
option = 0; //Here we will put the number of days expected for this type of food
phase = 4;
image_change = true;
foodType = 2;
}
break;
case 3: //Load fourth option
if(image_change == true){
uLCD.media_init();
uLCD.set_sector_address(0x003B, 0x8924);
uLCD.display_image(0, 0);
image_change = false;
}
if (pbSelect == 0) {
option = 0; //Here we will put the number of days expected for this type of food
phase = 4;
image_change = true;
foodType = 3;
}
break;
case 4: //Load fifth option
if(image_change == true){
uLCD.media_init();
uLCD.set_sector_address(0x003B, 0x879E);
uLCD.display_image(0, 0);
image_change = true;
}
if (pbSelect == 0) {
option = 0; //Here we will put the number of days expected for this type of food
phase = 4;
image_change = true;
foodType = 4;
}
break;
case 5: //Load sixth option
if(image_change == true){
uLCD.media_init();
uLCD.set_sector_address(0x003B, 0x8861);
uLCD.display_image(0, 0);
image_change = false;
}
if (pbSelect == 0) {
option = 0; //Here we will put the number of days expected for this type of food
phase = 4;
image_change = true;
foodType = 5;
}
break;
case 6: //Load sixth option
if(image_change == true){
uLCD.media_init();
uLCD.set_sector_address(0x003B, 0x88A2);
uLCD.display_image(0, 0);
image_change = false;
}
if (pbSelect == 0) {
option = 0; //Here we will put the number of days expected for this type of food
phase = 4;
image_change = true;
foodType = 6;
}
break;
case 7: //Load sixth option
if(image_change == true){
uLCD.media_init();
uLCD.set_sector_address(0x003B, 0x88E3);
uLCD.display_image(0, 0);
image_change = false;
}
if (pbSelect == 0) {
option = 0; //Here we will put the number of days expected for this type of food
phase = 4;
image_change = true;
foodType = 7;
}
break;
case 8: //Load sixth option
if(image_change == true){
uLCD.media_init();
uLCD.set_sector_address(0x003B, 0x87DF);
uLCD.display_image(0, 0);
image_change = false;
}
if (pbSelect == 0) {
option = 0; //Here we will put the number of days expected for this type of food
phase = 4;
image_change = true;
foodType = 8;
}
break;
}
if (pbDown == 0) {
option++;
option = option % 9;
image_change = true;
}
if (pbUp == 0) {
image_change = true;
if (option == 0) {
option = 8;
}
else {
option--;
}
}
if (pbSelect == 0) {
phase = 4;
option = 0;
image_change = true;
}
break;
//Phase 4: Food Timing Section
case 4:
switch (option) {
case 0: //Load first option
if(image_change == true){
uLCD.media_init();
uLCD.set_sector_address(0x003B, 0x8249);
uLCD.display_image(0, 0);
image_change = false;
}
break;
case 1: //Load second option
if(image_change == true){
uLCD.media_init();
uLCD.set_sector_address(0x003B, 0x828A);
uLCD.display_image(0, 0);
image_change = false;
}
break;
case 2: //Load third option
if(image_change == true){
uLCD.media_init();
uLCD.set_sector_address(0x003B, 0x82CB);
uLCD.display_image(0, 0);
image_change = false;
}
break;
case 3: //Load fourth option
if(image_change == true){
uLCD.media_init();
uLCD.set_sector_address(0x003B, 0x830C);
uLCD.display_image(0, 0);
image_change = false;
}
break;
case 4: //Load fifth option
if(image_change == true){
uLCD.media_init();
uLCD.set_sector_address(0x003B, 0x834D);
uLCD.display_image(0, 0);
image_change = false;
}
break;
case 5: //Load sixth option
if(image_change == true){
uLCD.media_init();
uLCD.set_sector_address(0x003B, 0x838E);
uLCD.display_image(0, 0);
image_change = false;
}
break;
case 6: //Load seventh option
if(image_change == true){
uLCD.media_init();
uLCD.set_sector_address(0x003B, 0x83CF);
uLCD.display_image(0, 0);
image_change = false;
}
break;
case 7: //Load eighth option
if(image_change == true){
uLCD.media_init();
uLCD.set_sector_address(0x003B, 0x8410);
uLCD.display_image(0, 0);
image_change = false;
}
break;
case 8: //Load ninth option
if(image_change == true){
uLCD.media_init();
uLCD.set_sector_address(0x003B, 0x8451);
uLCD.display_image(0, 0);
image_change = false;
}
break;
case 9: //Load tenth option
if(image_change == true){
uLCD.media_init();
uLCD.set_sector_address(0x003B, 0x8492);
uLCD.display_image(0, 0);
image_change = false;
}
break;
}
if (pbDown == 0) {
option++;
option = option % 10;
image_change = true;
}
if (pbUp == 0) {
image_change = true;
if (option == 0) {
option = 9;
}
else {
option--;
}
}
if (pbSelect == 0) { //Food was added
image_change = true;
foodStored = true;
daysRemaining = option + 1;
timer = daysRemaining * 3600 * 24;
phase = 5;
}
break;
//Phase 5: Food Status Section
case 5:
switch (daysRemaining) {
case -1: //Load no food stored
if(image_change == true){
uLCD.media_init();
uLCD.set_sector_address(0x003B, 0x8082);
uLCD.display_image(0, 0);
image_change = false;
}
break;
case 0: //Load "food is no good" image
if(image_change == true){
uLCD.media_init();
uLCD.set_sector_address(0x003B, 0x8041);
uLCD.display_image(0, 0);
image_change = false;
}
break;
case 1: //Load 1 day remaining.
if(image_change == true){
uLCD.media_init();
uLCD.set_sector_address(0x003B, 0x84D3);
uLCD.display_image(0, 0);
image_change = false;
}
break;
case 2: //Load 2 days remaining.
if(image_change == true){
uLCD.media_init();
uLCD.set_sector_address(0x003B, 0x8514);
uLCD.display_image(0, 0);
image_change = false;
}
break;
case 3: //Load 3 days remaining.
if(image_change == true){
uLCD.media_init();
uLCD.set_sector_address(0x003B, 0x8555);
uLCD.display_image(0, 0);
image_change = false;
}
break;
case 4: //Load 4 days remaining.
if(image_change == true){
uLCD.media_init();
uLCD.set_sector_address(0x003B, 0x8596);
uLCD.display_image(0, 0);
image_change = false;
}
break;
case 5: //Load 5 days remaining.
if(image_change == true){
uLCD.media_init();
uLCD.set_sector_address(0x003B, 0x85D7);
uLCD.display_image(0, 0);
image_change = false;
}
break;
case 6: //Load 6 days remaining.
if(image_change == true){
uLCD.media_init();
uLCD.set_sector_address(0x003B, 0x8618);
uLCD.display_image(0, 0);
image_change = false;
}
break;
case 7: //Load 7 days remaining.
if(image_change == true){
uLCD.media_init();
uLCD.set_sector_address(0x003B, 0x8659);
uLCD.display_image(0, 0);
image_change = false;
}
break;
case 8: //Load 8 days remaining.
if(image_change == true){
uLCD.media_init();
uLCD.set_sector_address(0x003B, 0x869A);
uLCD.display_image(0, 0);
image_change = false;
}
break;
case 9: //Load 9 days remaining.
if(image_change == true){
uLCD.media_init();
uLCD.set_sector_address(0x003B, 0x86DB);
uLCD.display_image(0, 0);
image_change = false;
}
break;
case 10: //Load 10 days remaining.
if(image_change == true){
uLCD.media_init();
uLCD.set_sector_address(0x003B, 0x871C);
uLCD.display_image(0, 0);
image_change = false;
}
break;
}
if (pbRight == 0) { //Press Right
phase = 6;
image_change = true;
}
if (pbBackToMenu == 0) { //Press Menu Button
phase = 1;
option = 1;
image_change = true;
}
break;
//Phase 6: Sensor Data
case 6:
if(daysRemaining != -1){
if (sensorData < 0.33) {
//Display food is good
if(image_change == true){
uLCD.media_init();
uLCD.set_sector_address(0x003B, 0x8145);
uLCD.display_image(0, 0);
//image_change = false;
}
}
else if (sensorData < 0.66) {
//Display food is medium
if(image_change == true){
uLCD.media_init();
uLCD.set_sector_address(0x003B, 0x80C3);
uLCD.display_image(0, 0);
//image_change = false;
}
}
else {
//Display food is bad
if(image_change == true){
uLCD.media_init();
uLCD.set_sector_address(0x003B, 0x8041);
uLCD.display_image(0, 0);
//image_change = false;
}
}
}
else{
if(image_change == true){
uLCD.media_init();
uLCD.set_sector_address(0x003B, 0x8104);
uLCD.display_image(0, 0);
//image_change = false;
}
}
if (pbLeft == 0) { //Press Left
phase = 5;
image_change = true;
}
break;
}
if (pbBackToMenu == 0) { //Press Menu Button
phase = 1;
option = 1;
image_change = true;
}
tempC = ((LM61*3.3)-0.600)*100.0;
//convert to degrees F
tempF = (9.0*tempC)/5.0 + 32.0;
tempF = tempF;
if (tempF >= 100){
tempF = 99.99;
}
counter++;
if((counter % 10000) == 0){
int days = daysRemaining;
if(days == -1){
days = 0;
}
pc.printf("%i %.2f %.2f %i",foodType,sensorData,tempF,days);
}
}
}
Back End Data Handling
fridgehound.py
import pyrebase
import serial
import time
ser = serial.Serial('/dev/ttyACM1')
# variables
data = ''
sensor = 0.0
name = 'Empty'
temperature = 0.0
days = 0
config = {
'apiKey': 'apiKey',
'authDomain': 'fridgehound.firebaseapp.com',
'databaseURL': 'https://fridgehound.firebaseio.com/',
'storageBucket': 'fridgehound.appspot.com'
}
firebase = pyrebase.initialize_app(config)
db = firebase.database()
print('firebase setup complete')
print('running main program')
while 0<1:
ser = serial.Serial('/dev/ttyACM1')
print('executed1')
time.sleep(1)
print('executed2')
data = ser.read(14)
print('executed3')
print(data)
if data == '':
print('no data was read. trying again')
continue
parsedData = data.split()
foodData = parsedData[0].decode('utf-8')
sensorData = parsedData[1].decode('utf-8')
temperatureData = parsedData[2].decode('utf-8')
daysData = parsedData[3].decode('utf-8')
print('Food: ' + foodData)
print('Sensor: ' + sensorData)
print('Temp: ' + temperatureData)
print('Days: ' + daysData)
print(parsedData)
dataToPush = {
'Food': foodData,
'Sensor': sensorData,
'Temperature': temperatureData,
'Days': daysData
}
db.child('foods').set(dataToPush)
Web Interface
fridgehound.js
var database = firebase.database();
var ref = firebase.database().ref;
var newName = 0;
var newNameStr = '';
var newLife = 0;
var newSensor = 0;
var newTemperature = 0;
var dataToPush;
var foodsList = ['Fruit', 'Vegetables', 'Beef', 'Chicken', 'Pork', 'Fish', 'Eggs', 'Dairy', 'Other', 'No Food Stored'];
function fetchData() {
console.log('attempting to fetch data...');
var newData = firebase.database().ref('/foods').once('value').then(function (snapshot) {
newName = snapshot.val().Food;
newLife = snapshot.val().Days;
newSensor = snapshot.val().Sensor;
newTemperature = snapshot.val().Temperature
newNameStr = foodsList[newName];
newLife = parseInt(newLife);
newSensor = parseFloat(newSensor);
newTemperature = parseInt(newTemperature);
dataToPush = {
Name: newNameStr,
Life: newLife,
Sensor: newSensor,
Temperature: newTemperature
}
updateData(dataToPush)
console.log('data fetched successfully')
});
}
var col_blue = "#00B5B5";
var col_yellow = "#EBBD63";
var col_red = "#F1654C";
var col_gray = "#F0F0F0";
var col_black = "#3E4651";
var col_darkgray = "#5C6D7E";
var myHoundsData = {Name: "No Food", Life: 0, Sensor: 0, Temperature: 0};
var myHoundsData2 = {Name: "Vegetables", Life: 3, Sensor: 0.0, Temperature: 0};
var width = parseInt(d3.select('body').style('width'));
var borderDim = 10;
var paddingDim = 10;
var houndPictureDim = parseInt(0.2 * width);
var xLifeScale = d3.scaleLinear()
.domain([0, 10])
.range([width * 0.2, width - houndPictureDim - 2 - (2 * borderDim) - (8 * paddingDim)]);
var xSensorScale = d3.scaleLinear()
.domain([0.0, 1.0])
.range([width * 0.2, width - houndPictureDim - 2 - (2 * borderDim) - (8 * paddingDim)]);
var LifeColor = d3.scaleLinear()
.domain([0, 3, 5, 10])
.range([col_red, col_yellow, col_blue, col_blue]);
var SensorColor = d3.scaleLinear()
.domain([0, 0.3, 0.6, 1.0])
.range([col_blue, col_blue, col_yellow, col_red]);
var myHounds = d3.select("#hounds")
.append('svg');
var defs = myHounds.append('defs')
.attr('id', 'pic1')
.attr('patternUnits', 'userSpaceOnUse')
.attr('width', houndPictureDim)
.attr('height', houndPictureDim)
.append('svg:image')
.attr('src', 'media/vegetables.png')
.attr("width", houndPictureDim)
.attr("height", houndPictureDim)
.attr("x", 0)
.attr("y", 0);
myHounds.style('class', 'hound')
.attr('width', (width - (2 * borderDim) - (2 * paddingDim)))
.style('height', houndPictureDim + 'px')
.style('margin', '10px')
.style('margin-top', -10 + 'px')
.style('border-top', 'solid')
.style('border-color', col_red)
.append('g');
var myHoundPic = myHounds.append('rect')
.style('class', 'houndPicture')
.attr('width', houndPictureDim + 'px')
.style('height', houndPictureDim + 'px')
.style('z-index', -5)
.style('fill', 'url(#pic1)');
var lifeBar = d3.select('#hounds').select('svg').append('g').append('rect')
.classed('lifeBar', true)
.attr('stroke', LifeColor(myHoundsData.Life))
.attr('fill', LifeColor(myHoundsData.Life))
.style('stroke-width', '4px')
.style('position', 'relative')
.attr('width', xLifeScale(myHoundsData.Life))
.style('transform', 'translate(' + (houndPictureDim + 2) + 'px, ' + (0.33 * houndPictureDim - 2) + 'px)')
.style('height', function() {
return 0.33 * houndPictureDim - 4;
});
var lifeBarText = d3.select("#hounds").select('svg').append('g').append('text')
.style('position', 'absolute')
.style('font-size', houndPictureDim * 0.2 + 'px')
.style('background', col_black)
.style('fill', col_gray)
.style('alignment-baseline', 'central')
.style('transform', 'translate(' + (houndPictureDim + 10) + 'px, ' + (0.5 * houndPictureDim - 4) + 'px)')
// .style('margin-top', (0.3 * houndPictureDim) + 'px')
// .style('margin-left', '' + (-1 * (width - houndPictureDim - paddingDim * 2 - borderDim * 2) + 'px'))
.text(function() {
return "Days";
});
var lifeBarTextVal = d3.select("#hounds").select('svg').append('g').append('text')
.style('position', 'absolute')
.style('font-size', houndPictureDim * 0.2 + 'px')
.style('fill', col_blue)
.style('alignment-baseline', 'central')
.style('transform', 'translate(' + (houndPictureDim + 10 + xLifeScale(myHoundsData.Life)) + 'px, ' + (0.5 * houndPictureDim - 4) + 'px)')
.text(function() {
return myHoundsData.Life;
});
var myHoundText = d3.select("#hounds").select('svg').append('g').append('text')
.style('position', 'absolute')
.style('font-size', houndPictureDim * 0.2 + 'px')
.style('fill', col_blue)
.style('alignment-baseline', 'central')
.style('transform', 'translate(' + (houndPictureDim + 10) + 'px, ' + ((0.33 / 2) * houndPictureDim - 4) + 'px)')
// .style('margin-top', (0.3 * houndPictureDim) + 'px')
// .style('margin-left', '' + (-1 * (width - houndPictureDim - paddingDim * 2 - borderDim * 2) + 'px'))
.text(function() {
return myHoundsData.Name;
});
var temperatureText = d3.select('#hounds').select('svg').append('g').append('text')
.style('position', 'absolute')
.style('font-size', houndPictureDim * 0.2 + 'px')
.style('fill', col_blue)
.style('alignment-baseline', 'central')
.attr('text-anchor', 'end')
.style('transform', 'translate(' + (width - 4 * borderDim) + 'px, ' + ((0.33 / 2) * houndPictureDim - 4) + 'px)')
.text(function() {
return myHoundsData.Temperature + 'ºF';
});
var sensorBar = d3.select('#hounds').select('svg').append('svg').append('rect')
.attr('stroke', SensorColor(myHoundsData.Sensor))
.attr('fill', SensorColor(myHoundsData.Sensor))
.style('stroke-width', '4px')
.style('position', 'relative')
.attr('width', xSensorScale(myHoundsData.Sensor))
.style('transform', 'translate(' + (houndPictureDim + 2) + 'px, ' + (0.66 * houndPictureDim + 1) + 'px)')
.style('height', function() {
return 0.33 * houndPictureDim - 4;
});
var sensorBarText = d3.select("#hounds").select('svg').append('g').append('text')
.style('position', 'absolute')
.style('font-size', houndPictureDim * 0.2 + 'px')
.style('background', col_black)
.style('fill', col_gray)
.style('alignment-baseline', 'central')
.style('transform', 'translate(' + (houndPictureDim + 10) + 'px, ' + ((0.66 + (0.33/2)) * houndPictureDim - 4) + 'px)')
// .style('margin-top', (0.3 * houndPictureDim) + 'px')
// .style('margin-left', '' + (-1 * (width - houndPictureDim - paddingDim * 2 - borderDim * 2) + 'px'))
.text(function() {
return "Sensor";
});
var sensorBarTextVal = d3.select("#hounds").select('svg').append('g').append('text')
.style('position', 'absolute')
.style('font-size', houndPictureDim * 0.2 + 'px')
.style('fill', col_blue)
.style('alignment-baseline', 'central')
.style('transform', 'translate(' + (houndPictureDim + 10 + xSensorScale(myHoundsData.Sensor)) + 'px, ' + ((0.66 + (0.33/2)) * houndPictureDim - 4) + 'px)')
.text(function() {
return parseInt(myHoundsData.Sensor * 100) + '%';
});
function updateWindow() {
width = window.innerWidth;
parseInt(d3.select('body').style('width', width));
houndPictureDim = parseInt(0.2 * width);
xLifeScale.range([0, width - houndPictureDim]);
xSensorScale.range([0, width - houndPictureDim]);
lifeBar.attr('width', xLifeScale(myHoundsData.Life))
.style('transform', 'translate(' + (houndPictureDim + 2) + 'px, ' + (0.33 * houndPictureDim - 2) + 'px)')
.style('height', function() {
return 0.33 * houndPictureDim - 4;
});
lifeBarText.style('transform', 'translate(' + (houndPictureDim + 10) + 'px, ' + (0.5 * houndPictureDim - 4) + 'px)')
.style('font-size', houndPictureDim * 0.2 + 'px');
lifeBarTextVal.style('transform', 'translate(' + (houndPictureDim + 10 + xLifeScale(myHoundsData.Life)) + 'px, ' + (0.5 * houndPictureDim - 4) + 'px)')
.style('font-size', houndPictureDim * 0.2 + 'px')
.text(function() {
console.log(myHoundsData.Life);
return myHoundsData.Life;
});
sensorBar.attr('width', xSensorScale(myHoundsData.Sensor))
.style('transform', 'translate(' + (houndPictureDim + 2) + 'px, ' + (0.66 * houndPictureDim + 1) + 'px)')
.style('height', function() {
return 0.33 * houndPictureDim - 4;
});
sensorBarText.style('transform', 'translate(' + (houndPictureDim + 10) + 'px, ' + ((0.66 + (0.33/2)) * houndPictureDim - 4) + 'px)')
.style('font-size', houndPictureDim * 0.2 + 'px');
sensorBarTextVal.style('transform', 'translate(' + (houndPictureDim + 10 + xSensorScale(myHoundsData.Sensor)) + 'px, ' + ((0.66 + (0.33/2)) * houndPictureDim - 4) + 'px)')
.style('font-size', houndPictureDim * 0.2 + 'px')
.text(function() {
return myHoundsData.Sensor;
});
temperatureText.style('transform', 'translate(' + (width - 4 * borderDim) + 'px, ' + ((0.33 / 2) * houndPictureDim - 4) + 'px)')
.style('font-size', houndPictureDim * 0.2 + 'px')
.text(function() {
return myHoundsData.Temperature + 'ºF';
});
d3.select('#hounds').select('rect')
.attr('width', houndPictureDim + 'px')
.style('height', houndPictureDim + 'px');
d3.select('#hounds').select('svg')
.attr('width', (width - (2 * borderDim) - (2 * paddingDim)))
.style('height', houndPictureDim + 'px')
myHoundText.style('transform', 'translate(' + (houndPictureDim + 10) + 'px, ' + ((0.33 / 2) * houndPictureDim - 4) + 'px)')
.style('font-size', houndPictureDim * 0.2 + 'px')
}
function animateBars(newData) {
lifeBar.transition().duration(1000).attr('width', xLifeScale(newData.Life))
.attr('stroke', LifeColor(myHoundsData.Life))
.attr('fill', LifeColor(myHoundsData.Life));
lifeBarTextVal.transition().duration(1000).style('transform', 'translate(' + (houndPictureDim + 10 + xLifeScale(newData.Life)) + 'px, ' + (0.5 * houndPictureDim - 4) + 'px)')
.text(function() {
console.log(newData.Life);
return newData.Life;
});
sensorBar.transition().duration(1000).attr('width', xSensorScale(newData.Sensor))
.attr('stroke', SensorColor(myHoundsData.Sensor))
.attr('fill', SensorColor(myHoundsData.Sensor));
sensorBarTextVal.transition().duration(1000).style('transform', 'translate(' + (houndPictureDim + 10 + xSensorScale(newData.Sensor)) + 'px, ' + ((0.66 + (0.33/2)) * houndPictureDim - 4) + 'px)')
.text(function() {
console.log(newData.Sensor);
return parseInt(newData.Sensor * 100) + '%';
});
myHoundText.text(function() {
return newData.Name;
})
temperatureText.text(function() {
return newData.Temperature + 'ºF'
})
}
function updateData(newData) {
myHoundsData = {Name: newData.Name,
Life: newData.Life,
Sensor: newData.Sensor,
Temperature: newData.Temperature};
animateBars(newData);
}
function randomizeSensorData() {
myHoundsData.Sensor = 0.15 + (Math.random() * 0.1)
myHoundsData.Temperature = parseInt(Math.random() * 10 + 50);
console.log(myHoundsData.Temperature);
updateData(myHoundsData);
}
d3.select(window).on('resize', updateWindow);
window.setInterval(fetchData, 1000);
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>FridgeHound</title>
<script src="js/jquery.min.js"></script>
<script src="js/tether.min.js"></script>
<script src="js/bootstrap.js"></script>
<script src="https://d3js.org/d3.v4.min.js"></script>
<link rel="stylesheet" href="css/bootstrap.css">
<link rel="stylesheet" href="css/bootstrap-grid.css">
<link rel="stylesheet" href="css/bootstrap-reboot.css">
<link rel="stylesheet" href="css/fridgehound.css">
</head>
<body>
<div id="title">
<H1 class="text-left" class="">FridgeHound</H1>
</div>
<div>
<H1 class="subtitle">My Foods</H1>
<div id="hounds">
</div>
</div>
<script src="https://www.gstatic.com/firebasejs/3.9.0/firebase.js"></script>
<script src="https://www.gstatic.com/firebasejs/3.9.0/firebase-database.js"></script>
<script>
// Initialize Firebase
var config = {
apiKey: "AIzaSyAS84TYTgtx0ZPWyJ_wDyIoM1RKHzXdlng",
authDomain: "fridgehound.firebaseapp.com",
databaseURL: "https://fridgehound.firebaseio.com",
projectId: "fridgehound",
storageBucket: "fridgehound.appspot.com",
messagingSenderId: "969769836536"
};
firebase.initializeApp(config);
</script>
<script src="js/fridgehound.js"></script>
</body>
</html>
fridgehound.css
@import url('https://fonts.googleapis.com/css?family=Lato');
@import url('https://fonts.googleapis.com/css?family=Raleway:300');
@import url('https://fonts.googleapis.com/css?family=Josefin+Sans:300');
@import url('https://fonts.googleapis.com/css?family=Quicksand');
body {
font-family: 'Quicksand', sans-serif;
background: #F0F0F0;
}
#title {
font-size: 32px;
background: #F1654C;
color: #F0F0F0;
padding: 10px;
}
.subtitle {
color: #3E4651;
padding: 10px;
margin-top: 20px;
font-size: 48px;
}
Import programFridgeHound
FridgeHound is a smart tupperware that uses a gas sensor to estimates for how long your food is still good and users can access it from a web application.
Please log in to post comments.






