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.