Help with using menu widget

Awesome, thank you I appreciate all of your help. The menu is working flawlessly. I learned a lot as well.

Hey Pete, just adding the database deletion mode now for case 3. I based it off of the other two cases that are working perfectly. Case 3 is meant to output some text to the terminal and run the databaseDeletion() function. I have tested the keypad code by itself and it works as I would like it to. The issue I’m having with the code below is that it doesn’t seem to wait and look for the user to use the keypad. No matter what I press or how many times I press it, nothing happens.

 // BLYNK template setup code
#define BLYNK_TEMPLATE_ID "TMPL07nDhxvy"
#define BLYNK_TEMPLATE_NAME "Arduino Uno Fingerprint Scanner"
#define BLYNK_AUTH_TOKEN "k6bccbIipGLrb-AZBJ4lBSuKG8gBqaJi"


/* Comment this out to disable prints and save space */
//#define BLYNK_PRINT Serial

// Initialize the libraries needed for the code
#include <Adafruit_Fingerprint.h>      // Fingerprint scanner
#include <ESP8266_Lib.h>               // Wifi shield
#include <BlynkSimpleShieldEsp8266.h>  // Blynk wifi
#include <Keypad.h>                    // 4x4 Keypad

// 4x4 Keypad matrix
const int ROW_NUM = 4;     // Four rows
const int COLUMN_NUM = 4;  // Four columns
char keys[ROW_NUM][COLUMN_NUM] = {
  { '1', '2', '3', 'A' },
  { '4', '5', '6', 'B' },
  { '7', '8', '9', 'C' },
  { '*', '0', '#', 'D' }
};
byte pin_rows[ROW_NUM] = { 28, 26, 24, 22 };       // Connect to the row pinouts of the keypad
byte pin_column[COLUMN_NUM] = { 29, 27, 25, 23 };  // Connect to the column pinouts of the keypad

Keypad keypad = Keypad(makeKeymap(keys), pin_rows, pin_column, ROW_NUM,
                       COLUMN_NUM);

// Length of password + 1 for null character
#define Password_Length 6
// Character to hold password input
char Data[Password_Length];
// Password to delete database
char Master[Password_Length] = "C001*";
// Counter for character entries
byte data_count = 0;
// Character to hold key input
char Key;

// WiFi credentials.
// Set password to "" for open networks.
char ssid[] = "xxxx";
char pass[] = "xxxx";

// Define the serials for communication
#define EspSerial Serial2          // Serial for ESP8266
#define FingerprintSerial Serial1  // Serial for Fingerprint Sensor

WidgetTerminal terminal(V1);  // Blynk terminal widget datastream V1
BlynkTimer timer;             // Blynk timer

Adafruit_Fingerprint finger = Adafruit_Fingerprint(&FingerprintSerial);  // Define fingerprint Scanner

uint8_t static fid = 1;       // Variable for finger ID *STARTS WITH 1 NO MATTER WHAT*
bool isFirstConnect = true;   // Flag to check if blynk was connected
bool clearterm = true;        // Flag to clear terminal
bool enrollMode = false;      // Flag for enrollment mode
bool enrollStep1 = true;      // Flag for step 1 of enrollment
bool enrollStep2 = true;      // Flag for step 2 of enrollment
bool enrollStep3 = true;      // Flag for step 3 of enrollment
bool enrollStep4 = true;      // Flag for step 4 of enrollment
bool noFing = true;           // Flag for no fingerprints in database
bool scanningMode = false;    // Flag for scanning mode
bool scanningSuccess = true;  // Flag for successful scan
bool scanningFailed = true;   // Flag for failed scan
bool deleteDatabase = false;  // Flag to delete database
int index;                    // Integer for mode selection

uint8_t readnumber(void) {
  uint8_t num = 0;

  while (num == 0) {
    while (!Serial.available())
      ;
    num = Serial.parseInt();
  }
  return num;
}

// ESP8266 baud rate:
#define ESP8266_BAUD 38400
ESP8266 wifi(&EspSerial);

// Enroll mode for fingerprint scanner
uint8_t getFingerprintEnroll() {

  int p = -1;
  Serial.print("Waiting for valid finger to enroll as #");
  Serial.println(fid);

  while (p != FINGERPRINT_OK) {
    p = finger.getImage();
    switch (p) {
      case FINGERPRINT_OK:
        Serial.println("Image taken");
        break;
      case FINGERPRINT_NOFINGER:
        Serial.println(".");
        return p;
      case FINGERPRINT_PACKETRECIEVEERR:
        Serial.println("Communication error");
        break;
      case FINGERPRINT_IMAGEFAIL:
        Serial.println("Imaging error");
        break;
      default:
        Serial.println("Unknown error");
        break;
    }
  }

  // OK success!

  p = finger.image2Tz(1);
  switch (p) {
    case FINGERPRINT_OK:
      Serial.println("Image converted");
      break;
    case FINGERPRINT_IMAGEMESS:
      Serial.println("Image too messy");
      return p;
    case FINGERPRINT_PACKETRECIEVEERR:
      Serial.println("Communication error");
      return p;
    case FINGERPRINT_FEATUREFAIL:
      Serial.println("Could not find fingerprint features");
      return p;
    case FINGERPRINT_INVALIDIMAGE:
      Serial.println("Could not find fingerprint features");
      return p;
    default:
      Serial.println("Unknown error");
      return p;
  }
  enrollStep1 = false;                 // Set enrollment step 1 flag
  while (!removeFingerPrompt()) { ; }  // Finger was successfully scanned for step 1, call removeFingerPrompt

  Serial.println("Remove finger");
  delay(2000);
  p = 0;
  while (p != FINGERPRINT_NOFINGER) {
    p = finger.getImage();
  }
  Serial.print("ID ");
  Serial.println(fid);
  p = -1;
  enrollStep2 = false;                // Set enrollment step 2 flag
  while (!placeFingerPrompt()) { ; }  // Image was successfully converted, call placeFingerPrompt
  Serial.println("Place same finger again");
  while (p != FINGERPRINT_OK) {
    p = finger.getImage();
    switch (p) {
      case FINGERPRINT_OK:
        Serial.println("Image taken");
        break;
      case FINGERPRINT_NOFINGER:
        Serial.print(".");
        break;
      case FINGERPRINT_PACKETRECIEVEERR:
        Serial.println("Communication error");
        break;
      case FINGERPRINT_IMAGEFAIL:
        Serial.println("Imaging error");
        break;
      default:
        Serial.println("Unknown error");
        break;
    }
  }
  enrollStep3 = false;                  // Set enrollment step 3 flag
  while (!removeFingerPrompt2()) { ; }  // Finger was successfully processed, call removeFingerPrompt2
  delay(1000);
  // OK success!

  p = finger.image2Tz(2);
  switch (p) {
    case FINGERPRINT_OK:
      Serial.println("Image converted");
      break;
    case FINGERPRINT_IMAGEMESS:
      Serial.println("Image too messy");
      return p;
    case FINGERPRINT_PACKETRECIEVEERR:
      Serial.println("Communication error");
      return p;
    case FINGERPRINT_FEATUREFAIL:
      Serial.println("Could not find fingerprint features");
      return p;
    case FINGERPRINT_INVALIDIMAGE:
      Serial.println("Could not find fingerprint features");
      return p;
    default:
      Serial.println("Unknown error");
      return p;
  }

  // OK converted!
  Serial.print("Creating model for #");
  Serial.println(fid);

  p = finger.createModel();
  if (p == FINGERPRINT_OK) {
    Serial.println("Prints matched!");
  } else if (p == FINGERPRINT_PACKETRECIEVEERR) {
    Serial.println("Communication error");
    return p;
  } else if (p == FINGERPRINT_ENROLLMISMATCH) {
    Serial.println("Fingerprints did not match");
    return p;
  } else {
    Serial.println("Unknown error");
    return p;
  }

  Serial.print("ID ");
  Serial.println(fid);
  p = finger.storeModel(fid);
  if (p == FINGERPRINT_OK) {
    Serial.println("Stored!");
    enrollMode = false;
    delay(1000);
  } else if (p == FINGERPRINT_PACKETRECIEVEERR) {
    Serial.println("Communication error");
    return p;
  } else if (p == FINGERPRINT_BADLOCATION) {
    Serial.println("Could not store in that location");
    return p;
  } else if (p == FINGERPRINT_FLASHERR) {
    Serial.println("Error writing to flash");
    return p;
  } else {
    Serial.println("Unknown error");
    return p;
  }
  enrollStep4 = false;            // Set enrollment step 4 flag
  while (!enrollSuccess()) { ; }  // Enrollment was successful, call enrollSuccess
  fid++;                          // Increase finger ID #

  return true;
}

// Scanning mode for fingerprint scanner
uint8_t getFingerprintID() {
  finger.getTemplateCount();

  if (finger.templateCount == 0) {
    noFing = false;            // Set no finger flag
    while (!noFinger()) { ; }  // No fingerprints enrolled, call noFinger
    Serial.print("Sensor doesn't contain any fingerprint data. Please run the 'enroll' example.");
  }
  uint8_t p = finger.getImage();
  switch (p) {
    case FINGERPRINT_OK:
      Serial.println("Image taken");
      break;
    case FINGERPRINT_NOFINGER:
      Serial.println("No finger detected");
      return p;
    case FINGERPRINT_PACKETRECIEVEERR:
      Serial.println("Communication error");
      return p;
    case FINGERPRINT_IMAGEFAIL:
      Serial.println("Imaging error");
      return p;
    default:
      Serial.println("Unknown error");
      return p;
  }

  // OK success!

  p = finger.image2Tz();
  switch (p) {
    case FINGERPRINT_OK:
      Serial.println("Image converted");
      break;
    case FINGERPRINT_IMAGEMESS:
      Serial.println("Image too messy");
      return p;
    case FINGERPRINT_PACKETRECIEVEERR:
      Serial.println("Communication error");
      return p;
    case FINGERPRINT_FEATUREFAIL:
      Serial.println("Could not find fingerprint features");
      return p;
    case FINGERPRINT_INVALIDIMAGE:
      Serial.println("Could not find fingerprint features");
      return p;
    default:
      Serial.println("Unknown error");
      return p;
  }

  // OK converted!
  p = finger.fingerSearch();
  if (p == FINGERPRINT_OK) {
    Serial.println("Found a print match!");
  } else if (p == FINGERPRINT_PACKETRECIEVEERR) {
    Serial.println("Communication error");
    return p;
  } else if (p == FINGERPRINT_NOTFOUND) {
    scanningFailed = false;
    while (!scanFailed()) { ; }
    Serial.println("Did not find a match");
    return p;
  } else {
    Serial.println("Unknown error");
    return p;
  }

  // Found a match!
  scanningSuccess = false;      // Set flag for successful scan
  while (!scanSuccess()) { ; }  // Successful scan, call scanSuccess
  Serial.print("Found ID #");
  Serial.print(finger.fingerID);
  Serial.print(" with confidence of ");
  Serial.println(finger.confidence);

  return finger.fingerID;
}

void clearData() {
  // Go through array and clear data
  while (data_count != 0) {
    Data[data_count--] = 0;
  }
  return;
}

void databaseDeletion() {
  Serial.println("I GOT HERE!");
  Key = keypad.getKey();
  if (Key) {
    Data[data_count] = Key;
    Serial.println(Data[data_count]);
    Blynk.virtualWrite(V1, Data[data_count]);
    data_count++;
  }
  if (data_count == Password_Length - 1) {
    if (!strcmp(Data, Master)) {
      // Password is correct
      Blynk.virtualWrite(V1, "Correct!");
      Blynk.virtualWrite(V1, "Deleting fingerprint database.");
      finger.LEDcontrol(FINGERPRINT_LED_BREATHING, 100, FINGERPRINT_LED_RED);
      delay(2000);
      finger.emptyDatabase();
      Blynk.virtualWrite(V1, "Database deleted.");
      Blynk.virtualWrite(V1, "To return to desired mode, switch using mode selection menu.");
      finger.LEDcontrol(FINGERPRINT_LED_OFF, 0, FINGERPRINT_LED_RED);
      fid = 1;
    } else {
      // Password is incorrect
      Blynk.virtualWrite(V1, "Incorrect Password!");
      delay(1000);
    }
  }
  clearData();
  deleteDatabase = false;
}

// Clear Blynk Terminal
boolean CLEARTERMINAL() {
  if (!clearterm) {
    Blynk.virtualWrite(V1, " ");
    Blynk.virtualWrite(V1, " ");
    Blynk.virtualWrite(V1, " ");
    Blynk.virtualWrite(V1, " ");
    Blynk.virtualWrite(V1, " ");
    Blynk.virtualWrite(V1, " ");
    Blynk.virtualWrite(V1, " ");
    Blynk.virtualWrite(V1, " ");
    Blynk.virtualWrite(V1, " ");
    Blynk.virtualWrite(V1, " ");
    Blynk.virtualWrite(V1, " ");
    Blynk.virtualWrite(V1, " ");
    Blynk.virtualWrite(V1, " ");
    Blynk.virtualWrite(V1, " ");
    Blynk.virtualWrite(V1, " ");
    Blynk.virtualWrite(V1, " ");
    Blynk.virtualWrite(V1, " ");
    clearterm = true;
  }
  return true;
}

// Send text to terminal, control scanner LED. Called when scanning mode is initialized without any fingerprints enrolled.
boolean noFinger() {
  if (!noFing) {
    Blynk.virtualWrite(V1, "Sensor doesn't contain any fingerprint data. Please run the 'enroll' mode.");
    finger.LEDcontrol(FINGERPRINT_LED_FLASHING, 25, FINGERPRINT_LED_RED, 10);
    delay(2000);
    finger.LEDcontrol(FINGERPRINT_LED_OFF, 0, FINGERPRINT_LED_RED);
    noFing = true;
  }
  return true;
}

// Send text to terminal, control scanner LED. Called when the user needs to remove their finger to continue the enrollment process.
boolean removeFingerPrompt() {
  if (!enrollStep1) {
    finger.LEDcontrol(FINGERPRINT_LED_OFF, 0, FINGERPRINT_LED_PURPLE);
    Blynk.virtualWrite(V1, "Remove finger.");
    Blynk.virtualWrite(V1, "Prepare to place same finger again when prompted.");
    enrollStep1 = true;
  }
  return true;
}

// Send text to terminal, control scanner LED. Called when the user needs to place their finger again to continue the enrollment process.
boolean placeFingerPrompt() {
  if (!enrollStep2) {
    finger.LEDcontrol(FINGERPRINT_LED_ON, 0, FINGERPRINT_LED_PURPLE);
    Blynk.virtualWrite(V1, "Place the same finger again.");
    enrollStep2 = true;
  }
  return true;
}

// Send text to terminal, control scanner LED. Called when the user needs to remove their finger to finish the enrollment process.
boolean removeFingerPrompt2() {
  if (!enrollStep3) {
    finger.LEDcontrol(FINGERPRINT_LED_OFF, 0, FINGERPRINT_LED_PURPLE);
    Blynk.virtualWrite(V1, "Remove finger.");
    enrollStep3 = true;
  }
  return true;
}

// Send text to terminal, control scanner LED. Called when the enrollment process was a success.
boolean enrollSuccess() {
  if (!enrollStep4) {
    String fing = String(fid);
    finger.LEDcontrol(FINGERPRINT_LED_FLASHING, 25, FINGERPRINT_LED_PURPLE, 10);
    Blynk.virtualWrite(V1, "Successfully enrolled fingerprint id #" + fing + ".");
    delay(2000);
    finger.LEDcontrol(FINGERPRINT_LED_OFF, 0, FINGERPRINT_LED_PURPLE);
    enrollStep4 = true;
  }
  return true;
}

// Send text to terminal, control scanner LED. Called when there was a successful scan in the scanning mode.
boolean scanSuccess() {
  if (!scanningSuccess) {
    Blynk.virtualWrite(V1, "Print found, success!");
    scanningSuccess = true;
    finger.LEDcontrol(FINGERPRINT_LED_ON, 0, FINGERPRINT_LED_BLUE);
    delay(2000);
    finger.LEDcontrol(FINGERPRINT_LED_OFF, 0, FINGERPRINT_LED_BLUE);
  }
  return true;
}

// Send text to terminal, control scanner LED. Called when there was a failed scan in the scanning mode.
boolean scanFailed() {
  if (!scanningFailed) {
    Blynk.virtualWrite(V1, "Print not found, Failed!");
    finger.LEDcontrol(FINGERPRINT_LED_ON, 0, FINGERPRINT_LED_RED);
    delay(2000);
    finger.LEDcontrol(FINGERPRINT_LED_OFF, 0, FINGERPRINT_LED_RED);
  }
  return true;
}

void modeSelection() {
  String fing = String(fid);  // Create fing to set fid to a string in order to pass through terminal.
  switch (index) {            // Switch selections
    case 1:                   // Enroll mode
      {
        Serial.println("case option 1 was selected");
        if (!enrollMode) {
          Serial.println("ENROLL PROMPT HASN'T BEEN DISPLAYED");
          clearterm = false;
          while (!CLEARTERMINAL()) { ; }
          // terminal.clear();

          scanningMode = false;
          finger.LEDcontrol(FINGERPRINT_LED_OFF, 0, FINGERPRINT_LED_PURPLE);
          Blynk.virtualWrite(V1, "To switch modes please use mode selection menu on admin dashboard/application.");
          Blynk.virtualWrite(V1, "If you would like to wipe the database, press the delete button.");
          Blynk.virtualWrite(V1, "Ready to enroll a fingerprint!");
          Blynk.virtualWrite(V1, "Enrolling ID #" + fing + ".");
          Blynk.virtualWrite(V1, "Waiting for valid finger to enroll as #" + fing + ".");
          Serial.print("Enrolling ID #");
          Serial.println(fid);
          finger.LEDcontrol(FINGERPRINT_LED_ON, 0, FINGERPRINT_LED_PURPLE);
          enrollMode = true;
        }
        while (!getFingerprintEnroll())
          ;
        delay(300);
        break;
      }
    case 2:  // Scanning mode
      {
        Serial.println("case option 2 was selected");
        if (!scanningMode) {
          Serial.println("SCAN PROMPT HASN'T BEEN DISPLAYED");
          clearterm = false;
          while (!CLEARTERMINAL()) { ; }
          // terminal.clear();

          enrollMode = false;
          finger.LEDcontrol(FINGERPRINT_LED_OFF, 0, FINGERPRINT_LED_PURPLE);
          Blynk.virtualWrite(V1, "To switch modes please use mode selection menu on admin dashboard/application.");
          Blynk.virtualWrite(V1, "If you would like to wipe the database, press the delete button.");
          Blynk.virtualWrite(V1, "Scanning, waiting for fingerprint.");
          scanningMode = true;
          Serial.println("SCAN PROMPT HAS BEEN DISPLAYED");
        }
        getFingerprintID();
        delay(300);
        break;
      }
    case 3:
      {
        Serial.println("case option 3 was selected");
        if (!deleteDatabase) {
          Serial.println("DELETE PROMPT HASN'T BEEN DISPLAYED");
          clearterm = false;
          while (!CLEARTERMINAL()) { ; }
          Blynk.virtualWrite(V1, "Enter password, press '#' when finished.");
          deleteDatabase = true;
          Serial.println("DELETE PROMPT HAS BEEN DISPLAYED");
          Serial.println("THIS SHOULD STOP THE TERMINAL FROM PRINTING THIS AGAIN.");
        }
        databaseDeletion();
        delay(300);
        break;
      }
    default:  // If there is no selection
      Blynk.virtualWrite(V1, "Please make a selection.");
  }
}

// Callback function that triggers when the device connects or re-connects to the Blynk server
BLYNK_CONNECTED() {
  Serial.println("BLYNK_CONNECTED triggered");
  Blynk.syncVirtual(V0);
}


BLYNK_WRITE(V0)  // Triggerd when Menu widget value changes or Blynk.syncVirtual(V0) is called
{
  Serial.println("BLYNK_WRITE(V0) triggered");
  index = param.asInt();  // Get status of V0.
  Serial.print("index = ");
  Serial.println(index);
  modeSelection();
}

void setup() {
  // Debug console
  Serial.begin(115200);

  // Set ESP8266 baud rate
  Serial2.begin(ESP8266_BAUD);
  delay(10);

  // Set the data rate for the sensor serial port
  finger.begin(57600);

  Serial.println(F("Reading sensor parameters"));
  finger.getParameters();
  Serial.print(F("Status: 0x"));
  Serial.println(finger.status_reg, HEX);
  Serial.print(F("Sys ID: 0x"));
  Serial.println(finger.system_id, HEX);
  Serial.print(F("Capacity: "));
  Serial.println(finger.capacity);
  Serial.print(F("Security level: "));
  Serial.println(finger.security_level);
  Serial.print(F("Device address: "));
  Serial.println(finger.device_addr, HEX);
  Serial.print(F("Packet len: "));
  Serial.println(finger.packet_len);
  Serial.print(F("Baud rate: "));
  Serial.println(finger.baud_rate);

  finger.getTemplateCount();

  if (finger.templateCount == 0) {
    Serial.print("Sensor doesn't contain any fingerprint data. Please run the 'enroll' example.");
  } else {
    Serial.print("Sensor contains ");
    Serial.print(finger.templateCount);
    Serial.println(" templates");
  }

  // Connect to Blynk
  Blynk.begin(BLYNK_AUTH_TOKEN, wifi, ssid, pass, "blynk.cloud", 80);

  timer.setInterval(5000L, modeSelection);  // Timer interval, every 5 seconds
}


void loop() {
  Blynk.run();
  timer.run();
}

The serial output I get if I upload the code while in the delete mode is this:

Reading sensor parameters
Status: 0x0
Sys ID: 0x0
Capacity: 200
Security level: 3
Device address: FFFFFFFF
Packet len: 128
Baud rate: 57600
Sensor contains 3 templates
BLYNK_CONNECTED triggered
BLYNK_WRITE(V0) triggered
index = 3
case option 3 was selected
DELETE PROMPT HASN'T BEEN DISPLAYED
DELETE PROMPT HAS BEEN DISPLAYED
THIS SHOULD STOP THE TERMINAL FROM PRINTING THIS AGAIN.
I GOT HERE!
case option 3 was selected
DELETE PROMPT HASN'T BEEN DISPLAYED
DELETE PROMPT HAS BEEN DISPLAYED
THIS SHOULD STOP THE TERMINAL FROM PRINTING THIS AGAIN.
I GOT HERE!

It seems to enter the function to delete the database is it outputs “I GOT HERE!” but doesn’t wait for the user to use the keypad. I feel like it’s because of the timer, I’m not sure. Is there any way for me to pause the timer once I enter that function?

Thank you

Please add triple backticks to your serial output.

Pete.

I believe I did, I have three “```” before and after my code and serial output.

Apologies, your text messages are confusing the forum software and causing it to colourise some words.

I’m guessing that the issue is with the way that this code works…

I’m not familiar with the keypad library that you’re using, so don’t know how it handles this type of command.

Pete.