Password Library and Creating a Variable Integer

Hi, so this is part 2 of my security system/ chicken coop door monitor project. Right now I’m just focusing on the security system part. I’m having difficulty displaying the password as its being typed. I definitely think it has something to do with the int Position = 0. What I want to do is have the password displayed as ***** on the LCD. The way I think I can do this is by increasing the values of Position by 1 each time a button is pressed. I don’t think I implemented the Position part right (I probably messed up the password part too) and I’d really appreciate some help! If you have any questions about my code I’d be happy to clarify!

#include <Password.h>
#include <LiquidCrystal.h>
#include <Keypad.h>

Password password = Password( "1234" );

const byte ROWS = 4;
const byte COLS = 4;

char keys[ROWS][COLS] = {
  {'1', '2', '3'},
  {'4', '5', '6'},
  {'7', '8', '9'},
  {'*', '0', '#'}
};
byte rowPins[ROWS] = {3, 5, 6, 7};
byte colPins[COLS] = {8, 9, 10};

Keypad myKeypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

LiquidCrystal lcd(A0, A1, A2, A3, A4, A5);

void setup() {
  lcd.begin(16, 2);
  MainMenu();
  Serial.begin(9600);

}

void loop() {
  char myKey = myKeypad.getKey();
  Serial.print("Pressed: ");
  Serial.println(myKey);

  if (myKey == '#') {
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print(" Enter Password");
    int Position = 0;

    if (myKey == '0' || myKey == '1' || myKey == '2' || myKey == '3' ||
        myKey == '4' || myKey == '5' || myKey == '6' || myKey == '7' ||
        myKey == '8' || myKey == '9' ) {
      lcd.setCursor(Position, 1);
      lcd.print('*');
      ++Position;
    }
    if (Position == 5) {
      checkPassword();
      password.append(myKey);
    }
  }
}

void checkPassword() {
  if (password.evaluate()) {
    Serial.println("Success");

  } else {
    Serial.println("Wrong");
    password.reset();
  }
}

void MainMenu () {
  lcd.setCursor(0, 0);
  lcd.print("* for Coop");
  lcd.setCursor(0, 1);
  lcd.print("# for Security");
}

When key == ‘#’, it cannot be anything else (i.e. ‘0’, ‘1’, …)

Keep a variable in which mode you are (security or coop). It can be global (usually declared before setup()) or static in the function.

void loop()
{
  // mode; 0 is coop, 1 = security
  static byte mode = 0;

  char myKey = myKeypad.getKey();
  Serial.print("Pressed: ");
  Serial.println(myKey);

  if(key == '#')
  {
    mode = 1;
  }
  ...
  ...
}

How you get out of security mode is another question.

Now it might be a bit difficult to remember what 0 and 1 mean. Therefor you can use an enum or a #define which allows you to use sensible names; the below uses the latter.

// modes that application can be in
#define MODE_COOP 0
#define MODE_SECURITY 1

...
...
void setup()
{
  ...
  ...
}

void loop()
{
  // mode
  static byte mode = MODE_COPE;

  char myKey = myKeypad.getKey();
  Serial.print("Pressed: ");
  Serial.println(myKey);

  if(key == '#')
  {
    mode = MODE_SECURITY;
  }

  ...
  ...
}

And now you can test the mode variable and handle other keypresses

void loop()
{
  ...
  ...

  if (mode == MODE_SECURITY)
  {
    // test for the digits and verify password
    ...
    ...

  }
}

And just for your information, the below can be a lot shorter.

    if (myKey == '0' || myKey == '1' || myKey == '2' || myKey == '3' ||
        myKey == '4' || myKey == '5' || myKey == '6' || myKey == '7' ||
        myKey == '8' || myKey == '9' ) {

If you look at e.g. this ascii table, you will see that the digits 0…9 are consecutive (0x30…0x39). So instead of testing for every single value, you can check if the character is in range.

    if (myKey >= '0' && myKey <= '9')

Ok cool, thanks! I’ll put that into the code! Do you know how I can solve my int Position problem? I also didn’t set up the define modes right, the IDE wont compile its expecting a ‘)’ before ‘;’. Do I need to include a a byte thing along with the #define? Before this I was using boolean variables to say that the Coop’s Screen is being displayed, why is the static byte mode better than using the boolean varibles?

#include <Password.h>
#include <LiquidCrystal.h>
#include <Keypad.h>

#define ModeMainMenu 0;
#define ModeCoop 1;
#define ModeSecurity 2;

Password password = Password( "1234" );

const byte ROWS = 4;
const byte COLS = 4;

char keys[ROWS][COLS] = {
  {'1', '2', '3'},
  {'4', '5', '6'},
  {'7', '8', '9'},
  {'*', '0', '#'}
};
byte rowPins[ROWS] = {3, 5, 6, 7};
byte colPins[COLS] = {8, 9, 10};

Keypad myKeypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

LiquidCrystal lcd(A0, A1, A2, A3, A4, A5);

void setup() {
  lcd.begin(16, 2);
  MainMenu();
  Serial.begin(9600);

}

void loop() {

  char myKey = myKeypad.getKey();
  Serial.print("Pressed: ");
  Serial.println(myKey);

  if (myKey == '#') {
    static byte mode = ModeSecurity;
  }
  if (ModeSecurity) {
    if (myKey == '*') {
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("  Invalid Key  "
    }
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print(" Enter Password");

    int Position = 0;

    if (  if (myKey >= '0' && myKey <= '9') {
      lcd.setCursor(Position, 1);
        lcd.print('*');
        ++Position;
      }
    if (Position == 5) {
    checkPassword();
      password.append(myKey);
    }
  }
}

void checkPassword() {
  if (password.evaluate()) {
    Serial.println("Success");

  } else {
    Serial.println("Wrong");
    password.reset();
  }
}

void MainMenu () {
  lcd.setCursor(0, 0);
  lcd.print("* for Coop");
  lcd.setCursor(0, 1);
  lcd.print("# for Security");
}

Take the semicolons out at the end of the #define lines.

...an even better choice...

const byte ModeMainMenu = 0;
const byte ModeCoop = 1;
const byte ModeSecurity = 2;
  if (myKey == '#') {
    static byte mode = ModeSecurity;
  }

...scope trouble.

  if (ModeSecurity) {

ModeSecurity is a constant; the condition is always true. I suspect you meant...

  if (mode) {

So would the if statement be something like

If(mode == ModeSecurity){

So I how can I write this so it # makes the mode = ModeSecurity if its always true? Would it be easier to make these boolean and set them up at false?

if (myKey == '#') {
    static byte mode = ModeSecurity;
  }
  if (ModeSecurity) {
    if (myKey == '*') {
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("  Invalid Key  ");
    }
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print(" Enter Password");

    int Position = 0;

    if (myKey >= '0' && myKey <= '9') {
      lcd.setCursor(Position, 1);
        lcd.print('*');
        ++Position;
      }
    if (Position == 5) {
    checkPassword();
      password.append(myKey);
    }
  }

So I how can I write this so it # makes the mode = ModeSecurity if its always true?

You need to fix the issues in the order identified. Your mode variable, even though static, has way too small a scope.

Until you fix that, any talk about using mode is pointless.

I'm sorry, I don't understand what you mean by saying I have too small a scope.

If you define a variable outside of any function, it has global scope. That is, it can be seen, and used, anywhere, in any function, in the file.

If you define the variable in a function, it has local scope. That is, it can only be used by that function.

If you define the variable in a block, within a function (as you have done), it is visible ONLY in that block.

{
    static byte mode = ModeSecurity;
  }

There being no other code in the block, the variable is useless.

Please pay attention to where I defined the mode variable; definitely not inside an if block.

I prefer static variables; that makes them only accessible in the function where they are needed.

So would the if statement be something like

Yes.

I was under the impression that static byte mode = ModeSecurity; made mode become ModeSecurity.
So is this better?

static byte mode = ModeMainMenu;
  
  char myKey = myKeypad.getKey();
  Serial.print("Pressed: ");
  Serial.println(myKey);

  if (myKey == '#') {
    static byte mode = ModeSecurity;
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print(" Enter Password");
  }
  if (mode == ModeSecurity) {
    if (myKey == '*') {
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("  Invalid Key  ");
    }
   
    int Position = 0;
    if (myKey >= '0' && myKey <= '9') {
      lcd.setCursor(Position, 1);
        lcd.print('*');
        ++Position;
      }
    if (Position == 5) {
    checkPassword();
      password.append(myKey);
    }
  }

Watson221: So would the if statement be something like

If(mode == ModeSecurity){

Yes. (minus the typographical error "if" not "If") Sorry about that.

So I how can I write this so it # makes the mode = ModeSecurity if its always true?

if (myKey == '#') {
    mode = ModeSecurity;
}

Do I need the static byte?

if (myKey == '#') {
    mode = ModeSecurity;
}

VS

if (myKey == '#') {
  static byte mode = ModeSecurity;
}

Watson221: So is this better?

No.

This is a reasonable simplification of the code of interest...

static byte mode = 37;

void setup( void )
{
  Serial.begin( 250000 );

  // if (myKey == '#')
  {
    static byte mode = 99;
    Serial.println( mode );
  }

  Serial.println( mode );
  if (mode == 99)
  {
    Serial.println( mode );
  }
}

void loop( void ) { }

Your expected output is...

99
99
99

Run it. What do you actually get?

Watson221: Do I need the static byte?

Run the snippet above for the answer.

Ok thanks! I’ll try to get that implemented, but I need to go for a bit. Thanks for your help!

So I got this when I tried doing it the const byte way.

#include <Password.h>
#include <LiquidCrystal.h>
#include <Keypad.h>

const byte ModeMainMenu = 0;
const byte ModeCoop = 1;
const byte ModeSecurity = 2;


Password password = Password( "1234" );

const byte ROWS = 4;
const byte COLS = 4;

char keys[ROWS][COLS] = {
  {'1', '2', '3'},
  {'4', '5', '6'},
  {'7', '8', '9'},
  {'*', '0', '#'}
};
byte rowPins[ROWS] = {3, 5, 6, 7};
byte colPins[COLS] = {8, 9, 10};

Keypad myKeypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

LiquidCrystal lcd(A0, A1, A2, A3, A4, A5);

void setup() {
  lcd.begin(16, 2);
  MainMenu();
  Serial.begin(9600);

}

void loop() {

  static byte mode = ModeMainMenu;

  char myKey = myKeypad.getKey();
  Serial.print("Pressed: ");
  Serial.println(myKey);

  if (myKey == '#') {
    static byte mode = ModeSecurity;
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print(" Enter Password");
  }
  if (mode == ModeSecurity) {
    if (myKey == '*') {
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("  Invalid Key  ");
    }
    
    int Position = 0;
    if (myKey >= '0' && myKey <= '9') {
      lcd.setCursor(Position, 1);
      lcd.print('*');
      ++Position;
    }
    if (Position == 5) {
      checkPassword();
      password.append(myKey);
    }
  }
}

void checkPassword() {
  if (password.evaluate()) {
    Serial.println("Success");

  } else {
    Serial.println("Wrong");
    password.reset();
  }
}

void MainMenu () {
  lcd.setCursor(0, 0);
  lcd.print("* for Coop");
  lcd.setCursor(0, 1);
  lcd.print("# for Security");
}

And this when I tried doing it the boolean way

#include <Password.h>
#include <LiquidCrystal.h>
#include <Keypad.h>

Password password = Password( "1234" );

const byte ROWS = 4;
const byte COLS = 4;

boolean MainMenuMode = false;
boolean SecurityMode = false;
boolean CoopMode = false;

char keys[ROWS][COLS] = {
  {'1', '2', '3'},
  {'4', '5', '6'},
  {'7', '8', '9'},
  {'*', '0', '#'}
};
byte rowPins[ROWS] = {3, 5, 6, 7};
byte colPins[COLS] = {8, 9, 10};

Keypad myKeypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

LiquidCrystal lcd(A0, A1, A2, A3, A4, A5);

void setup() {

  lcd.begin(16, 2);
  MainMenu();
  Serial.begin(9600);
}

void loop() {
  char myKey = myKeypad.getKey();

  if (myKey == '#') {
    SecurityMode = true;
    lcd.setCursor(0, 1);
    lcd.print(" Enter Password");
  }

  if (SecurityMode = true) {
    int position = 0;
    if (myKey == '*') {
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("  Invalid Key  ");
    }

    int Position = 0;
    if (myKey >= '0' && myKey <= '9') {
      lcd.setCursor(Position, 1);
      lcd.print('*');
      ++Position;
    }
    if (Position == 5) {
      checkPassword();
      password.append(myKey);
    }
  }
}

void checkPassword() {
  if (password.evaluate()) {
    Serial.println("Success");

  } else {
    Serial.println("Wrong");
    password.reset();
  }
}



void MainMenu() {
  lcd.setCursor(0, 0);
  lcd.print("* for Coop");
  lcd.setCursor(0, 1);
  lcd.print("# for Security");
}

Did I implement these right?

Hi, since I’m only familiar with boolean stuff I made up this code. It works more or less as intended. The cursor moves with keypad presses and displays ******. The only thing I can’t seem to figure out is how to verify the password.

Here’s my full Code

#include <Password.h>
#include <LiquidCrystal.h>
#include <Keypad.h>
int a = 0;

Password password = Password( "1234" );

const byte ROWS = 4;
const byte COLS = 4;

boolean MainMenuMode = false;
boolean SecurityMode = false;
boolean CoopMode = false;


char keys[ROWS][COLS] = {
  {'1', '2', '3'},
  {'4', '5', '6'},
  {'7', '8', '9'},
  {'*', '0', '#'}
};
byte rowPins[ROWS] = {3, 5, 6, 7};
byte colPins[COLS] = {8, 9, 10};

Keypad myKeypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

LiquidCrystal lcd(A0, A1, A2, A3, A4, A5);

void setup() {

  lcd.begin(16, 2);
  MainMenu();
  Serial.begin(9600);
}

void loop() {
  char myKey = myKeypad.getKey();

  if (myKey == '#') {
    SecurityMode = true;
    SecurityScreen();
  }

  if (SecurityMode == true && myKey == '*') {
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("  Invalid Key  ");
    delay (2000);
    SecurityScreen();
  }
  else if (MainMenuMode == true && myKey == '*') {
    MainMenu(); //Replace with coop Door function down the line
  }

  if (SecurityMode == true) {
    if (myKey >= '0' && myKey <= '9') {
      lcd.setCursor(a, 1);
      lcd.print('*');
      a++;
    }
  }
  if (a == 4) {
    checkPassword();
    password.append(myKey);
  }
}

void checkPassword() {
  if (password.evaluate()) {
    Serial.println("Success");

  } else {
    Serial.println("Wrong");
    password.reset();
  }
}

void SecurityScreen() {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print(" Enter Password");
}

void MainMenu() {
  lcd.setCursor(0, 0);
  lcd.print("* for Coop");
  lcd.setCursor(0, 1);
  lcd.print("# for Security");
  MainMenuMode = true;
  SecurityMode = false;
  CoopMode = false;
}

And here’s the statement that controls the password checking.

if (SecurityMode == true && myKey == '*') {
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("  Invalid Key  ");
    delay (2000);
    SecurityScreen();
  }
  else if (MainMenuMode == true && myKey == '*') {
    MainMenu(); //Replace with coop Door function down the line
  }

  if (SecurityMode == true) {
    if (myKey >= '0' && myKey <= '9') {
      lcd.setCursor(a, 1);
      lcd.print('*');
      a++;
    }
  }
  if (a == 4) {
    checkPassword();
    password.append(myKey);
  }
}

void checkPassword() {
  if (password.evaluate()) {
    Serial.println("Success");

  } else {
    Serial.println("Wrong");
    password.reset();
  }
}

No you're not [u]only[/u] familiar with booleans. Else you would not be able to compare a key that you read with e.g. '#' or compare a with 4.

The disadvantage of multiple variables to indicate the mode is that, if you don't take care, more than one can be active. A mistake in your code can cause two or three of the modes to be active; having one variable prevents that.

I've never used the password library but I see in your code that there is an append method; wouldn't it be sensible to append the key that you read to the password when the key is read instead of when there are 4 keys read (a==4)?

The password library make's use of so-called c-strings; those are character arrays that are terminated with a null-character. So "1234" is stored in memory as 0x31 0x32 0x33 0x34 0x00. Before checking the password, you will have to add that null character.

Regardless of which mode you're in, you will do a checkPassword if a equals 4. And you will do that even before appending a key. And you will append a key even if none was read.

To be able to use the result of checkPassword() in loop(), you will have to let checkPassword return a value indicating that you can check in loop().

In the best of times it's not advisable to use single letter variable names. That even more applies if they have global scope; don't !! Currently you know what the variable a is used for; in a years time you don't and you have to dig though your code to find where it is used. I've counted the number of times that the letter a (not the variable) occurred in your code: 50 times :) So a simple search will not help too much. Give that variable a decent name (e.g. dispPos for display position or (possibly better) keypressCnt for key press count).