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.

/media/uploads/phpinto/fridgehound.png /media/uploads/phpinto/fridgehound1.png

Hardware Components

mbed/media/uploads/phpinto/mbed.pngGas Sensor (MQ-135)/media/uploads/phpinto/mq-135.pngTemperature Sensor (TMP-36)/media/uploads/phpinto/temp.png
uLCD-144-G2/media/uploads/phpinto/ulcd.pngPushbuttons/media/uploads/phpinto/button_2.pngRaspberry Pi 2 /media/uploads/phpinto/pi_2.png

Pin-out Connections

Gas Sensor (MQ-135)

mBedSD
p15out
GNDGND
VoutVcc
VU5v

Temperature sensor (TMP-36)

mBedMQ-135
GndGnd
Vout3.3V
P18Out

uLCD Connections

mBeduLCD
Vu5V
GndGnd
Tx=p9RX
Rx=p10TX
P11Reset

Up Pushbutton Connections

mBedUp Pushbutton
P8P1
GndP2

Down Pushbutton Connections

mBedUp Pushbutton
P28P1
GndP2

Left Pushbutton Connections

mBedUp Pushbutton
P29P1
GndP2

Right Pushbutton Connections

mBedUp Pushbutton
P24P1
GndP2

Select Pushbutton Connections

mBedUp Pushbutton
P20P1
GndP2

Homepage Pushbutton Connections

mBedUp Pushbutton
P19P1
GndP2

USB Serial Connection

mBedRaspberry Pi
USB mini OutUSB 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.