Clear string and process code

I am working on a security access point. I would like it to read an RFID and then enter my OTP. I have it kinda working. The OTP works great and it will scan the the RFID and hold in the buffer. It will not clear the buffer and will not run this section. I have included a full copy of the code as well.

  if(myserial.available() > 0) {
    BadgeRead[Index] = myserial.read();
       if (Badge[Index] == BadgeRead[Index])
           digitalWrite (powerPin, LED_ON);
           lcd.setCursor(0, 2);
           lcd.print("Good RFID");
#include <Arduino.h>
#include <RTClib.h>
#include <DS3231.h>
#include <Wire.h>
#include <RTClib.h>
#include <Time.h>
#include <sha1.h>
#include <TOTP.h>
#include <LiquidCrystal_I2C.h>
#include <i2ckeypad.h>
#include <SoftwareSerial.h>

DS3231 RTC;
LiquidCrystal_I2C lcd(0x27,20,4);
SoftwareSerial myserial(10, 11); // RX, TX

#define DS3231_I2C_ADDRESS 0x68
#define PCF8574_ADDR 0x20

#define ROWS 4
#define COLS 4

#define LED_ON LOW
#define LED_OFF HIGH

#define powerPin 3
#define passPin 4
#define failPin 2
#define relayPin 5

int z = 0;
int i = 0; //----- JUNK VARIABLE -----
long Idle_Count = 0; //----- IDLE TIME COUNTER -----
int Index = 0; //----- COUNTS EACH BYTE READ FROM RFID MODULE -----
int BadgeRead[14]; //----- STORES BYTES READ FROM RFID MODULE INTO AN ARRAY -----

i2ckeypad kpd = i2ckeypad(PCF8574_ADDR, ROWS, COLS);

// shared secret
uint8_t hmacKey[] = {0x34, 0x67, 0x78, 0x71, 0x40, 0x6d, 0x5a, 0x3b, 0x7e, 0x4e};
TOTP totp = TOTP(hmacKey, 10);

char totpCode[7];
char inputCode[7];
int inputCode_idx;

int Badge[14]  = {2, 48, 48, 48, 48, 67, 70, 55, 70, 56, 70, 51, 70, 3};// BADGE - 0013598607 207,32655

void setup() {

lcd.begin();
lcd.backlight();

Serial.begin(9600);
myserial.begin(9600);

pinMode(powerPin, OUTPUT);
pinMode(passPin, OUTPUT);
pinMode(failPin, OUTPUT);
pinMode(relayPin, OUTPUT);

digitalWrite(failPin, LED_OFF);
digitalWrite(passPin, LED_OFF);
digitalWrite(powerPin, LED_OFF);
digitalWrite(relayPin, LOW);

lcd.clear();
lcd.setCursor(0, 0);
lcd.print("One Time Password");
lcd.setCursor(0, 1);
lcd.print("Enter your Code");
 
Wire.begin();
kpd.init();
 
 // reset input buffer index
 inputCode_idx = 0;

}

void loop() {
 char key = kpd.get_key();
    
 // a key was pressed
 if (key != '\0') {

   // # resets the input buffer   
   if(key == '#') {
     lcd.setCursor(0, 2);
     lcd.print("Clear Buffer");
     inputCode_idx = 0; 
     memset(&BadgeRead, 0, 14);
     delay (1000);
     lcd.clear();
     lcd.setCursor(0, 0);
     lcd.print("One Time Password");
     lcd.setCursor(0, 1);
     lcd.print("Enter your Code");
     
   }
 
   else {     
    
     // save key value in input buffer
     inputCode[inputCode_idx++] = key;
    
     // if the buffer is full, add string terminator, reset the index
     // get the actual TOTP code and compare to the buffer's content
     if(inputCode_idx == 6) {
      
       inputCode[inputCode_idx] = '\0';
       inputCode_idx = 0;
      // lcd.setCursor(0, 2);
     // lcd.print("Code Entered: ");
      // lcd.setCursor(14, 2);
      // lcd.print(inputCode);
      
       RTCDateTime now = RTC.getDateTime();
       unsigned long GMT = now.unixtime;
       strcpy(totpCode,totp.getCode(GMT));
    
    //----- READ FROM RFID MODULE -----  
  if(myserial.available() > 0) {
    BadgeRead[Index] = myserial.read();
       if (Badge[Index] == BadgeRead[Index])
           digitalWrite (powerPin, LED_ON);
           lcd.setCursor(0, 2);
           lcd.print("Good RFID");
           
      // code is ok :)
       if(strcmp(inputCode, totpCode) == 0) {
         digitalWrite(failPin, LED_OFF);
         digitalWrite(powerPin, LED_OFF);
         digitalWrite(passPin, LED_ON);
         digitalWrite(relayPin, HIGH);
         lcd.setCursor(0, 3);
         lcd.print("Code ok");
         delay(4000);
         memset(&BadgeRead, 0, 14);
         digitalWrite(failPin, LED_OFF);
         digitalWrite(passPin, LED_OFF);
         //digitalWrite(powerPin, LED_ON);
         digitalWrite(relayPin, LOW);
         lcd.clear();
         lcd.setCursor(0, 0);
         lcd.print("One Time Password");
         lcd.setCursor(0, 1);
         lcd.print("Enter your Code");
        
       // code is wrong :( 
       } else {
         digitalWrite(failPin, LED_ON);
         digitalWrite(powerPin, LED_OFF);
         digitalWrite(passPin, LED_OFF);
         lcd.setCursor(0, 3);
         lcd.print("Correct Code: ");
         lcd.setCursor(14, 3);
         lcd.print(totpCode);
         delay(4000);
         memset(&BadgeRead, 0, 14);
         digitalWrite(failPin, LED_OFF);
         digitalWrite(passPin, LED_OFF);
         digitalWrite(powerPin, LED_ON);
         digitalWrite(relayPin, LOW);
         lcd.clear();
         lcd.setCursor(0, 0);
         lcd.print("One Time Password");
         lcd.setCursor(0, 1);
         lcd.print("Enter your Code");
         }
     }  else {
         digitalWrite(failPin, LED_ON);  
         lcd.setCursor(0, 3);
         lcd.print("Bad RFID");
         delay (4000);
         memset(&BadgeRead, 0, 14);
         digitalWrite(failPin, LED_OFF);
         digitalWrite(passPin, LED_OFF);
         digitalWrite(powerPin, LED_OFF);
         digitalWrite(relayPin, LOW);
         lcd.clear();
         lcd.setCursor(0, 0);
         lcd.print("One Time Password");
         lcd.setCursor(0, 1);
         lcd.print("Enter your Code");
     }
   }
 }
 }
}

The way your code is indented it is very hard to see what parts are within what other parts.

As well as that, because you have all the code in loop() it is virtually impossible to see the logic separately from the different actions. Have a look at the way code is organized into small functions in planning and implementing a program. With small single purpose functions each part can be tested on its own.

My guess is that some part is inside some other part where it should not be, or vice versa.

...R

Thank you Robin2 I am newer to coding. I am going to pull the RFID part out as a entry door that requires a RFID and a one time password is a little over kill. :slight_smile:

Would you mind helping me clean my code and may be a couple of the ideas I have below?
1). Create a 12 digit fail safe code if your phone dies or you left it in the house.
a). I have a 4x4 keypad so this option would fall under one of the letters being pressed.
2). A 5 minute count timer if you get the code wrong 3 times. (and display the timer on the display.)

Here is the code with out the RFID.

#include <Arduino.h>
#include <RTClib.h>
#include <DS3231.h>
#include <Wire.h>
#include <RTClib.h>
#include <Time.h>
#include <sha1.h>
#include <TOTP.h>
#include <LiquidCrystal_I2C.h>
#include <i2ckeypad.h>

DS3231 RTC;
LiquidCrystal_I2C lcd(0x27,20,4);

// I2C address assignment 
#define DS3231_I2C_ADDRESS 0x68
#define PCF8574_ADDR 0x20

// Define Keypad type
#define ROWS 4
#define COLS 4

// Define on/off output
#define LED_ON LOW
#define LED_OFF HIGH

// Define pin assignment
#define powerPin 3
#define passPin 4
#define failPin 2
#define relayPin 5

// setup I2C Keypad
i2ckeypad kpd = i2ckeypad(PCF8574_ADDR, ROWS, COLS);

// shared secret
uint8_t hmacKey[] = {0x34, 0x67, 0x78, 0x71, 0x40, 0x6d, 0x5a, 0x3b, 0x7e, 0x4e};
TOTP totp = TOTP(hmacKey, 10);

// Set-up Arrays
char totpCode[7];
char inputCode[7];
int inputCode_idx;

void setup() {

// Initialize LCD Screen 
lcd.begin();
lcd.backlight();

// Initialize Serial Ports
Serial.begin(9600);

// Define Pin Type
pinMode(powerPin, OUTPUT);
pinMode(passPin, OUTPUT);
pinMode(failPin, OUTPUT);
pinMode(relayPin, OUTPUT);

// Define Pin Value
digitalWrite(relayPin, LOW);
digitalWrite(powerPin, LED_ON);
digitalWrite(passPin, LED_OFF);
digitalWrite(failPin, LED_OFF);

// Welcome Screen on LCD
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("One Time Password");
lcd.setCursor(0, 1);
lcd.print("Enter your Code");
 
// Initialize Keypad and I2C
Wire.begin();
kpd.init();
 
 // reset input buffer index
 inputCode_idx = 0;

}

void loop() {
 char key = kpd.get_key();
    
 // a key was pressed
 if (key != '\0') {

   // # resets the input buffer   
   if(key == '#') {
     lcd.setCursor(0, 2);
     lcd.print("Cleared Memory");
     inputCode_idx = 0; 
     delay (1000);
     lcd.clear();
     lcd.setCursor(0, 0);
     lcd.print("One Time Password");
     lcd.setCursor(0, 1);
     lcd.print("Enter your Code");
     
   }
 
   else {     
    
     // save key value in input buffer
     inputCode[inputCode_idx++] = key;
    
     // if the buffer is full, add string terminator, reset the index
     // get the actual TOTP code and compare to the buffer's content
     if(inputCode_idx == 6) {
      
       inputCode[inputCode_idx] = '\0';
       inputCode_idx = 0;
       lcd.setCursor(0, 2);
       lcd.print("Code Entered: ");
       lcd.setCursor(14, 2);
       lcd.print(inputCode); 
      
       RTCDateTime now = RTC.getDateTime();
       unsigned long GMT = now.unixtime;
       strcpy(totpCode,totp.getCode(GMT));
           
      // code is ok :)
       if(strcmp(inputCode, totpCode) == 0) {
         digitalWrite(failPin, LED_OFF);
         digitalWrite(powerPin, LED_OFF);
         digitalWrite(passPin, LED_ON);
         digitalWrite(relayPin, HIGH);
         lcd.setCursor(0, 3);
         lcd.print("Access Granted");
         delay(4000);
         digitalWrite(failPin, LED_OFF);
         digitalWrite(passPin, LED_OFF);
         digitalWrite(powerPin, LED_ON);
         digitalWrite(relayPin, LOW);
         lcd.clear();
         lcd.setCursor(0, 0);
         lcd.print("One Time Password");
         lcd.setCursor(0, 1);
         lcd.print("Enter your Code");
        
       // code is wrong :( 
       } else {
         digitalWrite(powerPin, LED_OFF);
         digitalWrite(passPin, LED_OFF);
         digitalWrite(failPin, LED_ON);
		     lcd.setCursor(0, 3);
         lcd.print("Access Denied");
         //lcd.print("Correct Code: ");
         //lcd.setCursor(14, 3);
         //lcd.print(totpCode);
         delay(4000);
         digitalWrite(failPin, LED_OFF);
         digitalWrite(passPin, LED_OFF);
         digitalWrite(powerPin, LED_ON);
         digitalWrite(relayPin, LOW);
         lcd.clear();
         lcd.setCursor(0, 0);
         lcd.print("One Time Password");
         lcd.setCursor(0, 1);
         lcd.print("Enter your Code");
         }
       }
     }
   }
 }

Why have you this code repeated 3 times

lcd.clear();
         lcd.setCursor(0, 0);
         lcd.print("One Time Password");
         lcd.setCursor(0, 1);
         lcd.print("Enter your Code");

There are two issues here. If you do need to use the code in more than one place you should put it in a function such as

void askPWD() {
         lcd.clear();
         lcd.setCursor(0, 0);
         lcd.print("One Time Password");
         lcd.setCursor(0, 1);
         lcd.print("Enter your Code");
}

and then call it with

askPWD();

However, really, there should only be one place where that code is needed. The rest of the code should be organized so that it gets back to that place when a new password should be entered.
You could, perhaps, have the code in loop() as simple as this

void loop() {
  askPWD();
  receivePWD();
  checkPWD();
  openDoor();
}

That would require you to have a variable that keeps track of what is happening. For example a variable named pwdState could have the possible values 'N' for a new pwd, 'R' for receiving pwd , 'C' to check received pwd and 'O' for open door.

The the code for askPWD() could be like this

void askPWD() {
    if(pwdState == 'N') {
         pwdState = 'R';         // sets up the next section
         lcd.clear();
         lcd.setCursor(0, 0);
         lcd.print("One Time Password");
         lcd.setCursor(0, 1);
         lcd.print("Enter your Code");
     }
}

And deal with the other functions in the same way

...R