Help with using menu widget

But at tie point when you are doing this, you don’t yet have a valid fingerprint scanned.

So are you saying that terminal.clear() is not working correctly?

Pete.

I initialize the fingerprint id “fid” using:

String fing = String(fid);

Once the finger is successfully scanned it will add 1 and continue to enroll finger 2. I am not too concerned with overwriting existing ones upon restart.

Yes, terminal.clear() was just outputting “clr” as text into the terminal for me, not actually clearing the terminal. If I get the menu working with I can show you.

uint8_t static fid = 1;
I meant to quote this, not the one I quoted above.

Still doesn’t make any sense to me.

Pete.

It’s a variable for the adafruit sensor, just an integer. In the example sketch for enrolling fingerprints, it just initializes that variable without a value and the user chooses a number by typing into the serial monitor. I was having trouble getting user input from the terminal instead of the serial monitor so I decided to set the variable to 1 and add 1 to it each time a finger was successfully enrolled.

[Unformatted code removed by moderator]

Sorry if I am unclear. I am pretty new to this stuff, especially working with this many libraries and different pieces of equipment. Can you point me to an example of a good timer and callback function to use?

When you post code to the forum it needs to have triple backticks at the beginning and end, not blockquotes.

and that’s my point. at the point when the code I quoted is called, this has not happened.

I can see that. All of the stuff you’re doing with workarounds on top of workarounds inst helping you, its just making your code more complex. The lack of in-code documentation and the use of obscure variable names doesn’t help either.

Not specifically about what you’re trying to do, but a good primer nonetheless…

Reading this may also help…

Pete.

Pete,

Thanks to you I have finally made some progress with this menu widget. I tried to clean my code up some by adding additional comments and removing some functions that I am not using at the moment. Currently, here’s what I have:

// 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
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[] = "xxxxxx";
char pass[] = "xxxxx";

// 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

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;
}

// 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' example.");
    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;
}

// Callback function to check V0 status
void V0check() {
  Blynk.syncVirtual(V0);
}

// Callback function to check if the blynk was connected
// BLYNK_CONNECTED() {
//   if (isFirstConnect) {
//     Blynk.syncVirtual(V0);
//     isFirstConnect = false;
//   }
// }

BLYNK_WRITE(V0)  // Menu widget
{
  int index = param.asInt();  // Get status of V0.
  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
      {
        if (!enrollMode) {
          clearterm = false;
          while (!CLEARTERMINAL()) { ; }
          scanningMode = false;
          finger.LEDcontrol(FINGERPRINT_LED_OFF, 0, FINGERPRINT_LED_PURPLE);
          Blynk.virtualWrite(V1, "To switch modes please use switch on admin dashboard/application.");
          Blynk.virtualWrite(V1, "If switching modes, please be patient as this process could take up to 30 seconds.");
          Blynk.virtualWrite(V1, "If you would like to wipe the database, press the delete button.");
          Blynk.virtualWrite(V1, "Ready to enroll a fingerprint!");
          Serial.print("Enrolling ID #");
          Blynk.virtualWrite(V1, "Enrolling ID #" + fing);
          Serial.println(fid);
          Blynk.virtualWrite(V1, "Waiting for valid finger to enroll as #" + fing);
          finger.LEDcontrol(FINGERPRINT_LED_ON, 0, FINGERPRINT_LED_PURPLE);
          enrollMode = true;
        }
        while (!getFingerprintEnroll())
          ;
        delay(300);
        break;
      }
    case 2:  // Scanning mode
      {
        if (!scanningMode) {
          clearterm = false;
          while (!CLEARTERMINAL()) { ; }
          enrollMode = false;
          finger.LEDcontrol(FINGERPRINT_LED_OFF, 0, FINGERPRINT_LED_PURPLE);
          Blynk.virtualWrite(V1, "To switch modes please use switch on admin dashboard/application.");
          Blynk.virtualWrite(V1, "If switching modes, please be patient as this process could take up to 30 seconds.");
          Blynk.virtualWrite(V1, "If you would like to wipe the database, press the delete button.");
          Blynk.virtualWrite(V1, "Scanning, waiting for fingerprint.");
          scanningMode = true;
        }
        getFingerprintID();
        delay(300);
        break;
      }
    case 3:
      {
        break;
      }
    default:  // If there is no selection
      Blynk.virtualWrite(V1, "Please make a selection.");
  }
}

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

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

  // Blnk auth tokens
  Blynk.begin(BLYNK_AUTH_TOKEN, wifi, ssid, pass, "blynk.cloud", 80);

  // 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");
  }
  timer.setInterval(5000L, V0check);  // Timer interval, every 5 seconds
}

void loop() {
  Blynk.run();
  timer.run();
  // You can inject your own code or combine it with other sketches.
  // Check other examples on how to communicate with Blynk. Remember
  // to avoid delay() function!
}

I had to comment out the BLYNK_CONNECTED() because when I had that in there it would skip the initialization of the fingerprint scanner and it would not work. With that commented out, it works… but very patchy I guess is the word. It takes a couple seconds for the fingerprint scanner to detect a finger now. Additionally, if there isn’t a finger on the scanner for either case 1 or 2, after about 3 seconds of waiting it will begin to return “communication error” in the serial monitor which is one of the error escapes from getFingerprintEnroll(). This will happen at any step of the enrollment process or scanning proccess. It WILL work if I leave my finger on the scanner for a few seconds, but I’m not sure whats triggering the error. It does switch modes very quickly though.

Many Thanks

Correction, it only outputs the communication error once you enter the getFingerprintEnroll() while statement. Basically once it detects a finger and passes the enrollStep1 while waiting for a finger it will output the error.

I dont think youve taken onboard anything I’ve said so far.

You have to stop calling Blynk.suncVirtual(V0) from within your main code.
This command should be called once only, at startup.

And your BLYNK_WRITE(V0) should contain around two lines of code:

  1. get the incoming value from the menu widget and assign it to a GLOBAL variable
  2. call a new function which contains all of the code currently in BLYNK_WRITE(V0). This line of code is optional, as your new function will be called by a BlynkTimer, but saves you having to wait while the timer kicks-in.

Pete.

Sorry, now I believe I understand what you mean. Everything above this is the same, I just added a function called modeSelection() above the V0check().

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
      {
        if (!enrollMode) {
          clearterm = false;
          while (!CLEARTERMINAL()) { ; }
          scanningMode = false;
          finger.LEDcontrol(FINGERPRINT_LED_OFF, 0, FINGERPRINT_LED_PURPLE);
          Blynk.virtualWrite(V1, "To switch modes please use switch on admin dashboard/application.");
          Blynk.virtualWrite(V1, "If switching modes, please be patient as this process could take up to 30 seconds.");
          Blynk.virtualWrite(V1, "If you would like to wipe the database, press the delete button.");
          Blynk.virtualWrite(V1, "Ready to enroll a fingerprint!");
          Serial.print("Enrolling ID #");
          Blynk.virtualWrite(V1, "Enrolling ID #" + fing);
          Serial.println(fid);
          Blynk.virtualWrite(V1, "Waiting for valid finger to enroll as #" + fing);
          finger.LEDcontrol(FINGERPRINT_LED_ON, 0, FINGERPRINT_LED_PURPLE);
          enrollMode = true;
        }
        while (!getFingerprintEnroll())
          ;
        delay(300);
        break;
      }
    case 2:  // Scanning mode
      {
        if (!scanningMode) {
          clearterm = false;
          while (!CLEARTERMINAL()) { ; }
          enrollMode = false;
          finger.LEDcontrol(FINGERPRINT_LED_OFF, 0, FINGERPRINT_LED_PURPLE);
          Blynk.virtualWrite(V1, "To switch modes please use switch on admin dashboard/application.");
          Blynk.virtualWrite(V1, "If switching modes, please be patient as this process could take up to 30 seconds.");
          Blynk.virtualWrite(V1, "If you would like to wipe the database, press the delete button.");
          Blynk.virtualWrite(V1, "Scanning, waiting for fingerprint.");
          scanningMode = true;
        }
        getFingerprintID();
        delay(300);
        break;
      }
    case 3:
      {
        break;
      }
    default:  // If there is no selection
      Blynk.virtualWrite(V1, "Please make a selection.");
  }
}

// Callback function to check V0 status
void V0check() {
  modeSelection();
}

// Callback function to check if the blynk was connected
BLYNK_CONNECTED() {
  if (isFirstConnect) {
    Blynk.syncVirtual(V0);
    isFirstConnect = false;
  }
}

BLYNK_WRITE(V0)  // Menu widget
{
  index = param.asInt();  // Get status of V0.
  modeSelection();  
}

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

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

  // Blnk auth tokens
  Blynk.begin(BLYNK_AUTH_TOKEN, wifi, ssid, pass, "blynk.cloud", 80);

  // 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");
  }
  timer.setInterval(5000L, V0check);  // Timer interval, every 5 seconds
}

void loop() {
  Blynk.run();
  timer.run();
  // You can inject your own code or combine it with other sketches.
  // Check other examples on how to communicate with Blynk. Remember
  // to avoid delay() function!
}

I tried to implement this and I am having the same issue as I did before when I had BLYNK_CONNECTED() uncommented. It seems to never initialize the fingerprint scanner and it gets stuck in a loop outputting “communication error”.

Please post the full sketch, not snippets.

Posting the actual seral output, formatted with triple backticks, would probably provide more insight into the issue than the information you’ve provided so far.

Pete.

Okay. Sorry for making this rough for you :man_facepalming:

// 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
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[] = "xxxxxx";
char pass[] = "xxxxxx";

// 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
int index;

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;
}

// 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' example.");
    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
      {
        if (!enrollMode) {
          clearterm = false;
          while (!CLEARTERMINAL()) { ; }
          scanningMode = false;
          finger.LEDcontrol(FINGERPRINT_LED_OFF, 0, FINGERPRINT_LED_PURPLE);
          Blynk.virtualWrite(V1, "To switch modes please use switch on admin dashboard/application.");
          Blynk.virtualWrite(V1, "If switching modes, please be patient as this process could take up to 30 seconds.");
          Blynk.virtualWrite(V1, "If you would like to wipe the database, press the delete button.");
          Blynk.virtualWrite(V1, "Ready to enroll a fingerprint!");
          Serial.print("Enrolling ID #");
          Blynk.virtualWrite(V1, "Enrolling ID #" + fing);
          Serial.println(fid);
          Blynk.virtualWrite(V1, "Waiting for valid finger to enroll as #" + fing);
          finger.LEDcontrol(FINGERPRINT_LED_ON, 0, FINGERPRINT_LED_PURPLE);
          enrollMode = true;
        }
        while (!getFingerprintEnroll())
          ;
        delay(300);
        break;
      }
    case 2:  // Scanning mode
      {
        if (!scanningMode) {
          clearterm = false;
          while (!CLEARTERMINAL()) { ; }
          enrollMode = false;
          finger.LEDcontrol(FINGERPRINT_LED_OFF, 0, FINGERPRINT_LED_PURPLE);
          Blynk.virtualWrite(V1, "To switch modes please use switch on admin dashboard/application.");
          Blynk.virtualWrite(V1, "If switching modes, please be patient as this process could take up to 30 seconds.");
          Blynk.virtualWrite(V1, "If you would like to wipe the database, press the delete button.");
          Blynk.virtualWrite(V1, "Scanning, waiting for fingerprint.");
          scanningMode = true;
        }
        getFingerprintID();
        delay(300);
        break;
      }
    case 3:
      {
        break;
      }
    default:  // If there is no selection
      Blynk.virtualWrite(V1, "Please make a selection.");
  }
}

// Callback function to check V0 status
void V0check() {
  modeSelection();
}

// Callback function to check if the blynk was connected
BLYNK_CONNECTED() {
  if (isFirstConnect) {
    Blynk.syncVirtual(V0);
    isFirstConnect = false;
  }
}

BLYNK_WRITE(V0)  // Menu widget
{
  index = param.asInt();  // Get status of V0.
  modeSelection();  
}

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

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

  // Blnk auth tokens
  Blynk.begin(BLYNK_AUTH_TOKEN, wifi, ssid, pass, "blynk.cloud", 80);

  // 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");
  }
  timer.setInterval(5000L, V0check);  // Timer interval, every 5 seconds
}

void loop() {
  Blynk.run();
  timer.run();
  // You can inject your own code or combine it with other sketches.
  // Check other examples on how to communicate with Blynk. Remember
  // to avoid delay() function!
}

When the code uploads to the arduino, the serial output is:

Enrolling ID #1
Waiting for valid finger to enroll as #1
Communication error
Communication error
Communication error

The “Communication error” will continue to infinitely.

I’d expected to see rather more of yor serial output.

I hadn’t expected to see you using a BlynkTimer to call a function to call a function. This is the stuff that makes the code very difficult to follow and adds totally unnecessary complexity.

Try using this code…

// 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
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[] = "xxxxxx";
char pass[] = "xxxxxx";

// 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
int index;

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;
}

// 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' example.");
    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("Not in enrol mode");          
          //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 switch on admin dashboard/application.");
          Blynk.virtualWrite(V1, "If switching modes, please be patient as this process could take up to 30 seconds.");
          Blynk.virtualWrite(V1, "If you would like to wipe the database, press the delete button.");
          Blynk.virtualWrite(V1, "Ready to enroll a fingerprint!");
          Serial.print("Enrolling ID #");
          Blynk.virtualWrite(V1, "Enrolling ID #" + fing);
          Serial.println(fid);
          Blynk.virtualWrite(V1, "Waiting for valid finger to enroll as #" + fing);
          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("Not in scanning mode");
          
          //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 switch on admin dashboard/application.");
          Blynk.virtualWrite(V1, "If switching modes, please be patient as this process could take up to 30 seconds.");
          Blynk.virtualWrite(V1, "If you would like to wipe the database, press the delete button.");
          Blynk.virtualWrite(V1, "Scanning, waiting for fingerprint.");
          
          Serial.println("To switch modes please use switch on admin dashboard/application.");
          Serial.println("If switching modes, please be patient as this process could take up to 30 seconds.");
          Serial.println("If you would like to wipe the database, press the delete button.");
          Serial.println("Scanning, waiting for fingerprint.");         
                           
          scanningMode = true;
        }
        getFingerprintID();
        delay(300);
        break;
      }
    case 3:
      {
        Serial.println("case option 3 was selected");
        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();
}

and post your ENTIRE serial output from boot-up to whatever error message you encounter when you run the code.

Pete.

1 Like

Wow Pete. Thank you so much I appreciate it. Working good and no errors at all. What I sent you before was the only serial output I was getting. Now everything is smooth. Just to let you know though, this is what I was talking about before when I said that the clear terminal wasn’t working for me. I attached a picture to show you the terminal output. terminal.clear just outputs “clr”.

Sounds like a bug, as the documentation says that should work…

I’ll do some tests later, and I’m sure that there is a better way to do it than the one you’ve used.

Pete.

1 Like

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.