password lock with lcd and other functions

hey guys and girls im just starting off in the wonderfull world of arduino and im have alil issue with coding my first project( totally new to me) i have attached the code that im working with so far the password part works pretty good( freezes everyonce in a while on the press any key to lock screen)
but im tryin to make it so that when the arduino turns on it will display enter grow code on the first row which works and on the second row lights:(ON/OFF)update it say like every min or so with a ldr sensor getting the light readings but i also want to make it so when i go to enter a pass it clears the 2 row and displays 4 **** for the pass. i have tryed looking thru the forums to help but havent been able to find info or just dont understand it. if someone could help me out with my project that would be great

#include <Wire.h>
#include <Keypad_I2C.h>
#include <Keypad.h>
#include <LiquidCrystal_I2C.h>

#define I2CADDR 0x38
#define openpin 13


char inputArray[4];
char Thomas[4] = {'1', '9', '6', '6'};
char Benny[4] = {'1', '5', '5', '6'};
char Arta[4] = {'1', '9', '9', '7'};
char Andrew[4] = {'1', '9', '9', '1'};

int i = 0;


int checkpass()
{
  delay(1000);
  if ((inputArray[0] == Thomas[0] &&
       inputArray[1] == Thomas[1] &&
       inputArray[2] == Thomas[2] &&
       inputArray[3] == Thomas[3]) ||
      (inputArray[0] == Benny[0] &&
       inputArray[1] == Benny[1] &&
       inputArray[2] == Benny[2] &&
       inputArray[3] == Benny[3]) ||
      (inputArray[0] == Arta[0] &&
       inputArray[1] == Arta[1] &&
       inputArray[2] == Arta[2] &&
       inputArray[3] == Arta[3]) ||
      (inputArray[0] == Andrew[0] &&
       inputArray[1] == Andrew[1] &&
       inputArray[2] == Andrew[2] &&
       inputArray[3] == Andrew[3]))
  {
    access();
  } else
  {
    noaccess();
  }
}



//......keypad
const byte ROWS = 4; //four rows
const byte COLS = 3; //three columns
char keys[ROWS][COLS] = {
  {'1', '2', '3'},
  {'4', '5', '6'},
  {'7', '8', '9'},
  {'*', '0', '#'}
};

// Digitran keypad, bit numbers of PCF8574 i/o port
byte rowPins[ROWS] = {6, 5, 4, 3}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {0, 1, 2}; //connect to the column pinouts of the keypad
Keypad_I2C kpd = Keypad_I2C( makeKeymap(keys), rowPins, colPins, ROWS, COLS, I2CADDR );

// constants
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);



void setup() {
  Wire.begin( );
  Serial.begin(9600);
  kpd.begin();
  lcd.begin(16, 2);
  DisplayCodeEntryScreen();
  kpd.setDebounceTime(50);
  pinMode(openpin, OUTPUT);
  pinMode(lightsensor, INPUT);
  digitalWrite(openpin, LOW);


}

void loop()
{
  char key = kpd.getKey();

  if (key)
  {
    inputArray[i] = key;
    i++;
    Serial.print(key);
    lcd.setCursor(i + 5, 1);
    lcd.print("*");

    if (i == 4)
    {
      checkpass();
    }

    if (i >= 5)
    {
      i = 0;
      DisplayCodeEntryScreen();
    }


  }
}

void DisplayCodeEntryScreen ()
{
  digitalWrite(openpin, LOW);
  lcd.clear();
  Serial.begin(9600);
  lcd.setCursor(0, 0);
  lcd.print("Enter Grow Code");
  lcd.setCursor(0, 1);
  lcd.print("Lights:");



}

void access()
{
  lcd.clear();
  lcd.setCursor(1, 0);
  lcd.print("Access Granted");
  digitalWrite(openpin, HIGH);
  delay(2000);
  lcd.clear();
  lcd.setCursor(1, 0);
  lcd.print("Press Any Key");
  lcd.setCursor(1, 1);
  lcd.print("To Lock");
}

void noaccess()
{
  lcd.clear();
  lcd.setCursor(1, 0);
  lcd.print("Not Athorized");
  lcd.setCursor(3, 1);
  lcd.print("Try Again");
}

It is not clear what you want help with.

If you want help with clearing a row, go to the row and display space characters.

If you want code written for you, go to the "Gigs and Collaborations" section and bring your wallet.

delay(1000) wastes the considerable power of your Arduino for a whole second. It would be better to avoid using delay(...) and make use of millis() instead.

In the long run, it will be easier to compare C strings using the strcmp(...) function.

vaj4088: In the long run, it will be easier to compare C strings using the strcmp(...) function.

In this case memcmp() will also work and might be easier.

from http://www.cplusplus.com/reference/cstring/memcmp/

Notice that, unlike strcmp, the function does not stop comparing after finding a null character.

I think that, for a newbie, this makes memcmp(...) harder than strcmp(...). However, if all of the passwords are the same length (as they are in this case), then memcmp(...) may be easier.

sry for not being that clear about what i want done. lets make it simple for now the password to use memcmp() or strcmp() can i still use the char or do i have to do it another way, that link has made me even more confused this is what i tought but i know its wrong but by how much?

int checkpass()
{

  if (strcmp (Thomas,inputArray) != 0);
  
   {
  
    access();
  } 
  else 
  {
    noaccess();
  }
}

vaj4088: from http://www.cplusplus.com/reference/cstring/memcmp/

I think that, for a newbie, this makes memcmp(...) harder than strcmp(...). However, if all of the passwords are the same length (as they are in this case), then memcmp(...) may be easier.

It requires less modifications on the original code; currently the character array (e.g. Thomas) is not nul terminated and neither seems the inputArray to be terminated with a nul character. So a strcmp() will not work and a memcmp() will.

lrc_empire: sry for not being that clear about what i want done. lets make it simple for now the password to use memcmp() or strcmp() can i still use the char or do i have to do it another way, that link has made me even more confused this is what i tought but i know its wrong but by how much? }

You're on the right way; see above why I think it will not work with strcmp().

  if (memcmp(inputArray, Thomas, 4) == 0 ||
      memcmp(inputArray, Benny, 4) == 0 ||
      memcmp(inputArray, Arta, 4) == 0 ||
      memcmp(inputArray, Andrew, 4) == 0)
  {
    access();
  }
  else
  {
    noaccess();
  }

The disadvantage is that you must make sure that all arrays are the same size (4) and that that number is currently hardcoded. You can (probably) work around that if needed.

PS both strcmp() and memcmp() return 0 on a match; your updated code currently checks for 'not 0' which means you test if the two variables (arrays) differ.

ok got the memcmp updates and it looks like once i took the delay out of the int checkpass() the freezing problem stopped... now as for using millis() instead of delay() it looks like i have to use it in the loop but i need it in the void access() too and have only found info about Blink Without Delay which isnt what i want to do ... or am i looking at this all wrong

Your looking at it wrong :wink: You can use the approach anywhere. The trick is simple once you understand it. Let’s say you want to boil an egg. You put the egg in a pan with boiling water and look at the time. It’s 04:30 and that is the start time. You know that your egg will be done to perfection after 4 minutes, so you keep on checking the clock and when it’s 4:34 you take action (the action being taking the egg out of the boiling water).

In code

/*
  boil an egg
  returns:
    false while boiling in progress, true when finished
*/
bool boilEgg()
{
  static unsigned long startTime = 0;

  // if you just put the egg in
  if(startTime == 0)
  {
    // remember the time that you put the egg in
    startTime = millis();
  }

  // if 4 minutes have lapsed
  if(millis() - startTime >= 240000)
  {
    // reset the start time for the next time that you want to boil an egg
    startTime = 0;
    // indicate that egg is ready
    return true;
  }
  // indicate that egg is not ready
  return false;
}

Note the use of the static keyword; the result is that the local variable startTime will be remembered when the function returns so the next time it’s still known.

Now you also want to make toast; you can use that exact same function framework.

/*
  make toast
  returns:
    false while making toast in progress, true when finished
*/
bool makeToast()
{
  static unsigned long startTime = 0;

  // if you just put the toast in the toaster
  if(startTime == 0)
  {
    // remember the time that you put the toast in
    startTime = millis();
  }

  // if 2 minutes have lapsed
  if(millis() - startTime >= 120000)
  {
    // reset the start time for the next time that you want to boil an egg
    startTime = 0;
    // indicate that toast is ready
    return true;
  }
  // indicate that toast is not ready
  return false;
}

Because the variables startTime are local to the functions, they do not interfere with each other.

Now you need to combine both.

void loop()
{
  static bool eggReady = false;
  static bool toastReady = false;

  if(eggReady == false)
  {
    eggReady = boilEgg();
  }
  else
  {
    // take egg out of water
  }

  if(toastReady == false)
  {
    toastReady = makeToast();
  }
  else
  {
    // take toast out of toaster 
  }

  if(eggReady == true && toastReady == true)
  {
    // breakfast is ready
    
    // for next breakfast
    eggReady = false;
    toastReady = false;
  }
}

As you can see, while a ‘flag’ is false, the associated function is called. The flags will be changed by the return value of the associated functions (boilEgg and makeToast). Be aware that the above code will continuously boil eggs and make toast :wink:

Hmm, this make me hungry.

Now you first need to fix a bug in your existing code

void loop()
{
  char key = kpd.getKey();

  if (key)
  {
    inputArray[i] = key;        <--- i can be 4
    i++;
    Serial.print(key);
    lcd.setCursor(i + 5, 1);
    lcd.print("*");

    if (i == 4)
    {
      checkpass();
    }

    if (i >= 5)
    {
      i = 0;
      DisplayCodeEntryScreen();
    }
  }
}

The variable i can get the value 4; in which case you will write a memory location outside the inputArray which can make your program crash. The easiest fix is to make inputArray one char bigger so you can also place the last keypress (to lock again after access was granted)

char inputArray[5];

It would also be nice that in the ‘no access’ situation you inform the user that he/she first has to press another key before trying again.

PS
note the use of comments before functions; it indicates what the functions do and what they return under which conditions.

To apply to your situation

/*
  display access message and unlock door
*/
void access()
{
  static unsigned long startTime = 0;

  // if delay not started yet
  if(startTime == 0)
  {
    // remember the time that access was granted
    startTime = millis();

    // update display with 'access granted' message
    ...
    ...

    // unlock door
    ...
    ...
  }

  // if 2 seconds have lapsed
  if(millis() - startTime >= 2000)
  {
    // reset the start time for the next time that access is granted
    startTime = 0;

    // display the message to press any key to look the door
    ...
    ...
  }
}

Note that this code does not return a value; if you encounter a need for that you can implement it.

Now the rest of your code needs to be reworked as the access function needs to be called repeatedly.

Currently you call access from checkPass(). It's probably better that you call it from loop. To achieve that, you can let checkPass return a value (your code was already prepared for that).

/*
  check password against known passwords
  returns:
    true if password matched one of the known ones, else false
*/
bool checkPass()
{
  if (memcmp(inputArray, Thomas, 4) == 0 ||
      memcmp(inputArray, Benny, 4) == 0 ||
      memcmp(inputArray, Arta, 4) == 0 ||
      memcmp(inputArray, Andrew, 4) == 0)
  {
    return true;
  }
  else
  {
    return false;
  }
}

Note that I have changed the function to return a bool instead of an int.

And in loop you can check the return value.

void loop()
{
  static bool accessGranted = false;

  ...
  ...

    if (i == 4)
    {
      accessGranted = checkpass();
      
      if(accessGranted == true)
      {
        access();
      }
      else
      {
        noaccess();
      }
    }
}

Now the next problem comes in; you only go through this if a key was pressed. So once access is granted, the access function will only be called once and hence the 'delay' will not work. You need to seperate the keyboard input from the testing.

void loop()
{
  static bool accessGranted = false;

  char key = kpd.getKey();

  if (key)
  {
    inputArray[i] = key;
    i++;
    Serial.print(key);
    lcd.setCursor(i + 5, 1);
    lcd.print("*");
  }

  if (i == 4)
  {
    ...
    ...
  }

  if (i >= 5)
  {
    ...
    ...
  }
}

Now you still need to set the accessGranted flag to false if the user presses the extra key.

  if (i >= 5)
  {
    i = 0;
    accessGranted = false;
    DisplayCodeEntryScreen();
  }

And I think that that are all 'components' that you need. If you get stuck, post your revised code and we can see where it goes wrong.

Lastly a personal pet hate; you should never use a single character variable as a global variable. If you ever want to find out where the variable i is use, you have a hard time. Searching for it is nearly impossible because (in your original code) the letter 'i' occurs 110 times. Your code is small and you will probably remember where i is used but when code grows bigger and the variable is used in multiple places far away from each other you will have a hard time finding it. I suggest therefore that you change it to e.g. 'inputIndex' to reflect what it actually does (an index into the inputArray).

There is also no reason for it to be a global variable as you only use it in one function. I would place it in loop() and make it static; but that is a personal preference.

so i have updated the code as u have said still havin trouble with the millis()
this is what the code looks like now… the millis() are not working i suspect it to be something lil that i over looked, btw thank you for your help so far buddy. the code compiles but when i put the password in the first time it displays “access granted” and it ends there but if i push another key it goes back to the displaycodeentryscreen then i try the password again and it displays press any key to lock but no access granted b4 that

[code]


#include <Wire.h>
#include <Keypad_I2C.h>
#include <Keypad.h>
#include <LiquidCrystal_I2C.h>

#define I2CADDR 0x38
#define openpin  13


char inputArray[5];
char Thomas[4] = {'1', '9', '6', '6'};
char Benny[4] = {'1', '5', '5', '6'};
char Arta[4] = {'1', '9', '9', '7'};
char Andrew[4] = {'1', '9', '9', '1'};

int inputIndex = 0;

bool checkpass()
{
  if (memcmp(inputArray, Thomas, 4) == 0 ||
      memcmp(inputArray, Benny, 4) == 0 ||
      memcmp(inputArray, Arta, 4) == 0 ||
      memcmp(inputArray, Andrew, 4) == 0)
  {
    return true;
  } else
  {
    return false;
  }
}



//......keypad
const byte ROWS = 4; //four rows
const byte COLS = 3; //three columns
char keys[ROWS][COLS] = {
  {'1', '2', '3'},
  {'4', '5', '6'},
  {'7', '8', '9'},
  {'*', '0', '#'}
};

// Digitran keypad, bit numbers of PCF8574 i/o port
byte rowPins[ROWS] = {6, 5, 4, 3}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {0, 1, 2}; //connect to the column pinouts of the keypad
Keypad_I2C kpd = Keypad_I2C( makeKeymap(keys), rowPins, colPins, ROWS, COLS, I2CADDR );

// constants
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);


void setup() {
  Wire.begin( );
  Serial.begin(9600);
  kpd.begin();
  lcd.begin(16, 2);
  DisplayCodeEntryScreen();
  kpd.setDebounceTime(50);
  pinMode(openpin, OUTPUT);
  //  pinMode(lightsensor, INPUT);
  digitalWrite(openpin, LOW);


}

void loop()
{
  static bool accessGranted = false;

  char key = kpd.getKey();


  if (key)
  {
    inputArray[inputIndex] = key;
    inputIndex++;
    Serial.print(key);
    lcd.setCursor(inputIndex + 5, 1);
    lcd.print("*");

    if (inputIndex == 4)

    {
      accessGranted = checkpass();

      if (accessGranted == true)
      {
        access();
      }
      else
      {
        noaccess();
      }
    }

    if (inputIndex >= 5)
    {
      inputIndex = 0;
      accessGranted = false;
      DisplayCodeEntryScreen();
    }

  }

}

void DisplayCodeEntryScreen ()
{
  digitalWrite(openpin, LOW);
  lcd.clear();
  Serial.begin(9600);
  lcd.setCursor(0, 0);
  lcd.print("Enter Grow Code");
  //lcd.setCursor(0, 1);
  //lcd.print("Lights:");



}


void access()
{
  static unsigned long startTime = 0;

  if (startTime == 0)
  {
    startTime = millis();

    lcd.clear();
    lcd.setCursor(1, 0);
    lcd.print("Access Granted");
    digitalWrite(openpin, HIGH);
  }

  if (millis() - startTime >= 2000)
  {
    startTime = 0;

    lcd.clear();
    lcd.setCursor(1, 0);
    lcd.print("Press Any Key");
    lcd.setCursor(1, 1);
    lcd.print("To Lock");

  }
}

void noaccess()
{
  lcd.clear();
  lcd.setCursor(1, 0);
  lcd.print("Not Athorized");
  lcd.setCursor(3, 1);
  lcd.print("Try Again");
}

[/code]

sterretje:
Now the next problem comes in; you only go through this if a key was pressed. So once access is granted, the access function will only be called once and hence the ‘delay’ will not work. You need to seperate the keyboard input from the testing.

void loop()

{
  static bool accessGranted = false;

char key = kpd.getKey();

if (key)
  {
    inputArray[i] = key;
    i++;
    Serial.print(key);
    lcd.setCursor(i + 5, 1);
    lcd.print("*");
  }

if (i == 4)
  {
    …
    …
  }

if (i >= 5)
  {
    …
    …
  }
}

You missed the above part in reply #8 :wink:

ok totally over looked that part sry

so here is the new code

#include <Wire.h>
#include <Keypad_I2C.h>
#include <Keypad.h>
#include <LiquidCrystal_I2C.h>

#define I2CADDR 0x38
#define openpin  13


char inputArray[5];
char Thomas[4] = {'1', '9', '6', '6'};
char Benny[4] = {'1', '5', '5', '6'};
char Arta[4] = {'1', '9', '9', '7'};
char Andrew[4] = {'1', '9', '9', '1'};

int inputIndex = 0;

bool checkpass()
{
  if (memcmp(inputArray, Thomas, 4) == 0 ||
      memcmp(inputArray, Benny, 4) == 0 ||
      memcmp(inputArray, Arta, 4) == 0 ||
      memcmp(inputArray, Andrew, 4) == 0)
  {
    return true;
  } else
  {
    return false;
  }
}



//......keypad
const byte ROWS = 4; //four rows
const byte COLS = 3; //three columns
char keys[ROWS][COLS] = {
  {'1', '2', '3'},
  {'4', '5', '6'},
  {'7', '8', '9'},
  {'*', '0', '#'}
};

// Digitran keypad, bit numbers of PCF8574 i/o port
byte rowPins[ROWS] = {6, 5, 4, 3}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {0, 1, 2}; //connect to the column pinouts of the keypad
Keypad_I2C kpd = Keypad_I2C( makeKeymap(keys), rowPins, colPins, ROWS, COLS, I2CADDR );

// constants
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);


void setup() {
  Wire.begin( );
  Serial.begin(9600);
  kpd.begin();
  lcd.begin(16, 2);
  DisplayCodeEntryScreen();
  kpd.setDebounceTime(50);
  pinMode(openpin, OUTPUT);
  //  pinMode(lightsensor, INPUT);
  digitalWrite(openpin, LOW);


}

void loop()
{
  static bool accessGranted = false;

  char key = kpd.getKey();


  if (key)
  {
    inputArray[inputIndex] = key;
    inputIndex++;
    Serial.print(key);
    lcd.setCursor(inputIndex + 5, 1);
    lcd.print("*");
  }
  if (inputIndex == 4)

  {
    accessGranted = checkpass();

    if (accessGranted == true)
    {
      access();
    }
    else
    {
      noaccess();
    }
  }

  if (inputIndex >= 5)
  {
    inputIndex = 0;
    accessGranted = false;
    DisplayCodeEntryScreen();
  }



}

void DisplayCodeEntryScreen ()
{
  digitalWrite(openpin, LOW);
  lcd.clear();
  Serial.begin(9600);
  lcd.setCursor(0, 0);
  lcd.print("Enter Grow Code");
  //lcd.setCursor(0, 1);
  //lcd.print("Lights:");



}


void access()
{
  static unsigned long startTime = 0;

  if (startTime == 0)
  {
    startTime = millis();


    lcd.setCursor(0, 0);
    lcd.print(" Access Granted ");
    lcd.setCursor(0, 1);
    lcd.print("                ");
    digitalWrite(openpin, HIGH);
  }

  if (millis() - startTime >= 2000)
  {
    startTime = 0;


    lcd.setCursor(0, 0);
    lcd.print(" Press Any Key  ");
    lcd.setCursor(1, 1);
    lcd.print("    To Lock     ");

  }
}

void noaccess()
{
  lcd.setCursor(0, 0);
  lcd.print(" Not Athorized  ");
  lcd.setCursor(0, 1);
  lcd.print("   Try Again    ");
}

but now it displays “access granted” and for a split second it shows “press any key to lock” then goes back to “access granted” im guessing thats because its going thru the loop but i want it to end on “press any key to lock”

Sorry, I missed an else

void access()
{
  static unsigned long startTime = 0;

  if (startTime == 0)
  {
    startTime = millis();


    lcd.setCursor(0, 0);
    lcd.print(" Access Granted ");
    lcd.setCursor(0, 1);
    lcd.print("                ");
    digitalWrite(openpin, HIGH);
  }
  else if (millis() - startTime >= 2000)  <------------ HERE
  {
    startTime = 0;

    lcd.setCursor(0, 0);
    lcd.print(" Press Any Key  ");
    lcd.setCursor(1, 1);
    lcd.print("    To Lock     ");

  }
}

that code still doesnt work, if i take out the startTime = 0;, it works only once then i lock then re enter the password and just goes to “push any key to lock”

void access()
{
  static unsigned long startTime = 0;

  if (startTime == 0)
  {
    startTime = millis();


    lcd.setCursor(0, 0);
    lcd.print(" Access Granted ");
    lcd.setCursor(0, 1);
    lcd.print("                ");
    digitalWrite(openpin, HIGH);
  }

 else if (millis() - startTime >= 2000)
  {
    startTime = 0;   <====here


    lcd.setCursor(0, 0);
    lcd.print(" Press Any Key  ");
    lcd.setCursor(1, 1);
    lcd.print("    To Lock     ");
 
  }
}

Please post your complete code. I think that I know what the problem can be.

#include <Wire.h>
#include <Keypad_I2C.h>
#include <Keypad.h>
#include <LiquidCrystal_I2C.h>

#define I2CADDR 0x38
#define openpin  13


char inputArray[5];
char Thomas[4] = {'1', '9', '6', '6'};
char Benny[4] = {'1', '5', '5', '6'};
char Arta[4] = {'1', '9', '9', '7'};
char Andrew[4] = {'1', '9', '9', '1'};

int inputIndex = 0;

bool checkpass()
{
  if (memcmp(inputArray, Thomas, 4) == 0 ||
      memcmp(inputArray, Benny, 4) == 0 ||
      memcmp(inputArray, Arta, 4) == 0 ||
      memcmp(inputArray, Andrew, 4) == 0)
  {
    return true;
  } else
  {
    return false;
  }
}



//......keypad
const byte ROWS = 4; //four rows
const byte COLS = 3; //three columns
char keys[ROWS][COLS] = {
  {'1', '2', '3'},
  {'4', '5', '6'},
  {'7', '8', '9'},
  {'*', '0', '#'}
};

// Digitran keypad, bit numbers of PCF8574 i/o port
byte rowPins[ROWS] = {6, 5, 4, 3}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {0, 1, 2}; //connect to the column pinouts of the keypad
Keypad_I2C kpd = Keypad_I2C( makeKeymap(keys), rowPins, colPins, ROWS, COLS, I2CADDR );

// constants
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);


void setup() {
  Wire.begin( );
  Serial.begin(9600);
  kpd.begin();
  lcd.begin(16, 2);
  DisplayCodeEntryScreen();
  kpd.setDebounceTime(50);
  pinMode(openpin, OUTPUT);
  //  pinMode(lightsensor, INPUT);
  digitalWrite(openpin, LOW);


}

void loop()
{
  static bool accessGranted = false;

  char key = kpd.getKey();


  if (key)
  {
    inputArray[inputIndex] = key;
    inputIndex++;
    Serial.print(key);
    lcd.setCursor(inputIndex + 5, 1);
    lcd.print("*");
  }
  if (inputIndex == 4)

  {
    accessGranted = checkpass();

    if (accessGranted == true)
    {
      access();
    }
    else
    {
      noaccess();
    }
  }

  if (inputIndex >= 5)
  {
    inputIndex = 0;
    accessGranted = false;
    DisplayCodeEntryScreen();
  }



}

void DisplayCodeEntryScreen ()
{
  digitalWrite(openpin, LOW);
  lcd.clear();
  Serial.begin(9600);
  lcd.setCursor(0, 0);
  lcd.print("Enter Grow Code");
  //lcd.setCursor(0, 1);
  //lcd.print("Lights:");



}


void access()
{
  static unsigned long startTime = 0;

  if (startTime == 0)
  {
    startTime = millis();


    lcd.setCursor(0, 0);
    lcd.print(" Access Granted ");
    lcd.setCursor(0, 1);
    lcd.print("                ");
    digitalWrite(openpin, HIGH);
  }

 Else if (millis() - startTime >= 2000)
  {
    startTime = 0;


    lcd.setCursor(0, 0);
    lcd.print(" Press Any Key  ");
    lcd.setCursor(1, 1);
    lcd.print("    To Lock     ");

  }
}

void noaccess()
{
  lcd.setCursor(0, 0);
  lcd.print(" Not Athorized  ");
  lcd.setCursor(0, 1);
  lcd.print("   Try Again    ");
}
  if (inputIndex == 4)

  {
    accessGranted = checkpass();

Entering the 4th character triggers the password checking.

  if (inputIndex >= 5)
  {
    inputIndex = 0;
    accessGranted = false;
    DisplayCodeEntryScreen();
  }

Entering the 5th character, after being told to take a hike or being let in, triggers the reset for the next person.

Why?

You only call access() once, if the correct value is entered. You can't expect the function to take long to execute. It doesn't make sense to expect, in the function, for 2 seconds to have passed.

Some comments to explain what you think you are doing are definitely in order.

i did it that way because when i researched door locks key pads thats the way some ppl have done it so i tryed and it worked for me but is it a wrong way to do it? Im still very new with arduino only started a month ago

btw got my code working

#include <Wire.h>
#include <Keypad_I2C.h>
#include <Keypad.h>
#include <LiquidCrystal_I2C.h>

#define I2CADDR 0x38
#define openpin  13


char inputArray[5];
char Thomas[4] = {'1', '9', '6', '6'};
char Benny[4] = {'1', '5', '5', '6'};
char Arta[4] = {'1', '9', '9', '7'};
char Andrew[4] = {'1', '9', '9', '1'};

int inputIndex = 0;

boolean replay = true;

bool checkpass()
{
  if (memcmp(inputArray, Thomas, 4) == 0 ||
      memcmp(inputArray, Benny, 4) == 0 ||
      memcmp(inputArray, Arta, 4) == 0 ||
      memcmp(inputArray, Andrew, 4) == 0)
  {
    return true;
  } else
  {
    return false;
  }
}



//......keypad
const byte ROWS = 4; //four rows
const byte COLS = 3; //three columns
char keys[ROWS][COLS] = {
  {'1', '2', '3'},
  {'4', '5', '6'},
  {'7', '8', '9'},
  {'*', '0', '#'}
};

// Digitran keypad, bit numbers of PCF8574 i/o port
byte rowPins[ROWS] = {6, 5, 4, 3}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {0, 1, 2}; //connect to the column pinouts of the keypad
Keypad_I2C kpd = Keypad_I2C( makeKeymap(keys), rowPins, colPins, ROWS, COLS, I2CADDR );

// constants
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);


void setup() {
  Wire.begin( );
  Serial.begin(9600);
  kpd.begin();
  lcd.begin(16, 2);
  DisplayCodeEntryScreen();
  kpd.setDebounceTime(50);
  pinMode(openpin, OUTPUT);
  //  pinMode(lightsensor, INPUT);
  digitalWrite(openpin, LOW);


}

void loop()
{
  static bool accessGranted = false;

  char key = kpd.getKey();


  if (key)
  {
    inputArray[inputIndex] = key;
    inputIndex++;
    Serial.print(key);
    lcd.setCursor(inputIndex + 5, 1);
    lcd.print("*");
  }
  if (inputIndex == 4)

  {
    accessGranted = checkpass();

    if (accessGranted == true)
    {

      if (replay == true)
      {
        access();
      }
    }
    else
    {
      noaccess();
    }

  }

  if (inputIndex >= 5)
  {
    inputIndex = 0;
    accessGranted = false;
    DisplayCodeEntryScreen();
    replay = true;
  }



}

void DisplayCodeEntryScreen ()
{
  digitalWrite(openpin, LOW);
  lcd.clear();
  Serial.begin(9600);
  lcd.setCursor(0, 0);
  lcd.print("Enter Grow Code");
  //lcd.setCursor(0, 1);
  //lcd.print("Lights:");



}


void access()
{
  static unsigned long startTime = 0;

  if (startTime == 0)
  {
    startTime = millis();


    lcd.setCursor(0, 0);
    lcd.print(" Access Granted ");
    lcd.setCursor(0, 1);
    lcd.print("                ");
    digitalWrite(openpin, HIGH);
  }

  else if (millis() - startTime >= 2000)
  {
    lcd.setCursor(0, 0);
    lcd.print(" Press Any Key  ");
    lcd.setCursor(1, 1);
    lcd.print("    To Lock     ");
    replay = false;
    startTime = 0;
  }
}

void noaccess()
{
  lcd.setCursor(0, 0);
  lcd.print(" Not Athorized  ");
  lcd.setCursor(0, 1);
  lcd.print("   Try Again    ");
}

You get the 'press any key' message after entering a second /third etc valid code because pressing the 5th key does not complete the 'delay' in the access() function. So the first time after the second /third you will get the message, next time it access() is called it will be the normal sequence. Definitely a flaw in the code I suggested. It also keeps repeating till the 5th key is pressed.

The easy way out is to start thinking in states.

You have a state where the door is locked and the user needs to enter a password. You have a state where the password is entered and a state where (once complete) the password is validated. You have a state for access and a state for no access. And lastly you have a state for the 'press any key'.

Place the below in the beginning of your code

#define PASSWORD_ENTRY 1
#define PASSWORD_VALIDATE 2
#define UNLOCK_DOOR 3
#define ACCESS 4
#define NOACCESS 5
#define WAIT_ANYKEY 6

In loop(), you can build your statemachine that cycles through the states based on conditions.

void loop()
{
void loop()
{
  // remember the state that the program is in
  // start with waiting for password
  static byte currentState = PASSWORD_ENTRY;

  switch (currentState)
  {
    case PASSWORD_ENTRY:
      // get 4 digits from keypad
      // once complete, goto PASSWORD_VALIDATE
      break;
    case PASSWORD_VALIDATE:
      // validate the password
      // if OK, goto ACCESS
      // else goto NOACCESS
      break;
    case ACCESS:
      // unlock door
      // display message and wait for 2 seconds
      // goto WAIT_ANYKEY
      break;
    case NOACCESS:
      // display message
      // goto WAIT_ANYKEY
      break;
    case WAIT_ANYKEY:
      // 'clear' the array
      // wait for key
      // if key pressed, lock door and goto PASSWORD_ENTRY
      break;
  }
}

You can now implement the different cases (states). The below is based on serial input, not keypad input. Output goes to the serial port instead of the LCD. So you have to do a little work.

void loop()
{
  // remember the state that the program is in
  // start with waiting for password
  static byte currentState = PASSWORD_ENTRY;

  switch (currentState)
  {
    case PASSWORD_ENTRY:
      // read keyboard input
      if (Serial.available() > 0)
      {
        inputArray[inputIndex++] = Serial.read();
      }
      // if 4 digits entered, go to next state
      if (inputIndex == 4)
      {
        currentState = PASSWORD_VALIDATE;
      }
      break;
    case PASSWORD_VALIDATE:
      if (checkpass() == true)
      {
        currentState = ACCESS;
      }
      else
      {
        currentState = NOACCESS;
      }
      break;
    case ACCESS:
      digitalWrite(openpin, HIGH);
      if (access() == true)
      {
        currentState = WAIT_ANYKEY;
      }
      break;
    case NOACCESS:
      noaccess();
      currentState = WAIT_ANYKEY;
      break;
    case WAIT_ANYKEY:
      // 'clear' the array
      inputIndex = 0;
      // wait for key
      if (Serial.available() > 0)
      {
        Serial.read();
        currentState = PASSWORD_ENTRY;
        // lock door
        digitalWrite(openpin, LOW);
        // display code entry screen
        DisplayCodeEntryScreen();
      }
      break;
  }
}

Now access() needs to return a value (as I showed for boilEgg() a while ago) that can be checked in the access state to see if the two seconds have lapsed.

/*
  display access message
  wait two seconds
  inform user that he/she needs to press any key to lock

  returns:
    true if two seconds have passed, else false
*/
bool access()
{
  static unsigned long startTime = 0;

  if (startTime == 0)
  {
    startTime = millis();
    Serial.println(" Access Granted ");
  }
  else if (millis() - startTime >= 2000)
  {
    startTime = 0;
    Serial.println("Press Any Key");
    Serial.println("To Lock");

    // indicate that the 'delay' is finished
    return true;
  }

  // indicate that the 'delay' is not finished yet
  return false;
}

Note that access() no longer unlocks the door but only displays the message. The unlocking is done in the statemachine.

loop() is a little big; you can write a function getPassword() for the PASSWORD_ENTRY state and call that in the 'case PASSWORD_ENTRY'. Similar for the WAIT_ANYKEY state.

Please ask if you do not understand something.

Code compiled and tested.

PS I've modified the noaccess() function to inform the user to press any key.

void noaccess()
{
  Serial.println("Not Athorized");
  Serial.println("Press any key");
}

ok got it working and all thx u so much for your help, i definitely learned alot they past couple days, got it working and here is my new code

#include <Wire.h>
#include <Keypad_I2C.h>
#include <Keypad.h>
#include <LiquidCrystal_I2C.h>

#define I2CADDR 0x38

#define PASSWORD_ENTRY 1
#define PASSWORD_VALIDATE 2
#define UNLOCK_DOOR 3
#define ACCESS 4
#define NOACCESS 5
#define WAIT_ANYKEY 6

const int openpin = 13;


char inputArray[5];
char Thomas[4] = {'1', '9', '6', '6'};
char Benny[4] = {'1', '5', '5', '6'};
char Arta[4] = {'1', '9', '9', '7'};
char Andrew[4] = {'1', '9', '9', '1'};

int inputIndex = 0;


bool checkpass()
{
  if (memcmp(inputArray, Thomas, 4) == 0 ||
      memcmp(inputArray, Benny, 4) == 0 ||
      memcmp(inputArray, Arta, 4) == 0 ||
      memcmp(inputArray, Andrew, 4) == 0)
  {
    return true;
  } else
  {
    return false;
  }
}



//......keypad
const byte ROWS = 4; //four rows
const byte COLS = 3; //three columns
char keys[ROWS][COLS] = {
  {'1', '2', '3'},
  {'4', '5', '6'},
  {'7', '8', '9'},
  {'*', '0', '#'}
};

// Digitran keypad, bit numbers of PCF8574 i/o port
byte rowPins[ROWS] = {6, 5, 4, 3}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {0, 1, 2}; //connect to the column pinouts of the keypad
Keypad_I2C kpd = Keypad_I2C( makeKeymap(keys), rowPins, colPins, ROWS, COLS, I2CADDR );

// constants
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);


void setup() {
  Wire.begin( );
  Serial.begin(9600);
  kpd.begin();
  lcd.begin(16, 2);
  DisplayCodeEntryScreen();
  kpd.setDebounceTime(50);
  pinMode(openpin, OUTPUT);
  //  pinMode(lightsensor, INPUT);
  digitalWrite(openpin, LOW);


}

void loop()
{

  static byte currentState = PASSWORD_ENTRY;

  char key = kpd.getKey();

  switch (currentState)
  {
    case PASSWORD_ENTRY:
      // read keyboard input
      if (key)
      {
        inputArray[inputIndex++] = key;
        Serial.println(key);
        lcd.setCursor(inputIndex + 5, 1);
        lcd.print("*");
      }
      // if 4 digits entered, go to next state
      if (inputIndex == 4)
      {
        currentState = PASSWORD_VALIDATE;
      }
      break;
    case PASSWORD_VALIDATE:
      if (checkpass() == true)
      {
        currentState = ACCESS;
      }
      else
      {
        currentState = NOACCESS;
      }
      break;
    case ACCESS:
      digitalWrite(openpin, HIGH);
      if (access() == true)
      {
        currentState = WAIT_ANYKEY;
      }
      break;
    case NOACCESS:
      noaccess();
      currentState = WAIT_ANYKEY;
      break;
    case WAIT_ANYKEY:
      // 'clear' the array
      inputIndex = 0;
      // wait for key
      if (key)
      {
        key;
        currentState = PASSWORD_ENTRY;
        // lock door
        digitalWrite(openpin, LOW);
        // display code entry screen
        DisplayCodeEntryScreen();
      }
      break;
  }
}

bool access()
{
  static unsigned long startTime = 0;

  if (startTime == 0)
  {
    startTime = millis();
    lcd.setCursor(0, 0);
    lcd.print(" Access Granted ");
    lcd.setCursor(0, 1);
    lcd.print("                ");
    digitalWrite(openpin, HIGH);
  }
  else if (millis() - startTime >= 2000)
  {
    startTime = 0;
    lcd.setCursor(0, 0);
    lcd.print(" Press Any Key  ");
    lcd.setCursor(1, 1);
    lcd.print("    To Lock     ");

    // indicate that the 'delay' is finished
    return true;
  }

  // indicate that the 'delay' is not finished yet
  return false;
}

void DisplayCodeEntryScreen ()
{
  digitalWrite(openpin, LOW);
  lcd.clear();
  Serial.begin(9600);
  lcd.setCursor(0, 0);
  lcd.print("Enter Grow Code");


}

void noaccess()
{
  lcd.setCursor(0, 0);
  lcd.print(" Not Athorized  ");
  lcd.setCursor(0, 1);
  lcd.print(" Press Any Key  ");
}