RFID Protected Mini-Fridgs (updated)

RFID Protected mini-fridge

A while back I created a few threads leading up to this project. Now, they culminate into the project log below!

My inspiration: http://revision3.com/systm/rfid

I've wanted to do this many years for the longest time, but i had no idea that there were cheap RFID systems (i was always planning on using mag swipe cards as the cards are free from practically every hotel and the readers are cheap and use serial). The RFID system i use sells fro $50 usually, but earlier this summer, radioshack had a $10 special... that was cheap enough for me to byte!

In the systm episode they use the example of a Beer locker, but since i am not yet 21 (the legal drinking age in the US) this fridge won't be used to store beer. Doing so would be illegal and irresponsible. :wink: ::slight_smile: ;D

Status: 100% done

Apologies! Yeah, I know I should have taken more pictures along the way, but here is what I've got. I couldn't take too many of them because my hands were always full with stuff. The code I have posted (at the very end of the post) and the schematic I am using is similar to this: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1275369184/3#3

When i started, that schematic was what i planed to use... but i have never made a PCB and didn't want to spend the $ to get one made, i figured that because this project is basic enough, i could just go with a very slimmed down arduino board.

Hardware:

  1. Arduino mini board - http://www.anatools.com/anarduino-kit/ (ebay)
  2. Micro servo (ebay)
  3. Epoxy
  4. Radio shack project box, lm 7805 regulator
  5. Mini fridge - $20 craigs list
  6. Wire, misc mounting hardware

Basically, it's an RFID reader attached to an arduino attached to a servo and power supply. Scan a card, and we'll check it for validity and then open the servo or do nothing.
I've commented the code pretty well, and the Serial.println(“”); statements should clear up the rest of it. If in doubt, just ask me. Also, I am welcome to comments and critique about my coding style. I know there are faster ways to do some things, and there are some things that I really miss from Java that don't work in the arduino environment. Either way, I welcome the feedback :smiley: .

The Future:

  • solid state relay and thermistor + LCD for control of the compressor for fine tuned control over temperature.
  • web interface for locking / unlocking / viewing log of logins / admining cards / checking the status of the door (open / closed)
  • eeprom + RTC for logging the id used and the time
  • your suggestion here!

-- And here's what you've been waiting for! --

Pics!

Powering the Device

The fridge's design has an indoor light and thermostat, so 120V comes to the inside. This made it easy to tap into and add a small cellphone power supply. 120V gets turned into 5V at 800Ma and takes up almost no space. I left plenty of slack in the lines to allow for changing tensions as the door is opened and closed. I haven't done anything to secure the line to the wall as it holds its self pretty well.

The cable is naturally designed to do lots of bending, so i am not too concerned with the door's hinge wearing it out.

- CAPTION -

- CAPTION -

- CAPTION -

- CAPTION -

Locking the device

This was actually the hardest thing to design / develop. What you see here is the far more reliable and compact second revision. Basically, its a micro hobby servo from ebay epoxied to the side of a standard gate lock and i use some 14 gauge wire to tie the servo horn to the gate lock. This design has a few great advantages: The lock can move independently of the servo horn. This allows me to close and lock the door with out the servo opening. IE: if the door locks while it is open, you can still close the door and have it lock with out having to move the servo. This also allows my fail-safe to work; that transparent looking string tied to the gate lock is so 64 pound fishing line that is tied to a washer in the electronics control box. If the power is out, i can still open the fridge by taking off the panel and tugging the string. There is a second fail-safe that i did not mean to build in to the design: the pin (attached to the wall of the fridge) that the latch (attach to the door) lock on can be pulled out with enough force; it is held on my just two screws taped into thin plastic and insulating foam. I had to do this after i disabled the servo and closed the door and my intended fail-safe broke. After fixing the initial flaw with my original fail-safe, i decided to fix this unintended fail-safe by using some very strong epoxy. I do not have any exact numbers, but it should be much harder to yank the pin out now.

- CAPTION -

- CAPTION -

- CAPTION -

- CAPTION -

Making this think

FIRST AND FOREMOST! Sorry for the mess / crappy looking electronics. I am one of those people that has a minimum standard - make it work. The ends justify the means, and viola, you see my quality standards.

As i said above, i am using a cut down version of the arduino that i got off the ebay for cheap. This device is powered by the cellphone power adapter that i mentioned above; a 7805 adapter cleans up the power before i feed it to the RFID antenna, the servo and the controller.

the power lines are covered by the duct-tape, and the controller is secured to the side of the box by duct-tape, there is a bit of slack in the power line, so i've stuffed that into the box as well.. this makes it a bit more cluttered :confused:

Really, this stuff is pretty simple. I used a total of 3 data lines on the arduino. 1 drives the servo, 1 enables / disables the rfid tag, and one listens to the serial port on the rfid reader.

- CAPTION -

- I included this so you can see about how thick the door is. You can see how far the servo's wires need to travel to get into the control box. The door is filled entirely with foam, so carving room out for wires is easy. Drilling is also very easy; the only difficulty is the steel door cover. -

- CAPTION -

- CAPTION -

- CAPTION -

- CAPTION -

- The best soda ever. Period. -

Video:

http://www.youtube.com/watch?v=PGOhUQtgEHU
Code

Hey DarthTater,

I can't wait to see the code and pictures! Sounds like a very fun project :slight_smile:

retxed68

the standard 7805 based circuit; i would put it in the schematic, but i cant find a library that has it in it

I just type "regulator", search, and scroll down to "78*" expand it and voila..

Click for full size.

Now put it in your schematic! :wink:

pat

Thanks Pat! you have no idea how badly eagle needs a search function!

Or, it if it does, you have no idea how hard it is to find :slight_smile:

I am dumping the pictures from my camera now!

should start to upload and link in the next few min!

Can a mod please put this as post #2?

please note that i have FF'f and 69'd the unique bytes in my two tags.

you unique bytes would go there!

Also, this is actually a pretty small program

Binary sketch size: 6282 bytes (of a 30720 byte maximum)
/**
 * AUTHOR   : DarthTater
 * PURPOSE  : Control electromechanical lock on dorm room mini fridge
 * VERSION  : 2.8AF
 * LICENSE  : Completely open, be sure to credit me and Benjamin. Don't blame us for things this code does!
 *
 *
 * This is very loosely based on the work of Benjamin Eckel (http://www.gumbolabs.org/2009/10/17/parallax-rfid-reader-arduino/)
 * Some of his RFID handling code was used and modified to make more modular
 *
 * CIRCUIT:
 *  RFID VCC ==> ARDUINO VCC
 *  RFID ENA ==> ARDUINO 2 (SERIAL ENABLE)
 *  RFID SOT ==> ARDUINO 0 (GPIO)
 *  RFID GND ==> ARDUINO GND
 *
 *  SERVO POS ==> ARDUINO 5
 */

// INCLUDES
#include <Servo.h>               // This is used to  open the door's lock

//////////// Definitions ////////////


// RFID
#define RFID_Enable 2            // define the pin for RFID ENABLE
#define RFID_codeLength 10       // length of RFID tag (IN BYTES)
#define RFID_tagValiddate 1      // if set to 1, tag will be 'validated' by checking to makes sure we get the same UID twice
#define RFID_validateLength 200  // maximum time to wait for a second pass of the same tag
#define RFID_Pause 2000          // length of time that we set the reader to disable
#define RFID_startByte 0x0A      // this is the start of the serial string
#define RFID_stopByte 0x0D       // this is the end of the serial string

// SERVO
#define SERVO_Pin 5              // this is the servo's home!
#define SERVO_Open 155           // this is the position for open
#define SERVO_Closed  10         // this is the position for closed
#define SERVO_Delay  2500        // this is the amount of time to hold the lock open
#define SERVO_MiniDelay 10       // This is the number of miliseconds we wait before incrementing the servo's position.

// DEBUG
int ledPin = 13;

// SECURITY
boolean FirstRun;






////////////////////////////////////////////////////////////////////////////////////////////

////////// ALLOWED TAGS ////////// 
// put all tags you want to ALLOW in the arrays below \\



byte legit1[] = {
  0x31, 0x42, 0x30, 0x30, 0x38, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};


byte legit2[] = {
  0x31, 0x42, 0x30, 0x30, 0x38, 0x69, 0x69, 0x69, 0x69, 0x69};
////////////////////////////////////////////////////////////////////////////////////////////


// we will store the serial string (one byte at a time) into an array
byte tag[RFID_codeLength];       

// we will need a servo object
Servo lock;

void setup()
{ 
  // lets set up our serial for PC use  
  Serial.begin(2400);  // This is our PC connections
  Serial.println("PC Serial Should be ALIVE");
  BlinkLED(1);

  pinMode(RFID_Enable, OUTPUT);  //sets a single pin to high so we can tell the reader to activly search for tags... this will que up a red LED

  FirstRun = false;

  // blink the LED a few times to indicate startup is done.
  Serial.println("we have lift off!");
  RFID_SETUP_BLINK();
  Serial.println("SETUP and BLINKING are DONE!");

  lock.attach(SERVO_Pin);  // configure our servo pin

    BlinkLED(0);

}


void loop() { 

  Serial.println("Entering the LOOP");
  Serial.print("locking servo at position : ");
  Serial.println(SERVO_Closed);
  Serial.print("we are set to open at position : ");
  Serial.println(SERVO_Open);

  // we do this in the event of power loss.  the servo goes to 1/2 way (90 deg)
  // the if statement makes sure it is only done ONCE per power cycle. 
  // as it is now, a bad tag jumps to the top of the loop which will cause this to run
  // which will open the lock enough to forcefully pull it out!  


  if(FirstRun = true){
    for (int post = 90; SERVO_Closed <= post; post -=1)
    {
      lock.write(post);
      delay(5);
    }
    FirstRun = false;
  }

  Serial.println("SERVO IS LOCKING");

  BlinkLED(1);
  delay(500);
  BlinkLED(0);
  delay(500);
  BlinkLED(1);
  delay(500);
  BlinkLED(0);
  delay(500);
  BlinkLED(1);
  delay(500);
  BlinkLED(0);


  // Just to be sure, we are going to set the reader to ENABLE / RED
  RFID_Status(1);

  // lets open up and scan for tags

  Serial.println("checking for tags...");

  getRFIDTag();

  Serial.println("tag has been found");

  if(isTagValid){

    RFID_Status(0);     // if the code is valid, disable the reader for just a second (this also shows a green light)
    Serial.println("Reader is GREEN");

    sendCode();         // WE should send the code to the PC, if it is valid
    Serial.println("Tag is SENT - - - - - - AUTHORIZING");

    RFID_Status(1);     // go back to red for a second


    if(checkTagForAuth()){

      RFID_Status(0);  // go green

      Serial.println("Tag was good, AND IS GOOD!");

      Serial.println("Attempting to OPEN LOCK");
      Lock(0);
      BlinkLED(1);
      Serial.println("Should be open! NOW ENTERING DELAY...");
      delay(SERVO_Delay);

      Serial.println("Delay is over, now closing");
      Lock(1);
      BlinkLED(1);
      delay(200);
      BlinkLED(0);
      delay(200);
      BlinkLED(1);


    }
    else {

      Serial.println("Tag was good, but is not authed!"); 
      RFIDErrorBlink();
      BlinkLED(1);
    }


  } 
  else {

    Serial.println("sorry, NOISE"); 
    RFIDErrorBlink();  // blink the led a series of red / greens to indicate a problem
    BlinkLED(1);

  }

  delay(2000);  // We should just give everything a second or two to clear out;
  Serial.flush();    // clear the buffer for serial port.
  clearTagArr();    // clear out the array

}


/**************************************************************/
/**********************    Functions  *************************/
/**************************************************************/

//
// This is an infinite loop function, waits for available serial data, then checks it for validity, then fills the buffer if it is
// vaid.
//

void getRFIDTag() {

  // a temporary polace holder
  byte next_byte;
  while(Serial.available() <= 0) {

    // Do NOTHING while we don't have data coming in!

  }


  // When we do have data coming in, we process it below.
  // Check to see if we've got a PC instruction or not

  // fill our temporary buffer
  next_byte = Serial.read();

  // Check our buffer to see if it's valid.
  if(next_byte == RFID_startByte) {

    byte bytesread = 0;  // if we're staring with a valid character, start counting as we fill the buffer

    while(bytesread < RFID_codeLength) {
      if(Serial.available() > 0) {    // wait for the next byte

        if((next_byte = Serial.read()) == RFID_stopByte) break;  // if weve got a stop byte, then lets wrap up, else, heep filling the array.
        tag[bytesread++] = next_byte;               

        delay(1);
      }
    }                
  }    
}


//
//  This is a simple call to adjust the status (and led color) of the reader.
//
void RFID_Status(int S){
  if (S==1){
    // pin should be RED
    digitalWrite(RFID_Enable, LOW);    // tell the reader to start scanning
  }
  if (S==0){
    // let shoudl be GREEN
    digitalWrite(RFID_Enable, HIGH);    // tell the reader to stop scanning
  }

}


//
//  This is just a simple set of code to bink the led; its put here to clear up space above.
//

void RFID_SETUP_BLINK(){

  RFID_Status(1);  // RED
  delay(300);
  RFID_Status(0);  // GRN
  delay(300);
  RFID_Status(1);  // RED
  delay(300);
  RFID_Status(0);  // GRN
  delay(300);
  RFID_Status(1);  // RED
}


//
// clears the buffer array 
//

void clearTagArr() {
  for(int i=0; i<RFID_codeLength; i++) {
    tag[i] = 0; 
  }
}

//
// Sends the code to the PC
//

void sendCode() {
  Serial.print("TAG (HEX) : ");  
  for(int i=0; i<RFID_codeLength; i++) {
    Serial.print(tag[i] , HEX); 
    Serial.print("-");
  } 
  Serial.println();
}
//
// this is essentially a double check of the buffer
//

boolean isTagValid() {
  // Temp
  byte next_byte; 
  int count = 0;

  // We've already got 2 bytes in the buffer, its proably a stop byte
  while (Serial.available() < 2) {
    delay(2); // a very short wait, not too accurate and not too important

    // a REALLY simple check to see if the new count is the old;  if it's not, we clearly have garbage
    if(count++ > RFID_validateLength) return false;
  }

  Serial.read(); // read from the buffer and throw it to nothing; get rid of the stop byte

  // Is the new tag valid?  does it have a legit start bit?
  if ((next_byte = Serial.read()) == RFID_startByte) {  

    // Temp buffer (again)
    byte bytes_read = 0; 

    // reading the buffer and checking it for stop bytes and comparing them.
    while (bytes_read < RFID_codeLength) {
      if (Serial.available() > 0) { //wait for the next byte      
        if ((next_byte = Serial.read()) == RFID_stopByte) break;
        if (tag[bytes_read++] != next_byte) return false;                     
      }
    }                
  }
  return true;   
}


//
// indicate an error in reading the tag
//
void RFIDErrorBlink(){

  // blink the led to let user know there was noise on the line...
  RFID_Status(1);  // RED
  delay(200);
  RFID_Status(0);  // GREEN
  delay(200);
  RFID_Status(1);  // RED
  delay(250);
  RFID_Status(0);  // GREEN
  delay (250);
  RFID_Status(1);  // RED

}

Can a mod please make this post #3

CODE PART 2

--

boolean checkTagForAuth(){
  boolean Auth1 = true;
  boolean Auth2 = true;

  Serial.println("AuthCheck is live");

  if(legit1[5] != tag[5]){
    Serial.println("We Failed checking the FIRST unique BYTE for LEGIT KEY 1"); 
  }

  if(legit2[5] != tag[5]){
    Serial.println("We Failed checking the FIRST unique BYTE for LEGIT KEY 2"); 
  }

  if(  (legit2[5] != tag[5]) && (legit1[5] != tag[5])){
    Serial.println("this should only happen if the tag is valid but not authed!!!! - SHOULD NOT SEE THIS");
  }

  for(int i=0; i<RFID_codeLength; i++) {
    // read each bit, see if it matches.  if not, reject it and set local auth to fail!
    if(legit1[i] != tag[i]){
      Auth1 = false;
      Serial.print(" (1) Failed on byte number ");
      Serial.println(i);
      break;  // DO NOT USE CONTINUE - we want to skip checking AS SOON AS WE FIND A SINGLE INVALID BYTE!
    }

  }

  for(int i=0; i<RFID_codeLength; i++) {
    // read each bit, see if it matches.  if not, reject it and set local auth to fail!
    if(legit2[i] != tag[i]){
      Auth2 = false;
      Serial.print(" (2) Failed on byte number ");
      Serial.println(i);
      break;  // DO NOT USE CONTINUE - we want to skip checking AS SOON AS WE FIND A SINGLE INVALID BYTE!
    }

  }

  if((Auth1=false) || (Auth2=false)){
    return false;
  } 
  else if((Auth1=true) || (Auth2=true)){
    return true;
  }

}

void Lock(int s){

  int pos = SERVO_Closed;  // temp for our position.
  Serial.println("LOCK IS LIVE and POINTER IS CLOSED");


  if(s == 1){
    // Lets LOCK
    Serial.println("Servo is now closing to LOCK");

    for(pos = SERVO_Open; pos >= SERVO_Closed; pos -= 1) {

      lock.write(pos);
      delay(SERVO_MiniDelay);
      Serial.println(pos);

    }


    Serial.println("servo should be closed now");

  } 
  else if(s == 0){

    // Lets OPEN - we assume it is locked
    Serial.println("Attempting to open");

    for(pos = SERVO_Closed; pos <= SERVO_Open; pos += 1) {

      lock.write(pos);
      delay(SERVO_MiniDelay);
      Serial.println(pos);

    }

    Serial.println("Servo should be open now!");

  }
}


void BlinkLED(int s){

  if(s ==1){
    digitalWrite(ledPin, HIGH);   // set the LED on
  }

  if(s == 0){
    digitalWrite(ledPin, LOW);   // set the LED off
  }  

}

Easy design, but what if the wire snaps, the servo (or some of the other hardware) breaks? Will you have another way of opening it?

Yeah there is fishing line attached to the gate lock that goes to a handle inside the control box. i can tug on that to open the lock manually.

Excellent work! I thoroughly enjoyed the way you mounted the 7805 regulator. Classic! Nice fridge too. I want one for my dorm room! :wink:

Thanks!

All i had was small bits of prefboard that really wasn't going to work for the 7805, but i did have the loped off end of the servo wires..

It just seemed natural.

And i got this fridge on craigs list for $20 - year old, but works perfectly. Now that school for most college students is about to start up, you can buy these new from most retailers for less than 100$

Man that's awesome!

You really want to piss off your co-workers? Rig of the toilet seat in the bathroom like that! :smiley: