This arduino project will show you how to make a DIY fingerprint attendance system.
Things used in this project
Software apps and online services
Arduino IDE
Story
Now, you can easily track attendance and clock working hours with the help of this easy and fun to make DIY fingerprint scanner! We’ll be using ThingSpeak to store and retrieve the data. All you require is a cardboard piece, some colored paper, a fingerprint sensor, evive, and lots of DIYing!
Ready for some scanning and tracking? Hop on board!
Step 2: Making the Evive Holder
Take the piece of cardboard and cut it in the shape of evive or your Arduino Board.
The box I have made just needs to be folded and glued.
Cut out the extras and you will get the shape as shown in Image2.
To fold the cardboard, make slight cuts at the edges drawn. Thus, helping you to fold it into the box easily.
Finally, to keep the box stable, glue the edges using Hot Glue.
Thus, our box is almost ready.
Step 3: Decorating the Box
Take the box that, you have made and color it according to your choice.
I have glued the color paper on the box to make it attractive.
Finally, keep the evive safe :) I have added a lock to it.
I took a small string and have made a loop of it.
I have fixed a small bolt onto the side of the box to fix the loop around it.
Finally, as we are using the fingerprint sensor. I have 3D printed a sensor holder and have attached it to the front door of the box.
Step 4: Circuitry
Once done with the making, it's time to make the connection:
VCC (Red wire) to evive's 3.3 V
GND (Black wire) to evive's GND
Rx (Yellow wire) to Digital Pin 10 of evive
Tx (White wire) to Digital Pin 11 of evive
Step 5: Working Modes
I have added the two working mode for the attendance system:
Enroll Mode
Attendance Mode
Let's discuss each mode in detail.
Step 6: Enroll Mode
All the first time user needs to first enroll themselves into the system.
I have added some instructions so that one can enroll the fingerprints easily.
I have added the following instructions:
Choose the Enroll Mode
Choose the Number on which you wanna enroll yourself.
Place your finger on the sensor.
Then remove the finger and again place it for the verification
If the fingerprints are matched, you have now enrolled.
If not, have to follow the above steps again.
Step 7: Attendance Mode
Once you have enrolled yourself, all you need to do is mark your attendance daily to check your working hours.
Select the Attendance mode and place your finger on the sensor and mark your attendance.
You can select the text you want to display on the screen.
Once you have marked the attendance, on selecting the attendance mode again and placing your finger again, will mark your exit.
You can again choose the exit text you want to display.
Step 8: Storing Data
I have used Thingspeak, which is the opensource software to store and retrieve data.
I have first created a Thingspeak account. One out of the many good things about Thingspeak is that you can store the data coming from your multiple projects in a single account. All you need to do is create a different channel for each project. You can store up to 8 fields on 1 channel. We will store 1 parameter.
When a new channel is created, you can see four graphs for each parameter. Get the Channel ID of your Channel (To be used while connecting to the channel). Get the Read and Write API from the API tab:
To connect your project with the corresponding channel, you need to enter the Thingspeak's API of that channel into your Arduino Code.
All our records are being directly stored over WiFi to our account.
You can retrieve the data by downloading the CSV File.
Step 9: Arduino Code
Upload the following Arduino code to evive.
Code
//-------------------Library Declaration-----------------------
#include <Adafruit_Fingerprint.h>
#include <ESP8266.h>
#include <Rtc_Pcf8563.h>
#include <SoftwareSerial.h> // Library Declaration
#include <EEPROM.h>
#include<evive.h>
//------------------Declaration for fingerprint sensor---------
uint16_t id ; // variable for storing id
unsigned int total_count =0; // variable for storing total count
unsigned int buzzer = 46;
unsigned int state[25]={};
String UserName = ""; // variable for storing names
String Time_State = ""; // variable for Date and Time
SoftwareSerial mySerial(10, 11); // sensor Rx pin - 10 , Tx pin- 11 // if using arduino then change this pins
Adafruit_Fingerprint finger = Adafruit_Fingerprint(&mySerial);
//------------------- declaration for ESP8266------------------
#define SSID "AR3" // Enter your WiFi name here
#define PASSWORD "STEM@101" // Enter your Wifi password here
#define HOST_NAME "api.thingspeak.com"
#define KEY "G8WX13SFJTFN16ER" // Enter your thingspeak api key here
#define HOST_PORT (80)
ESP8266 wifi(Serial3, 115200); // library function
//-------------------Declaration for real time clock-----------
Rtc_Pcf8563 rtc;
////////////////////////////////////////////////////////////////////////////
void setup()
{
// put your setup code here, to run once:
Serial.begin(9600);
finger.begin(57600);
pinMode(buzzer,OUTPUT);
INIT_TFT();
Rtc_init();
for(unsigned int i=0;i<25;i++)
{
state[i]=0;
}
//---------------------------Setup for Fingerprint sensor-------------------
if (finger.verifyPassword())
{
Serial.println("Found fingerprint sensor!");
}
else
{
Serial.println("Did not find fingerprint sensor :(");
while (1)
{
delay(1);
}
}
finger.getTemplateCount();
Serial.print("Sensor contains ");
Serial.print(finger.templateCount);
Serial.println(" templates");
//--------------------------- setup for esp8266 --------------------------
if (wifi.setOprToStation())
{
Serial.print("set to station mode\r\n");
}
else
{
Serial.print("error in setting to station mode\r\n");
}
if (wifi.joinAP(SSID, PASSWORD))
{
Serial.print("Join AP success\r\n");
Serial.print("IP: ");
Serial.println(wifi.getLocalIP().c_str());
}
else
{
Serial.print("Join AP failure\r\n");
}
wifi.disableMUX();
Serial.print("setup end\r\n");
delay(100);
digitalWrite(13,HIGH);
}
///////////////////////////////////////////////////////////////////////////////////////
void loop()
{
// put your main code here, to run repeatedly:
START_TFT();
while(!((digitalRead(40)==HIGH)||(digitalRead(41)==HIGH)))
{
Delay(1);
}
////////////////////// Attendance mode ////////////////////////////////
if(digitalRead(40)==HIGH)
{
ATTENDANCE_BASIC_TFT();
while(digitalRead(40)==HIGH)
{
Attendance_mode();
}
}
///////////////////// Enroll mode ///////////////////////////////////
else if(digitalRead(41)==HIGH)
{
while(digitalRead(41)==HIGH)
{
Enroll_mode();
}
}
}
//////////////////////////////////TFT Function////////////////////////////////////////
void INIT_TFT()
{
tft_init(INITR_BLACKTAB);
tft.setRotation(1);
tft.fillScreen(ST7735_BLACK);
}
void START_TFT()
{
tft.fillScreen(ST7735_BLACK);
tft.setCursor(25,25);
tft.setTextSize(2);
tft.setTextColor(ST7735_WHITE,ST7735_BLACK);
tft.print("STEMpedia");
tft.setCursor(28,50);
tft.setTextSize(1);
tft.setTextColor(ST7735_GREEN,ST7735_BLACK);
tft.print("ATTENDANCE SYSTEM");
tft.setCursor(5,70);
tft.setTextSize(1);
tft.setTextColor(ST7735_WHITE,ST7735_BLACK);
tft.print("SS1 UP - ATTENDANCE MODE");
tft.setCursor(5,80);
tft.setTextSize(1);
tft.setTextColor(ST7735_WHITE,ST7735_BLACK);
tft.print("SS1 DOWN - ENROLL MODE");
tft.setCursor(20,100);
tft.print("(SS1 - SlideSwitch 1)");
}
void ATTENDANCE_BASIC_TFT()
{
tft.fillScreen(ST7735_BLACK);
tft.drawRoundRect(10,40,130,75,5,ST7735_WHITE);
tft.setCursor(40,50);
tft.setTextColor(ST7735_GREEN,ST7735_BLACK);
tft.setTextSize(1);
tft.print("INSTRUCTION");
tft.setCursor(35,30);
tft.setTextSize(1);
tft.setTextColor(ST7735_GREEN,ST7735_BLACK);
tft.print("ATTENDANCE MODE");
}
void ENROLL_BASIC_TFT()
{
tft.fillScreen(ST7735_BLACK);
tft.setCursor(45,30);
tft.setTextSize(1);
tft.setTextColor(ST7735_GREEN,ST7735_BLACK);
tft.print("ENROLL MODE");
tft.drawRoundRect(10,40,130,75,5,ST7735_WHITE);
tft.setCursor(40,50);
tft.setTextColor(ST7735_GREEN,ST7735_BLACK);
tft.setTextSize(1);
tft.print("INSTRUCTION");
}
///////////////////////////////////Function for fingerprint sensor//////////////////////////////////
uint8_t getFingerprintID()
{
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.fingerFastSearch();
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)
{
Serial.println("Did not find a match");
return p;
}
else
{
Serial.println("Unknown error");
return p;
}
return finger.fingerID;
}
int getFingerprintIDez()
{
if(digitalRead(40)==LOW)
{
return;
}
uint8_t p = finger.getImage();
Delay(1);
if (p != FINGERPRINT_OK)
{
return -1;
}
p = finger.image2Tz();
if (p != FINGERPRINT_OK)
{
return -1;
}
p = finger.fingerFastSearch();
if (p != FINGERPRINT_OK)
{
ENROLL_BASIC_TFT();
tft.setTextColor(ST7735_WHITE,ST7735_BLACK);
tft.setTextSize(1);
tft.setCursor(25,75);
tft.print(" Access Denied");
Access_denied_beeps();
Delay(20);
return -1;
}
ATTENDANCE_BASIC_TFT();
UserName = NUM_TO_NAME(finger.fingerID);
if(state[finger.fingerID-1]==0)
{
tft.setTextSize(1);
tft.setTextColor(ST7735_WHITE,ST7735_BLACK);
tft.setCursor(25,75);
tft.print(" Welcome "+UserName);
tft.setCursor(20,85);
tft.print(" Have a good day!");
Access_granted_beeps();
Delay(150);
ATTENDANCE_BASIC_TFT();
tft.setTextSize(1);
tft.setTextColor(ST7735_WHITE,ST7735_BLACK);
tft.setCursor(25,75);
tft.print("Attendance Marked");
Delay(50);
}
else if(state[finger.fingerID-1]==1)
{
tft.setTextSize(1);
tft.setTextColor(ST7735_WHITE,ST7735_BLACK);
tft.setCursor(25,75);
tft.print(" Bye "+UserName);
tft.setCursor(20,85);
tft.print(" See you soon!");
Access_granted_beeps();
Delay(10);
}
STATE(finger.fingerID);
SEND_DATA();
return finger.fingerID;
}
uint8_t getFingerprintEnroll()
{
int p = -1;
while (p != FINGERPRINT_OK)
{
Delay(1);
p = finger.getImage();
switch (p)
{
case FINGERPRINT_OK:
Serial.println("Image taken");
break;
case FINGERPRINT_NOFINGER:
Serial.println(".");
Delay(1);
if(digitalRead(41)==LOW)
{
return;
}
break;
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;
}
Serial.println("Remove finger");
ENROLL_BASIC_TFT();
tft.setTextColor(ST7735_WHITE,ST7735_BLACK);
tft.setTextSize(1);
tft.setCursor(25,75);
tft.print("Remove Your Finger");
Delay(150);
p = 0;
while (p != FINGERPRINT_NOFINGER)
{
Delay(1);
p = finger.getImage();
}
Serial.print("ID ");
Serial.println(id);
p = -1;
Serial.println("Place the same finger ");
ENROLL_BASIC_TFT();
tft.setTextColor(ST7735_WHITE,ST7735_BLACK);
tft.setTextSize(1);
tft.setCursor(30,75);
tft.print("Place the same ");
tft.setCursor(35,85);
tft.print("finger again");
Delay(50);
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;
}
}
// 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(id);
p = finger.createModel();
if (p == FINGERPRINT_OK)
{
Serial.println("Prints matched!");
ENROLL_BASIC_TFT();
tft.setTextColor(ST7735_WHITE,ST7735_BLACK);
tft.setTextSize(1);
tft.setCursor(35,75);
tft.print("Print matched");
Delay(250);
}
else if (p == FINGERPRINT_PACKETRECIEVEERR)
{
Serial.println("Communication error");
return p;
}
else if (p == FINGERPRINT_ENROLLMISMATCH)
{
Serial.println("Fingerprints did not match");
ENROLL_BASIC_TFT();
tft.setTextColor(ST7735_WHITE,ST7735_BLACK);
tft.setTextSize(1);
tft.setCursor(40,75);
tft.print("Enrollement ");
tft.setCursor(35,85);
tft.print("Unsuccessfull");
Delay(250);
return p;
}
else
{
Serial.println("Unknown error");
return p;
}
Serial.print("ID ");
Serial.println(id);
p = finger.storeModel(id);
if (p == FINGERPRINT_OK)
{
Serial.println("Stored!");
ENROLL_BASIC_TFT();
tft.setTextColor(ST7735_WHITE,ST7735_BLACK);
tft.setTextSize(1);
tft.setCursor(40,75);
tft.print("Enrolled");
tft.setCursor(35,85);
tft.print("Successfully");
Delay(250);
}
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;
}
}
/////////////////////////Function for selecting Number///////////////////////////////////
uint16_t readnumber(void)
{
uint16_t num = 0;
while(digitalRead(42)==HIGH)
{
if(digitalRead(40)==HIGH || digitalRead(41)==LOW)
{
return;
}
num = analogRead(A9);
num = map(num ,0,1023,1,25);
tft.setCursor(60,90);
tft.setTextSize(2);
tft.print(num);
tft.print(" ");
Delay(1);
}
return num;
}
///////////////////////////Function for Number to name conversion////////////////////////
String NUM_TO_NAME(uint16_t number)
{
String Name ="";
switch(number)
{
case 1:
Name = "Punit";
return Name;
case 2:
Name = "palak";
return Name;
case 3:
Name = "jennifer";
return Name;
case 4:
Name = "Jaydeep";
return Name;
case 5:
Name = "Sagar";
return Name;
case 6:
Name = "Mimansa";
return Name;
case 7:
Name = "User7";
return Name;
case 8:
Name = "User8";
return Name;
case 9:
Name = "User9";
return Name;
case 10:
Name = "User10";
return Name;
case 11:
Name = "User11";
return Name;
case 12:
Name = "User12";
return Name;
case 13:
Name = "User13";
return Name;
case 14:
Name = "User14";
return Name;
case 15:
Name = "User15";
return Name;
case 16:
Name = "User16";
return Name;
case 17:
Name = "User17";
return Name;
case 18:
Name = "User18";
return Name;
case 19:
Name = "User19";
return Name;
case 20:
Name = "User20";
return Name;
case 21:
Name = "User21";
return Name;
case 22:
Name = "User22";
return Name;
case 23:
Name = "User23";
return Name;
case 24:
Name = "User24";
return Name;
case 25:
Name = "User25";
return Name;
}
}
//////////////////////// Function for RTC Clock /////////////////////////////////////////
void Rtc_init()
{
rtc.initClock();
rtc.setDate(13,4,3,0,19);
rtc.setTime(15,30,0);
delay(2000);
}
///////////////////////// Function for Time state ///////////////////////////////////////
void STATE(uint16_t number)
{
rtc.getTime();
rtc.getDate();
if(state[finger.fingerID-1]==0)
{
Time_State= "Entering Time";
state[finger.fingerID-1]=1;
}
else if(state[finger.fingerID-1]==1)
{
Time_State= "leaving Time";
state[finger.fingerID-1]=0;
}
}
void Delay(unsigned int wait)
{
for(unsigned int i=0;i<wait;i++)
{
// delay(1);
print_date();
}
}
void print_date()
{
rtc.getTime();
rtc.getDate();
tft.setCursor(5,10);
tft.setTextSize(1);
tft.setTextColor(ST7735_WHITE,ST7735_BLACK);
tft.print(rtc.formatDate(RTCC_DATE_WORLD));
tft.setCursor(120,10);
tft.setTextSize(1);
tft.setTextColor(ST7735_WHITE,ST7735_BLACK);
tft.print(rtc.formatTime(RTCC_TIME_HM));
}
void Access_granted_beeps()
{
beeps(200);
beeps(200);
}
void Access_denied_beeps()
{
for(unsigned int i=0;i<5;i++)
{
beeps(100);
beeps(100);
delay(50);
}
}
void beeps(unsigned int wait)
{
analogWrite(buzzer,20);
delay(wait);
analogWrite(buzzer,0);
delay(wait);
}
////////////////////////// Function for sending data to Internet //////////////////////////////////
void SEND_DATA()
{
uint8_t buffer[1024] = {0};
if (wifi.createTCP(HOST_NAME, HOST_PORT))
{
Serial.print("create tcp ok\r\n");
}
else
{
Serial.print("create tcp err\r\n");
return;
}
String http = String();
http += "GET /update?key=";
http += KEY;
http += "&field1=" + UserName;
http += "&field2=" + String(String(rtc.getDay())+"|"+String(rtc.getMonth())+"|"+String(rtc.getYear()));
http += "&field3=" + String(rtc.formatTime());
http += "&field4=" + Time_State;
http += " HTTP/1.1\r\n";
http += "Host: api.thingspeak.com\r\n";
http += "Connection: close\r\n\r\n";
Serial.println(http);
wifi.send((const uint8_t*)http.c_str(), http.length());
uint32_t len = wifi.recv(buffer, sizeof(buffer), 10000);
if (len > 0)
{
Serial.print("Received:[");
for (uint32_t i = 0; i < len; i++)
{
Serial.print((char)buffer[i]);
}
Serial.print("]\r\n");
}
if (wifi.releaseTCP())
Serial.print("release tcp ok\r\n");
else
Serial.print("release tcp err\r\n");
Delay(20);
}
void Attendance_mode()
{
tft.setTextColor(ST7735_WHITE,ST7735_BLACK);
tft.setTextSize(1);
tft.setCursor(20,85);
tft.print(" ");
tft.setCursor(25,75);
tft.print("Place Your Finger");
getFingerprintIDez();
Delay(50);
}
void Enroll_mode()
{
ENROLL_BASIC_TFT();
tft.setCursor(15,75);
tft.setTextColor(ST7735_WHITE,ST7735_BLACK);
tft.print(" Slide Slideswitch2");
tft.setCursor(60,85);
tft.print(" \"UP\" ");
while(!(digitalRead(42)==HIGH))
{
Delay(2);
if(digitalRead(40)==HIGH || digitalRead(41)==LOW)
{
return;
}
}
tft.fillScreen(ST7735_BLACK);
ENROLL_BASIC_TFT();
tft.setCursor(15,75);
tft.setTextColor(ST7735_WHITE,ST7735_BLACK);
tft.setTextSize(1);
tft.print(" Use Potentiometer1");
tft.setCursor(15,85);
tft.print(" to Select Number");
Delay(80);
ENROLL_BASIC_TFT();
tft.setCursor(15,65);
tft.setTextColor(ST7735_WHITE,ST7735_BLACK);
tft.print(" Slide Slideswitch2");
tft.setCursor(60,75);
tft.print("\"DOWN\"");
id = readnumber();
ENROLL_BASIC_TFT();
tft.setTextColor(ST7735_WHITE,ST7735_BLACK);
tft.setTextSize(1);
tft.setCursor(25,75);
tft.print("Place Your Finger");
while (!getFingerprintEnroll())
{
Delay(1);
if(digitalRead(40)==HIGH || digitalRead(41)==LOW)
{
return;
}
}
}