Keypad Sequence check

Hi,

We have an escaperoom and we using some arduino's for puzzles.
For one puzzle the players must input a sequence of buttons (like an keypad with a code)

The players must select a few misprinted labels, if they choose al the wrong labels the puzzle is solved.
But most of the players starting with pressing some buttons.
After 7 clicks al de led buttons blinks 3 times, and the new input sequence starts.

Unfortunately most of the players doesn't understand this signal of failure/wrong input.

For example the code is 1234567
the input of the players is abc1234 -> led's blinks 3 times, new input is possible
the input of the players is 5671234 -> led's blinks 3 times, new input is possible
after every 7 inputs the arduino check if the input == code. if so -relay activated if not new input is possible.

What i'm looking for,
arduino checks after every input if last 7 inputs == code
for example input is abcd1234567abcd arduino checked the input and puzzle is solved.

My code at this moment is a simple keypad code.
note: we can't use an LCD or other LED's

hope you understand my question (with my bad english)
Hope you can help me

Greetz
Niels

Welcome to the group.

Use CTRL T to format your code.
Attach your ‘complete’ sketch between code tags, use the </> icon in the posting menu.
[code]Paste your sketch here[/code]

Show us a good schematic of your circuit.
Show us a good image of your wiring.
Give links to components.
Posting images:

Here is one method:

//A sketch that demonstrates turning ON a LED while a keypad button is held i.e. 'HOLD'
//and turning the LED OFF when the button is let go i.e. 'RELEASED'.
//Enter password then * or #
//LarryD
//17/04/03 ver 1.00
//17/07/29 ver 1.01  Added password
 
#include <Keypad.h>
 
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', '#'}
};
//                Row 0  1  2  3
byte rowPins[ROWS] = {4, 5, 6, 7}; //connect to the row pinouts of the keypad
//            Column  0    1    2
byte colPins[COLS] = {29, 28, 27}; //connect to the column pinouts of the keypad
 
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
 
//LOW on pin turns on LEDs
const byte ledPinWhite = 9; // +5V-----LED anode/cathode-----220R-----pin 9
const byte ledPinRed   = 8; // +5V-----LED anode/cathode-----220R-----pin 8
 
//Target password
unsigned int PassWord = 1234;
 
//Password number entered
unsigned int PW;
 
bool PWokay = false;
 
//******************************************************
void setup()
{
  Serial.begin(9600);
  pinMode(ledPinWhite, OUTPUT);
  pinMode(ledPinRed,  OUTPUT);
  digitalWrite(ledPinWhite, HIGH);      //Turn the LED OFF
  digitalWrite(ledPinRed,  HIGH);       //Turn the LED OFF
  keypad.addEventListener(keypadEvent); //Add an event listener for this keypad
  Serial.println("Enter a new password");
 
} //END of            s e t u p ( )
 
//******************************************************
void loop()
{
  char key = keypad.getKey();
  if (key)
  {
    Serial.print(key);
 
    //check for a valid password
    if ((key == '*' || key == '#') && PWokay == false)
    {
      if (PW == PassWord)
      {
        PWokay = true;
        Serial.println("");
        Serial.println("Password is okay.");
        Serial.println("You can use * or # to control the LEDs, hold 0 to reset.");
      }
 
      else
      {
        PWokay = false;
        PW = 0;
        Serial.println("");
        Serial.println("Password is bad.");
        Serial.println("Enter a new password");
      }
    }
 
    //assemble the password number
    if (PWokay == false && key >= '0' && key <= '9')
    {
        PW = PW * 10 + (key - '0');
    }
  }
 
} //END of            l o o p ( )
 
 
//******************************************************
void keypadEvent(KeypadEvent key)
{
  switch (keypad.getState())
  {
    //*********************
    //case PRESSED:
    //  {
    //  }
    //  break; //END of PRESSED
 
    //*********************
    case RELEASED:
      {
        switch (key)
        {
          //***************
          //only if there is a valid password
          case '*':
            if (PWokay == true)
            {
              {
                //LED OFF
                digitalWrite(ledPinWhite, HIGH);
              }
            }
            break;
 
          //***************
          //only if there is a valid password
          case '#':
            if (PWokay == true)
            {
              {
                //LED OFF
                digitalWrite(ledPinRed, HIGH);
              }
            }
            break;
 
        } //END of switch (key)
      }
      break; //END of RELEASED
 
    //*********************
    case HOLD:
      {
        switch (key)
        {
          //***************
          //only if there is a valid password
          case '*':
            if (PWokay == true)
            {
              {
                //LED ON
                digitalWrite(ledPinWhite, LOW);
              }
            }
            break;
 
          //***************
          //only if there is a valid password
          case '#':
            if (PWokay == true)
            {
              {
                //LED ON
                digitalWrite(ledPinRed, LOW);
              }
            }
            break;
 
          //***************
          //reset the lock
          case '0':
            {
              PWokay = false;
              PW = 0;
              Serial.println("");
              Serial.println("Enter a new password");
            }
            break;
 
        } //END of switch (key)
      }
      break; //END of HOLD
 
  } //END of switch (keypad.getState())
 
} //END of    k e y p a d E v e n  t ( )
 
//******************************************************

Unfortunately most of the players doesn’t understand this signal of failure/wrong input.

What instructions do you give them?

They must select wrong labels
They don’t know how much

I know that a Raspberry Pi can do this, but i want to use arduino’s because its easier to understand for me

My code at this moment is a simple keypad code.

Code you have not shared.

Use CTRL T to format your code.
Attach your ‘complete’ sketch between code tags, use the </> icon in the posting menu.

[code]Paste your sketch here[/code]

Show us a good schematic of your circuit.
Show us a good image of your wiring.
Give links to components.
Posting images:

Hope you can help me

Hope you can help us help you :wink:

The code offered to you in post #1 shows how a password can be handled.

Hi Thanks for your help, My code:
Note: The TM1637 Display isn’t connected anymore.

Everything works fine, but instead of “checking” the sequence after 7 inputs I want to check the sequence every time a button is pressed. So after a button on the keypad is pressed, the Arduino checks if the last 7 buttons == code

// INCLUDES
// 4-digit 7-segment LED Display library, download from https://github.com/avishorp/TM1637
#include <TM1637Display.h>
// Keypad library
#include <Keypad.h>

// DEFINES
#define DEBUG

// CONSTANTS
// Define the characters on the keypad layout
const char keys[4][4] = {
  {'1', '2', '3', 'a'},
  {'4', '5', '6', 'b'},
  {'7', '8', '9', 'c'},
  {'*', '0', '#', 'd'}
};
// Row pins
const byte keypadRowPins[4] = {6, 7, 8, 9};
// Column pins
const byte keypadColPins[4] = {2, 3, 4, 5};
// Pins which the relay modules are connected to
const byte relayPins[] = {10, 11, 12, 13};
// Clock pin for the display
const byte displayClockPin = A0;
// Data pin for the display
const byte displayDataPin = A1;

// GLOBALS
// Create a keypad input class from definitions above
Keypad keypad = Keypad( makeKeymap(keys), keypadRowPins, keypadColPins, 4, 4 );
// Create a display object, specifying pin parameters (Clock pin, Data pin)
TM1637Display display(displayClockPin, displayDataPin);
// Record the code which the user has entered
char data[] = "       ";
// What position through the code is being entered?
int sequenceNum = 0;


// Initial setup
void setup() {
  // Initialise serial communication if required for debugging
#ifdef DEBUG
  Serial.begin(9600);
#endif

  // Set brightness
  display.setBrightness(0x0c);

  // Initialise relay pins
  for (int i = 0; i < 4; i++) {
    digitalWrite(relayPins[i], LOW);
    pinMode(relayPins[i], OUTPUT);
  }
}



// Main Program Loop
void loop() {

  // Get the keypad input this frame
  char key = keypad.getKey();

  // Has a key been pressed?
  if (key) {

#ifdef DEBUG
    // Log it to the serial output
    Serial.println(key);
    digitalWrite(13, HIGH);
    delay(100);
    digitalWrite(13, LOW);
#endif

    // Set the current position of the code sequence to the key pressed
    data[sequenceNum] = key;
    // Increment the counter
    sequenceNum++;

    // Update the display to reflect the current sequence

    // If the player has entered all 4 digits of a code
    if (sequenceNum == 7) {

#ifdef DEBUG
      Serial.print(F("Code entered: "));
      // Log the whole code to the serial output
      Serial.println(data);
#endif

      // Take action based on the code entered
      if (strcmp(data, "71053ca") == 0) {
        digitalWrite(relayPins[0], HIGH);
        Serial.println("valt!");
        delay(2000);
        digitalWrite(relayPins[0], LOW);
        Serial.println("valt!");
        delay(2000);
        digitalWrite(13, HIGH);
      }

      // If none of the conditions above have matched, it's an unknown code
      else {

        // FLash the display
        Serial.println("Code Fout");
        digitalWrite(13, HIGH);
        delay(300);
        digitalWrite(13, LOW);
        delay(300);
        digitalWrite(13, HIGH);
        delay(300);
        digitalWrite(13, LOW);
        delay(300);
        digitalWrite(13, HIGH);
        delay(300);
        digitalWrite(13, LOW);
        delay(300);
      }

      // Clear the data array
      memset(data, 0, sizeof(data));
      sequenceNum = 0;


    }
  }
}

This is a poor way to initialize an array, because it is difficult to tell how large the array is:

char data[] = "       ";

Use something like this instead:

char data[7] = {0};

If you want to test the "last seven entries", the logic of your key entry loop needs to be changed completely. Right now, you accumulate seven entries, do the comparison, then start all over again from zero.

One approach might be to move the previous six entries down one index and add the last entry, before comparison. Another approach is to use a ring buffer, which requires a start and end pointer. In either case, having a "clear all" button is a good idea, to avoid user frustration.

I’ve modified your code and tried a ring buffer implementation as suggested by @jremington, check if works.

// INCLUDES
// 4-digit 7-segment LED Display library, download from https://github.com/avishorp/TM1637
#include <TM1637Display.h>
// Keypad library
#include <Keypad.h>

// DEFINES
#define DEBUG

// CONSTANTS
// Define the characters on the keypad layout
const char keys[4][4] = {
  {'1', '2', '3', 'a'},
  {'4', '5', '6', 'b'},
  {'7', '8', '9', 'c'},
  {'*', '0', '#', 'd'}
};
// Row pins
const byte keypadRowPins[4] = {6, 7, 8, 9};
// Column pins
const byte keypadColPins[4] = {2, 3, 4, 5};
// Pins which the relay modules are connected to
const byte relayPins[] = {10, 11, 12, 13};
// Clock pin for the display
const byte displayClockPin = A0;
// Data pin for the display
const byte displayDataPin = A1;

// GLOBALS
// Create a keypad input class from definitions above
Keypad keypad = Keypad( makeKeymap(keys), keypadRowPins, keypadColPins, 4, 4 );
// Create a display object, specifying pin parameters (Clock pin, Data pin)
TM1637Display display(displayClockPin, displayDataPin);

//
// INPUT RING BUFFER
//

#define RING_BUF_SIZE 7

char ringBuffer[RING_BUF_SIZE];
int ringStartPos = 0;
int ctCharInBuf = 0;

void resetRingBuffer()
{
	for(int i=0; i<RING_BUF_SIZE; i++)
		ringBuffer[i] = NO_KEY;
		
	ringStartPos = 0;
  ctCharInBuf = 0;	
}

bool ringBufferFull()
{
	return(ctCharInBuf >= 7);			
}

int nextBufPos(int pos)
{
	pos++;
	
	if (pos < RING_BUF_SIZE)
		return(pos);
		
	return(0);	
}

void incStartPos()
{
	ringStartPos = nextBufPos(ringStartPos);
}

void appendKey(char key)
{
  if (ringBufferFull())
  {
	  ringBuffer[ringStartPos] = key;

	  incStartPos();	

    return;
  }

  ringBuffer[ctCharInBuf] = key;
  ctCharInBuf++;  
}

void printRingBuffer()
{
	int j = ringStartPos;
	
	for(int i=0; i<RING_BUF_SIZE; i++)
	{
    char c = ringBuffer[j];
    
    if (c != NO_KEY)
		  Serial.print(c);
	  else
		  Serial.print(' ');	
			
		j=nextBufPos(j);
	}
			
	Serial.print('\n');
}

bool sequenceFound(const char *sequence)
{
	int j = ringStartPos;
	
	for(int i=0; i<RING_BUF_SIZE; i++)
	{
		if (ringBuffer[j] != sequence[i])
			return(false);
			
		j=nextBufPos(j);
	}
			
	return(true);		
}

//
// END RING BUFFER
//

// Initial setup
void setup() {
  // Initialise serial communication if required for debugging
#ifdef DEBUG
  Serial.begin(9600);
#endif

  // Set brightness
  display.setBrightness(0x0c);

  // Initialise relay pins
  for (int i = 0; i < 4; i++) {
    digitalWrite(relayPins[i], LOW);
    pinMode(relayPins[i], OUTPUT);
  }
  
  resetRingBuffer();
}

void checkNewSequence(char key)
{
#ifdef DEBUG
    // Log it to the serial output
    Serial.println(key);
    digitalWrite(13, HIGH);
    delay(100);
    digitalWrite(13, LOW);
#endif

	// append key to ring buffer
	appendKey(key);
	
	if (!ringBufferFull())
		// num keys pressed < 7
		return;

    // ring buffer full
    
#ifdef DEBUG
	Serial.print("Code: ");
	
	printRingBuffer();	 
#endif
	
    // Update the display to reflect the current sequence

    // If the player has entered all 7 digits of a code
    if (sequenceFound("71053ca")) 
    {
  		digitalWrite(relayPins[0], HIGH);
  		Serial.println("valt!");
  		delay(2000);
  		digitalWrite(relayPins[0], LOW);
  		Serial.println("valt!");
  		delay(2000);
  		digitalWrite(13, HIGH);
  		
  		return;
    }

    // unknown code

    // FLash the display
    Serial.println("Code Fout");
    digitalWrite(13, HIGH);
    delay(300);
    digitalWrite(13, LOW);
    delay(300);
    digitalWrite(13, HIGH);
    delay(300);
    digitalWrite(13, LOW);
    delay(300);
    digitalWrite(13, HIGH);
    delay(300);
    digitalWrite(13, LOW);
    delay(300);
}

// Main Program Loop
void loop() 
{
  // Get the keypad input this frame
  char key = keypad.getKey();

  // Has a key been pressed?
  if (key != NO_KEY)
  	checkNewSequence(key); 
}

vlc0617:
I've modified your code and tried a ring buffer implementation as suggested by @jremington, check if works.

Your code is great, It worked. Just one thing, I deleted the little blink sequence after the code was incorrect. (Just doesn't make sense anymore)

So thank you so much, I'm very happy with this