Introduction: Gut Check a Tweeting and Facebooking Fridge

I have a problem, I'm trying to lose weight but I love snacking late at night. And no one knows that I even do it. That being one of my biggest hurdles, I figured why not include all my social media friends and followers in helping me. Whether they know it or not.

So I decided to hook up my fridge to the internet, with an arduino and wishield and have it post to facebook and twitter whenever I try and get myself a late night snack.

I even have a tumblr account setup to track my progress and see what else is being done with it.
http://cyancdesigngutcheck.tumblr.com

This instructable is for a lite version of it. The message is hard coded in the php file, and so is the set times it will activate. The one I have personally is also updating and running off a MySQL database for some extra tracking for opening and closing, also so I can also give the fridge a wider array of things to say if I open the fridge contained in a database as well. But what I posted will do what it says, post a message to FB and TW if you try to sneak a late night snack.

If anything doesn't seem to be working properly, let me know. I did take my version and clean it up best I could for everyone and simplify it as a starting point.




Step 1: Hardware Components

The setup of the fridge needed these parts:

Arduino Microcontroller
Wall wart to power Arduino with Center-positive 5.5x2.1mm barrel connector
Force Sensative Resistor
10K ohm resistor
WiShield
Extra Wires
Tape
1 or 2, those kinda squishy cabinet door bumber things that make them not sound like there getting slammed hard.
Breadboard (options, but very useful also a zip tie can be handy)
A web server running PHP. (You cannot trigger the facebook and twitter apps without it being on a live server (at least it wouldn't work when I tried it).

Step 2: Wiring the Arduino

A great place to start learning how to use the pressure resistor with an arduino is http://www.ladyada.net/learn/sensors/fsr.html#simple_demonstration_of_use

I started with the simple demo to start it off.
The final setup I did has one leg of the pressure resistor hooked into 5V
The other leg has the 10K resistor wire to ground for pull down and the end is plugged into Analog 0.
This reads in the value of the pressure resistor.

And since I didn't want to have to wire it directly to my computer and have wires all over my house I used a WiShield from asynclabs.
You can use any method to do the communication: wifi, wired, bluetooth. I just happened to have a WiShield around to use.
The WiShield let you still plug the pressure resistor and other wires needed to still interface with the arduino.

The picture included is for reference, just plug in things the same with the WiShield attached to the arduino.

I have an outlet in one of the cabinets near my fridge, so that turned out to be a great spot to put it. It is tucked away and out of sight. I got a 12V 500mA wall wart from radio shack and a Center-positive 5.5x2.1mm barrel connector, as advised from a quick google search. 


Step 3: Arduino Code

The code is built with "SimpleClient" as a starting point from asynclabs' code.
First I'll show you all the code and then break it down.
(I replaced all my router's important info with XXXXXXs, just fyi)

=====================================================
/*
 * A simple sketch that uses WiServer to serve a web page
 */
int fsrAnalogPin = 0; // FSR is connected to analog 0
int fsrReading; // the analog reading from the FSR resistor divider
boolean hasOpened = false;
boolean hasClosed = false;
boolean isOpen = false;

#include <WiServer.h>

#define WIRELESS_MODE_INFRA 1
#define WIRELESS_MODE_ADHOC 2

// Wireless configuration parameters ----------------------------------------
unsigned char local_ip[] = {192,168,X,X}; // IP address of WiShield
unsigned char gateway_ip[] = {192,168,X,X}; // router or gateway IP address
unsigned char subnet_mask[] = {255,255,255,0}; // subnet mask for the local network
const prog_char ssid[] PROGMEM = {"XXXXXXXXX"}; // max 32 bytes

unsigned char security_type = 1; // 0 - open; 1 - WEP; 2 - WPA; 3 - WPA2

// WPA/WPA2 passphrase
const prog_char security_passphrase[] PROGMEM = {"XXXXXXX"}; // max 64 characters

// WEP 128-bit keys
// sample HEX keys
prog_uchar wep_keys[] PROGMEM = { 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX };

// setup the wireless mode
// infrastructure - connect to AP
// adhoc - connect to another WiFi device
unsigned char wireless_mode = WIRELESS_MODE_INFRA;

unsigned char ssid_len;
unsigned char security_passphrase_len;
// End of wireless configuration parameters ----------------------------------------

// Function that prints data from the server
void printData(char* data, int len) {

  // Print the data returned by the server
  // Note that the data is not null-terminated, may be broken up into smaller packets, and 
  // includes the HTTP header. 
  while (len-- > 0) {
    Serial.print(*(data++));
  } 
}

uint8 ip2[] = {XXX,XXX,XXX,XXX};
// A request that gets the latest METAR weather data for LAX
GETrequest getOpened(ip2, 80, "XXXXXX.com", "/gutcheck/opened.php");

void setup() {
    // Initialize WiServer (we'll pass NULL for the page serving function since we don't need to serve web pages) 
  WiServer.init(NULL);

  // Enable Serial output and ask WiServer to generate log messages (optional)
  Serial.begin(57600);
  WiServer.enableVerboseMode(true);

  // Have the processData function called when data is returned by the server
  getOpened.setReturnFunc(printData);

}

void loop(){

  fsrReading = analogRead(fsrAnalogPin);
  Serial.print(fsrReading);
  Serial.print("\n");

  if(fsrReading > 200){
    isOpen = false;
  }else{
    isOpen = true;
  }

  if(!hasOpened && isOpen){
      hasOpened = true;
      hasClosed = false;
      Serial.print("OPENED\n");
      getOpened.submit();
  }
      else if(!hasClosed && !isOpen)
 { 
      hasClosed = true;
      hasOpened = false;
      Serial.print("CLOSED\n");
 }

WiServer.server_task();
delay(100);
}

===============================================     





Now the breakdown

=========
int fsrAnalogPin = 0; // FSR is connected to analog 0
int fsrReading; // the analog reading from the FSR resistor divider
boolean hasOpened = false;
boolean hasClosed = false;
boolean isOpen = false;
=========

fsrAnalogPin Sets the values for the arduino to read the pressure resistor, it must be connected to an Analog pin
fsrReading is for reading the value later on.
The boolean variables will be used in the loop() function to keep track of when the door is opened and closed.






=========
#include <WiServer.h>

#define WIRELESS_MODE_INFRA 1
#define WIRELESS_MODE_ADHOC 2

// Wireless configuration parameters ----------------------------------------
unsigned char local_ip[] = {192,168,X,X}; // IP address of WiShield
unsigned char gateway_ip[] = {192,168,X,X}; // router or gateway IP address
unsigned char subnet_mask[] = {255,255,255,0}; // subnet mask for the local network
const prog_char ssid[] PROGMEM = {"XXXXXXXXX"}; // max 32 bytes

unsigned char security_type = 1; // 0 - open; 1 - WEP; 2 - WPA; 3 - WPA2

// WPA/WPA2 passphrase
const prog_char security_passphrase[] PROGMEM = {"XXXXXXX"}; // max 64 characters

// WEP 128-bit keys
// sample HEX keys
prog_uchar wep_keys[] PROGMEM = { 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX };

// setup the wireless mode
// infrastructure - connect to AP
// adhoc - connect to another WiFi device
unsigned char wireless_mode = WIRELESS_MODE_INFRA;

unsigned char ssid_len;
unsigned char security_passphrase_len;
// End of wireless configuration parameters ----------------------------------------
=========


The most difficult part for me was getting it to work with my router, I have a linksys e2000 protected with WEP 64-bit and there wasn't too much instruction on how to get it to work. It was all a matter of figuring out what info went it what field.

local_ip[] is the ip address that is set to the arduino, find an ip address that isn't being used by the router and set it to that. My router is pretty good at not conflicting addresses.

gateway_ip[] is usually the IP address you use to configure your router's settings via web browser.

subnet_mask[] what is already set is pretty typical from what I've seen, but check your router's settings just in case.

ssid[] is what you called your connection, what you see when you want to access the wireless router from the list of available wireless connections with a computer or phone.

security_type is the kind of security you have on it, I use 1 - WEP
By default, the WiShield code uses 128-bit encryption. So instead of trying to alter the WiShield code, I changed my router to 128-bit encryption as well. It sounds safer anyways, lol.
There is information in the forums and wiki on how to change it.
And when editing in you're 128 bit key, you need to break the values into pairs so for example:

Your Key: 4F45EEF232...
In the arduino code: 0x4F, 0x45, 0xEE, 0xF2, 0x32,...
(You'll see what I mean if you are using a protected router)

unsigned char wireless_mode = WIRELESS_MODE_INFRA;
makes sure it connects to the access point (router) as a new device so it can access the internet.

Everything else is just setting variables for the WiShield to use.

The wiki and forums at asynclabs is a great place to look to start getting your WiShield to work.





=========
// Function that prints data from the server
void printData(char* data, int len) {

  // Print the data returned by the server
  // Note that the data is not null-terminated, may be broken up into smaller packets, and 
  // includes the HTTP header. 
  while (len-- > 0) {
    Serial.print(*(data++));
  } 
}
=========

This function writes out information to the Serial Monitor in the Arduino IDE, useful for debugging.




=========
uint8 ip2[] = {XXX,XXX,XXX,XXX};
// A request that gets the latest METAR weather data for LAX
GETrequest getOpened(ip2, 80, "XXXXXX.com", "/gutcheck/opened.php");
=========

This sets up the php files which the fridge will communicate to. The PHP file react to the Arduino communication to post to Facebook and/or Twitter. They will be detailed later.







=========
void setup() {
    // Initialize WiServer (we'll pass NULL for the page serving function since we don't need to serve web pages) 
  WiServer.init(NULL);

  // Enable Serial output and ask WiServer to generate log messages (optional)
  Serial.begin(57600);
  WiServer.enableVerboseMode(true);

  // Have the processData function called when data is returned by the server
  getOpened.setReturnFunc(printData);

}
=========

The setup() function sets all the needed variable for the resistor and WiShield communication.






=========
void loop(){

  fsrReading = analogRead(fsrAnalogPin);
  Serial.print(fsrReading);
  Serial.print("\n");

  if(fsrReading > 200){
    isOpen = false;
  }else{
    isOpen = true;
  }

  if(!hasOpened && isOpen){
      hasOpened = true;
      hasClosed = false;
      Serial.print("OPENED\n");
      getOpened.submit();
  }
 else if(!hasClosed && !isOpen)
 { 
      hasClosed = true;
      hasOpened = false;
      Serial.print("CLOSED\n");
 }

WiServer.server_task();
delay(100);
}
========

This is the loop() function which runs everything.
fsrReading = analogRead(fsrAnalogPin); gets the current value of the pressure resistor.
It then checks to see if the value is high or low enough to know if the fridge is opened or closed.
The next set of conditionals check to see if the status of the fridge has changed any since the last loop.
If it has changed, it will either send out the getOpened to the applicable PHP file.

The WiShield code will queue up page requests if you open and close the fridge quickly and repeatedly, but it isn't necessarily bulletproof. So just keep that in mind.

Also, at first, I had the fsrReading comparing to 0. But since the resistor is taped down, there was a little residual press left when the door opened. It is good to open up the serial display and see if you need to adjust this for yourself.

Step 4: PHP Code

So the Arduino will trigger opened.php. This is a good starting point, I've continued building on it recently to also track the door closings and put everything into a MySQL database. So expand upon it as you'd like.

opened.php

============

<?php

$message = "I've been opened! Someone is trying to seak a late night snack!!!";

$startTime = "22:45:00"; // 10:45 pm (set in 24 hr. based time)
$endTime = "06:00:00"; // 6:00 am

$startHr = date("H", $startTime); 
$startMin = date("i", $startTime);
$endHr = date("H", $endTime);
$endMin = date("i", $endTime);

// Comepare to see if in SAFE Zone.

date_default_timezone_set('America/New_York'); // be sure to change to your time zone, your server may exists in a different one
$timenow_hr = date('H');
$timenow_min = date('i');

$timeNum = ((int)$timenow_hr * 60 + (int)$timenow_min)*60;
$sNum = ((int)$startHr * 60 + (int)$startMin)*60;
$eNum = ((int)$endHr * 60 + (int)$endMin)*60;

$inDanger = true; // checks to see if within 'danger zone' time, assumes it is initially

if($timeNum > $eNum && $timeNum < $sNum){ // if it isn't it changes the variable
 echo "Inside SAFE Zone";
 $inDanger = false;
}

$msg = urlencode(stripslashes($message)); 

if($msg != "" && $inDanger){
 //MESSAGE TO FACEBOOK
 $ch = curl_init();
 curl_setopt($ch, CURLOPT_URL, "/gutcheck/facebook-post/examples/index.php?msg=".$msg);
 curl_setopt($ch, CURLOPT_HEADER, 0);
 curl_exec($ch);
 curl_close($ch);

 // MESSAGE TO TWITTER
 $ch = curl_init();
 curl_setopt($ch, CURLOPT_URL, "/gutcheck/tweet.php?msg=".$msg);
 curl_setopt($ch, CURLOPT_HEADER, 0);
 curl_exec($ch);
 curl_close($ch);
}

?>

============

I've put comments in the code for a little extra information. In a nutshell, it'll be opening the page. It'll check the time you set with the time zone you have specified. For supported time zones: http://php.net/manual/en/timezones.php

And the facebook and twitter code I wanted to keep separate for everyone so it isn't too much at one time.
This uses curl to trigger said pages without having to load a new page, because, the arduino can only trigger one page with one call. I tried it with includes and did not work as intended. So you will need this initiated on your server.

The curl call sends the message to the page as a GET variable for simplicity sake.

If you are not in the 'danger zone' of time this page will do nothing.

Step 5: Facebook Posting

I'm not sure how deep into describing how to do this one. there are many articles across the internet to make it happen.
For instance:

http://www.moskjis.com/other-platforms/publish-facebook-page-wall-from-your-site
or
http://blog.theunical.com/facebook-integration/5-steps-to-publish-on-a-facebook-wall-using-php/
or
http://tips4php.net/2010/12/automatic-post-to-facebook-from-php-script/


Basics are,
1. You will need to make a Facebook app. 
2. You need to get the keys, secret and access tokens
3. Get the PHP framework: https://developers.facebook.com/docs/reference/php/
4. Make the page that'll post.


And since you will be the only one access this app, you can grant yourself permanent session key which is outlines nicely here:
http://www.typeoneerror.com/articles/post/permanent-facebook-sessions-and-posting-as-a-page


But since I'm also a better learner by example anyways, here is the code I use. (with the key values xxxx'd out)
==========

<?php
require '../src/facebook.php';

// need to turn these options off otherwise
// you will get errors from the API
Facebook::$CURL_OPTS[CURLOPT_SSL_VERIFYHOST] = 0;
Facebook::$CURL_OPTS[CURLOPT_SSL_VERIFYPEER] = 0;

// Replace with your page's ID (verified username may work, but i'm not positive)
$pageId = "xxxxxxxxxxx";
// Replace with your permanent session key from the last step
$permSess = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

// create the Facebook API
$facebook = new Facebook(array(
    "appId" => "xxxxxxxxxxxxxxxxxx",
    "secret" => "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "cookie" => true,
));

// should log out your page's info.
// simply makes a call to the Graph API
// you don't need a session for this.
$page = $facebook->api("/{$pageId}");

// publish to the page
// you do need a session for this.
if($_GET['msg'] != ""){
 $rest = $facebook->api(array(
  "uid" => $pageId,
  "method" => "stream.publish",
  "access_token" => $permSess,
  "message" => "\"".stripslashes($_GET['msg'])."\"\n-- Gut Check Fridge",
 ));
}

?>

==========

Step 6: Twitter Post

This is pretty much along the same lines as the Facebook one.
Not sure how far to explain it, since there are a lot of articles out there to explain it in great detail.
You don't have to use it, or use both or anything you'd like.

Here is the page I used to wrap my head around it and set everything up:

http://tips4php.net/2010/12/twitter-oauth-the-easy-way-simple-post-to-twitter-script/

1. Setup the app at twitter
2. download the twitteroauth framework. https://github.com/abraham/twitteroauth/
3. setup your simple php page


Here is mine:
=====================

<?php
if($_GET['msg'] != ""){
// Create our twitter API object
require_once("twitteroauth/twitteroauth/twitteroauth.php");
$oauth = new TwitterOAuth('xxxxxxxxxxx', 'xxxxxxxxxxxxxxxxxx', 'xxxxxxxxxxxxxxxxxxxxxxxxxx', 'xxxxxxxxxxxxxxxxxxxxxxxxxx');
// Send an API request to verify credentials
$credentials = $oauth->get("account/verify_credentials");
// Post our new status
$oauth->post('statuses/update', array('status' => "\"".stripslashes($_GET['msg'])."\" -- Gut Check Fridge" ));
}

?>

=====================


Step 7: Warp Up

There you have it. The fridge will now alert everyone you know that you are trying to raid the fridge late at night, or other parts of the day if you change the times. Or you can change it to always alert all the time. The choice is now yours. I may have some descent future ideas for this little project.

I am happy to say that I've been running it for over two weeks and it really is stopping me from raiding the fridge at night. I really think twice because my friends are happy to give me a hard time about my late night snacking now that they know (^_^)// And I am feeling the positive effects of not eating right before bed.

...It's always watching...