Navigation

RGB Combination Lock- Boredom over Christmas break

I saw this on HackADay.com; and thought it would be a fun little project.

http://hackaday.com/2008/06/12/how-to-make-an-rgb-combination-door-lock-part-1/


So i decided to replicate it.



Unfortunately; i my aim with the 16'' drill bit isn't quite as accurate as my aim with my 17hmr ( :D)....


... Outside or Inside of the closet :(

After sometime i was able to Successfully drill through the wall and fish the Cat5 Cables through it.

The inside of my control box is a MESS! But i still got it working; so i'm pleased with it.

Everything works now; except the door lock itself (which somewhat defeats the purpose of it); i still need to mount the locking mechanism in my door frame.

Ill post a video when everything is completed.


Other pictures of it may be found at: http://picasaweb.google.com/aadee92/DoorLock#

PicasaWeb Slideshow




the code for the Arduino:

//based on buttton_test
//This is the v1 release of the RGB door lock code. The hard coded code is:
// [r][g][b][r]
// [r][g][b][r]
// The buttons will flash blue in order while idle.
// On a press, the color is toggled, starting from blank. The password is entered
// by pressing the buttons to set the color code.
// When the code is entered, the pad will turn green and unlock for 10 seconds.
// If the counter is exceeded, the pad will turn red for 30 seconds.
// Written by Will O'Brien, based on various others works.

#define DATAOUT 11//MOSI (pin 7 of AD5206)
#define DATAIN 12//MISO - not used, but part of builtin SPI
#define SPICLOCK  13//sck (pin 8 of AD5206)
#define SLAVESELECT 10 //removed the slave switching code entirely.
#define COLS 4 //x axis
#define ROWS 2 //y axis
#define effect_select 1 //choose idle effect

const byte colpin[COLS] = { //pins for led column grounding transistors
  14,15,16,17}; // Using the analog inputs as digital pins (14=A0,15=A1,16=A2,17=A3)

const byte buttonWrite[ROWS] = {
  3, 2}; //Pins for the Vin of the buttons, y-axis
const byte buttonRead[COLS] = {
  9, 8, 7, 6}; //Pins for reading the state of the buttons, x-axis
boolean pressed[COLS][ROWS] = {
  0};
  const byte lock_pin = 4;
boolean lockState = 0;
boolean effect[COLS][ROWS] = {
  0};
byte effect_color = 3;
byte effect_state = 0;
byte effect_count = 0;


// The pot register numbers for each of the red, green, and blue channels
// Address map for AD5206:
// Pin bin dec
// 2   101 5
// 11  100 4
// 14  010 2
// 17  000 0
// 20  001 1
// 23  011 3

const byte red[2] = {
  5, 0};
const byte green[2] = {
  4, 1};
const byte blue[2] = {
  2, 3};

// Main data for the drawing routine
byte rGrid[COLS][ROWS] = {
  0};
byte gGrid[COLS][ROWS] = {
  0};
byte bGrid[COLS][ROWS] = {
  0};


//  Entry code definition
byte rCode[COLS][ROWS] = {
  0};
byte gCode[COLS][ROWS] = {
  0};
byte bCode[COLS][ROWS] = {
  0};
 
 

byte COLORS = 4;//0  1    2    3
byte gColors[] = {0, 255, 0,   0  }; //green
byte bColors[] = {0, 0,   255, 0  }; //blue
byte rColors[] = {0, 0,   0,   255}; //red

byte colorcode[COLS][ROWS] = { 0 };
byte count;

void setup(){
  count = 0; //init count
  //set entry code
  colorcode[0][0] = 1; //row 1
  colorcode[1][0] = 3;
  colorcode[2][0] = 4;
  colorcode[3][0] = 2;
    colorcode[0][1] = 0; //row 2
    colorcode[1][1] = 2;
    colorcode[2][1] = 1;
    colorcode[3][1] = 3;
 
 
  Serial.begin(19200);
  pinMode(lock_pin, OUTPUT);
  digitalWrite(lock_pin, LOW);

//setup the button inputs and outputs
  for(int i = 0; i < ROWS; ++i){ //set row lines to output and zero them
    pinMode(buttonWrite[i], OUTPUT);
    digitalWrite(buttonWrite[i],LOW);
  }
  for(int j = 0; j<COLS; ++j) { //set column lines to input
    pinMode(buttonRead[j], INPUT);
  }
  byte i;
  byte clr;
  pinMode(DATAOUT, OUTPUT);
  pinMode(DATAIN, INPUT);
  pinMode(SPICLOCK,OUTPUT);
  pinMode(SLAVESELECT,OUTPUT);

  for(byte c = 0; c < COLS; ++c){
    pinMode(colpin[c], OUTPUT); // Initialize LED columns
    digitalWrite(colpin[c], LOW); // Turn all LED cols off
  }

  digitalWrite(SLAVESELECT,HIGH); //disable device  // SPCR = 01010000
  //interrupt disabled,spi enabled,msb 1st,master,clk low when idle,
  //sample on leading edge of clk,system clock/4 (fastest)
  SPCR = (1<<SPE)|(1<<MSTR);
  clr=SPSR;
  clr=SPDR;
  delay(10);
  // clear all of the pot registers
  for (i=0;i<6;i++)
  {
    write_pot(i,0);
  }
grid_init(); //clear rgb grid.
code_init(); //set code in memory.
effect_init();
}

void grid_init(){
  //initialize the button grids with blank data
  for(byte c = 0; c < COLS; ++c){
    for(byte r = 0; r < ROWS; ++r){
      rGrid[c][r] = 0;
      gGrid[c][r] = 0;
      bGrid[c][r] = 0;
    }
  }
}

void effect_init(){
  //initialize the button grids with blank data
  for(byte c = 0; c < COLS; ++c){
    for(byte r = 0; r < ROWS; ++r){
      effect[c][r] = 0;
    }
  }
  effect[0][0] = 1;
}


void loop(){

  Serial.print("");
  effect_count++;
  if(count > 19){
   color_effect(0, 0, 255, 1.5);
   color_effect(0, 0, 0, 1);
   color_effect(0, 0, 255, 1.5);
   color_effect(0, 0, 0, 1);
   color_effect(0, 0, 255, 40);
   grid_init();
   count = 0;
  }
  for(byte r = 0; r < ROWS; ++r){
    digitalWrite(buttonWrite[r], HIGH); //bring button row high for reading presses
    clear_pot(); //clear pot regs between rows, otherwise the row not being read will be lit during other row reads.
    if(code_check()){
     count = 0;
     Serial.print("code matched!"); //silly debug statment.
     open_door(); //unlock the door.
     grid_init(); //clear entered code and return to scanning mode.
    }
   
   
    for(byte c = 0; c < COLS; ++c){
      if(pressed[c][r] != digitalRead(buttonRead[c])){
        pressed[c][r] = digitalRead(buttonRead[c]);
        if(pressed[c][r]){

          if(count == 0){
           grid_init(); //clear the button states once a code entry is begun.
          }
           on_press(c, r); //on button press, call on_press
          count++;
        } else {
          on_release(r, c); //on release, call on_release
        }
      } else {
        if(pressed[r][c]){
          while_pressed(c, r); //on button hold
        } else {
          while_released(c,r); //on release
        }
      }
      if(count == 0){
        if(effect_count == 20) {
           idle_effect();
           effect_count = 0;
        }
      }
    write_pot(red[r],rGrid[c][r]); //writes state of colors to the digital pot register
    write_pot(green[r],gGrid[c][r]);
    write_pot(blue[r],bGrid[c][r]);
     
    digitalWrite(colpin[c], HIGH); //turn one col on while pot is written.
    delayMicroseconds(750); // display. Persistance of Vision makes things appear lit constantly.
    digitalWrite(colpin[c], LOW); //turn the col back off
   
 
    }
    digitalWrite(buttonWrite[r], LOW); //bring current row low.
    delay(4);
   
  }
 
 
  //delay(10);
}

void on_press(byte c, byte r){
  Serial.print(c, DEC);
  Serial.print(", ");
  Serial.println(r, DEC);
  //set_lock();
  color_cycle(c, r);
}

void on_release(byte c, byte r){
  //rgb(c, r, 0, 0, 0);
}

void while_pressed(byte c, byte r){

}

void while_released(byte c, byte r){

}

void open_door(){
  digitalWrite(lock_pin, HIGH);
  color_effect(0, 255, 0, 5); //effect the keypad green for 5 seconds or soish.
 
  digitalWrite(lock_pin, LOW);
}

char spi_transfer(volatile char data)
{
  SPDR = data;                    // Start the transmission
  while (!(SPSR & (1<<SPIF)))     // Wait the end of the transmission
  {
  };
  return SPDR;                    // return the received byte
}

byte write_pot(byte address, byte value)
{
  digitalWrite(SLAVESELECT, LOW);
  //2 byte opcode
  spi_transfer(address % 6);
  spi_transfer(constrain(255-value,0,255));
  digitalWrite(SLAVESELECT, HIGH); //release chip, signal end transfer
}

void rgb(byte c, byte r, byte R, byte G, byte B){
  rGrid[c][r] = R;
  gGrid[c][r] = G;
  bGrid[c][r] = B;
}

void clear_pot(){
    // clear all of the pot registers
   byte i;
  for (i=0;i<6;i++)
  {
    write_pot(i,0);
  }
}

void code_init(){
//This is where the entry code is defined.
//    c r where c is column, r is row. Each is 0-255. Values are mixed to create colors.
// The code consists for four colors to be displayed on one row.
for(byte c=0; c < COLS; c++){
  for(byte r=0; r < ROWS; r++){
    rCode[c][r] = rColors[colorcode[c][r]]; //column 0, row 0
    gCode[c][r] = gColors[colorcode[c][r]];
    bCode[c][r] = bColors[colorcode[c][r]];
  }
}
}

boolean code_check(){ //check color state of grid to see if it matches entry code.


for(byte c=0;c<COLS;c++){
  for(byte r=0; r < ROWS; r++){

    if(rGrid[c][r] != rCode[c][r]){
      return(0);
    }
    if(gGrid[c][r] != gCode[c][r]){
      return(0);
    }
    if(bGrid[c][r] != bCode[c][r]){
      return(0);
    }
  }
}
  return(1);
}

void color_effect(byte dRed, byte dGreen, byte dBlue, byte time){
  //effect all of the keypad buttons to the provided color for n seconds and turn it off again.
  byte c;
      for(byte r=0; r<ROWS; r++){ //leave the grid alone, just write the pot.
        write_pot(red[r],dRed);
        write_pot(green[r],dGreen);
        write_pot(blue[r],dBlue);
      }
      for(c=0;c<COLS;c++){
    digitalWrite(colpin[c], HIGH); //turn one col on while pot is written.
      }   
    delay(time*1000); //turn time into secondsish
      for(c=0;c<COLS;c++){
    digitalWrite(colpin[c], LOW); //turn the col back off
      }
    clear_pot(); //turn off everything in the pot.
 
}

void color_cycle(byte c, byte r){
  byte color = get_color(c, r);
  Serial.print("got color");
  Serial.print( color, DEC );
  if(color < COLORS){
    color++;
  } else {
    color = 1; //skip blank color 0
  }
  rgb(c, r, rColors[color], gColors[color], bColors[color]);
}

byte get_color(byte c, byte r){
   for(byte i=0; i < COLORS; i++){
  if(rGrid[c][r] == rColors[i]){
    if(bGrid[c][r] == bColors[i]){
      if(gGrid[c][r] == gColors[i]){
        return(i);
      }
    }
  }
  } 
}

void idle_effect(){ //this is he eye candy while the keypad isn't in use.
  grid_init();
if(effect_select==1)
{
   for(byte r=0; r < ROWS; r++){
     for(byte c=0;c<COLS;c++){
    if(effect_state == 1){
     effect[c][r] = 1;
     effect_state = 0;
     return;
    }
    if(effect[c][r]) {
      rGrid[c][r] = rColors[effect_color];
      gGrid[c][r] = gColors[effect_color];
      bGrid[c][r] = bColors[effect_color];     
      effect[c][r] = 0;
      effect_state = 1;
     }

   
   }
  }
}
if(effect_select==2){
 
byte red = rColors[effect_color];
byte blue = bColors[effect_color];
byte green = gColors[effect_color];
if(red != 0)
  red = red - effect_state;



  for(byte r=0; r < ROWS; r++){
      for(byte c=0;c<COLS;c++){

      rGrid[c][r] = rColors[effect_color];
      gGrid[c][r] = gColors[effect_color];
      bGrid[c][r] = bColors[effect_color];     
      effect[c][r] = 0;
      effect_state = 1;
      }
     }
 
}
}