Introduction: Time & Attendance System With Raspberry and Phidgets

Picture of Time & Attendance System With Raspberry and Phidgets

In this tutorial we will create an easy time & attendance system using a Raspberry Pi and a Phidgets RFID read-write.

We will use a web page to display the current time, and a confirmation message for employees and all movements (incoming or outgoing) will be stored in a file.

You need:

In the tutorial I used the new Raspberry Pi 2, but you can use a Raspberry Pi B or B+, with the latest version of Raspbian, or our MIcroSD Card 8GB Class 10 Raspbian preinstalled.

A 1024_0 - PhidgetRFID Read-Write

Connect the rfid reader to an usb port of Raspberry, and a monitor

Step 1: Prepare the System

Picture of Prepare the System

Update the packages and firmware

sudo apt-get update
sudo apt-get upgrade
sudo rpi-update

Install the web server and prepare the system to work with Phidgets.

Next install the chromium browser, and unclutter ( removes the cursor from the screen). The chromium browser includes a kiosk mode which displays the browser full screen without any taskbars or icons which works perfectly for a kiosk style screen.

sudo apt-get install chromium unclutter

Before we start displaying anything on the screen we need to go through a few steps to setup and disable a few settings.

Firstly we should disable the screensaver and any energy saving settings as we don’t want our screen to go to sleep at all when it’s in use, wouldn’t be very useful if it went blank every 5 minutes.

Edit file /etc/xdg/lxsession/LXDE-pi/autostart

sudo nano /etc/xdg/lxsession/LXDE-pi/autostart

As you can probably guess this is a file that runs when your pi boots. To disable the screensaver add a # to the beginning of the line, this comments the line out.

@xscreensaver -no-splash

Next add these lines underneath the screensaver line

@xset s off
  @xset -dpms
  @xset s noblank

This disables power management settings and stops the screen blanking after a period of inactivity.

Now that is done we should prevent any error messages displaying on the screen in the instance that someone accidentally power cycles the pi without going through the shutdown procedure. To do this we add the following line underneath the lines you just added.

@sed -i 's/"exited_cleanly": false/"exited_cleanly": true/' ~/.config/chromium/Default/Preferences

Finally we need to tell chromium to start and which page to load once it boots without error dialogs and in Kiosk mode. To do this add the following line to the bottom of this autostart file.

@chromium --noerrdialogs --disable-translate --kiosk http://localhost/web/ --incognito

the file looks like this

Time and attendance system with Raspberry and Phidgets

To make sure your raspberry pi boots to desktop type the command

sudo raspi-config

and change this setting to boot in desktop mode by default.

Time and attendance system with Raspberry and Phidgets

Step 2: The GUI

Picture of The GUI
We create the web page that appears when Raspberry starts,  this page displays a clock with the current time and a confirmation message for employees.
 
Create a folder
 
sudo mkdir /home/pi/web
 
create the /home/pi/web/index.php file with this content
 
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="css/style.css" />
<script src="//code.jquery.com/jquery-1.11.2.min.js"></script>
<script src="js/attendance.js"></script>
</head>
<body>
<div class="container">
        <div class="clock">
        <div id="Date"></div>
          <ul>
              <li id="hours"></li>
              <li id="point">:</li>
              <li id="min"></li>
              <li id="point">:</li>
              <li id="sec"></li>
          </ul>
        </div>    
        <div class="tags">
        <div id="Message">Wait..</div>
        </div>
</div>
</body>
</html>

This is the main file, the animations are realized with jquery

Create the file /home/pi/web/js/attendance.js with this content

function updateDisplay() {
          var jqxhr = $.get("message.php", function(data){
            $('#Message').html(data);
      });
  }
   
  $(document).ready(function() {
  // Create two variable with the names of the months and days in an array
  var monthNames = [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ];
  var dayNames= ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"]
   
  // Create a newDate() object
  var newDate = new Date();
  // Extract the current date from Date object
  newDate.setDate(newDate.getDate());
  // Output the day, date, month and year   
  $('#Date').html(dayNames[newDate.getDay()] + " " + newDate.getDate() + ' ' + monthNames[newDate.getMonth()] + ' ' + newDate.getFullYear());
   
  setInterval( function() {
      // Create a newDate() object and extract the seconds of the current time
      var seconds = new Date().getSeconds();
      // Add a leading zero to seconds value
      $("#sec").html(( seconds < 10 ? "0" : "" ) + seconds);
      },1000);
       
  setInterval( function() {
      // Create a newDate() object and extract the minutes of the current time
      var minutes = new Date().getMinutes();
      // Add a leading zero to the minutes value
      $("#min").html(( minutes < 10 ? "0" : "" ) + minutes);
      },1000);
       
  setInterval( function() {
      // Create a newDate() object and extract the hours of the current time
      var hours = new Date().getHours();
      // Add a leading zero to the hours value
      $("#hours").html(( hours < 10 ? "0" : "" ) + hours);
      }, 1000);    
   
  setInterval(function(){updateDisplay()}, 500);
   
  });

Create the file /home/pi/web/css/style.css with this content

body{
       background:#333333;
       font:bold 12px Arial, Helvetica, sans-serif;
       margin:0;
       padding:0;
       min-width:90%;
       color:#bbbbbb;
  }
   
  a {
      text-decoration:none;
      color:#00c6ff;
  }
   
  h1 {
      font: 4em normal Arial, Helvetica, sans-serif;
      padding: 20px;    margin: 0;
      text-align:center;
  }
   
  h1 small{
      font: 0.2em normal  Arial, Helvetica, sans-serif;
      text-transform:uppercase; letter-spacing: 0.2em; line-height: 5em;
      display: block;
  }
   
  h2 {
      font-weight:700;
      color:#bbb;
      font-size:20px;
  }
   
  h2, p {
      margin-bottom:10px;
  }
  .container {
      width: 90%;
      margin: 0 auto;
      overflow: hidden;
  }
   
  .clock {
      width: 80%;
      margin: 0 auto;
      padding: 30px;
      border: 1px solid #333;
      color: #fff;
      background: #0066FF;
  }
   
  .tags {
      width: 80%;
      margin: 0 auto;
      padding: 30px;
      border: 1px solid #333;
      color: #fff;
      background: #0066FF;
  }
   
  #Date {
      font-size: 36px;
      text-align: center;
  }
  #Message {
      font-size: 36px;
      text-align: center;
  }
  ul {
      width: 800px;
      margin: 0 auto;
      padding: 0px;
      list-style: none;
      text-align: center;
  }
   
  ul li {
      display: inline;
      font-size: 10em;
      text-align: center;
  }
   
  #point {
      position: relative;
      -moz-animation: mymove 1s ease infinite;
      -webkit-animation: mymove 1s ease infinite;
      padding-left: 10px;
      padding-right: 10px;
  }
   
  /* Simple Animation */
  @-webkit-keyframes mymove {
      0% {opacity: 1.0;
      text-shadow: 0 0 20px #00c6ff;
  }
   
  50% {
      opacity: 0;
      text-shadow: none;
  }
   
  100% {
      opacity: 1.0;
      text-shadow: 0 0 20px #00c6ff;
  }    
  }
   
  @-moz-keyframes mymove {
      0% {
          opacity: 1.0;
          text-shadow: 0 0 20px #00c6ff;
      }
   
      50% {
          opacity: 0;
          text-shadow: none;
      }
   
      100% {
          opacity: 1.0;
          text-shadow: 0 0 20px #00c6ff;
      };
  }

Create the file /home/pi/web/message.php with the follow content, we use this in the next step

<?php
  if (isset($_POST['direction']))
  {
      $str_in=$_POST['direction'];
      $file = fopen("message.txt","w")or die("Unable to write file !");
      $str_in = mb_convert_encoding($str_in, 'HTML-ENTITIES', "UTF-8");
      fwrite($file,$str_in);
      fclose($file);
  }
      $myfile = fopen("message.txt", "r") or die("Unable to open file!");
      $read=fread($myfile,filesize("message.txt"));
      fclose($myfile);
      echo $read;
  ?>

Create a file /home/pi/web/message.txt, we will use this to store temporarily the message to show

Make a link to the web server

sudo ln -s /home/pi/web /var/www

If you reboot, Raspberry start in display mode and shows the current date and time

Time and attendance system with Raspberry and Phidgets

Step 3: Rfid Tags

Picture of Rfid Tags

To store the RFID tag we will use a simple text file. With a Python script we will read the tag and if the file contains it, we will record a new row in the file attendance.txt.  At the same time the script sends a message to display.

Create a new file /home/pi/tag.txt with some tags

Time and attendance system with Raspberry and Phidgets     1  startx

Create a new file /home/pi/attendance.txt where we will store the movements incoming and outgoing

Create the file /home/pi/rfid.py with this content

#!/usr/bin/env python
         
         
         
        #Basic imports
        from ctypes import *
        import sys
        import time
        import datetime
        import urllib2
        import urllib
        #Phidget specific imports
        from Phidgets.PhidgetException import PhidgetErrorCodes, PhidgetException
        from Phidgets.Events.Events import AttachEventArgs, DetachEventArgs, ErrorEventArgs, OutputChangeEventArgs, TagEventArgs
        from Phidgets.Devices.RFID import RFID, RFIDTagProtocol
         
        tagsList=list()
        tagStatus=list()
         
        with open('tag.txt') as f:
            tagsList = f.read().splitlines()
            
         
        for index in range(len(tagsList)):
            tagStatus.append(0)
         
         
        #Create an RFID object
        try:
            rfid = RFID()
        except RuntimeError as e:
            print("Runtime Exception: %s" % e.details)
            print("Exiting....")
            exit(1)
         
        #Information Display Function
        def displayDeviceInfo():
            print("|------------|----------------------------------|--------------|------------|")
            print("|- Attached -|-              Type              -|- Serial No. -|-  Version -|")
            print("|------------|----------------------------------|--------------|------------|")
            print("|- %8s -|- %30s -|- %10d -|- %8d -|" % (rfid.isAttached(), rfid.getDeviceName(), rfid.getSerialNum(), rfid.getDeviceVersion()))
            print("|------------|----------------------------------|--------------|------------|")
            print("Number of outputs: %i -- Antenna Status: %s -- Onboard LED Status: %s" % (rfid.getOutputCount(), rfid.getAntennaOn(), rfid.getLEDOn()))
         
        #Event Handler Callback Functions
        def rfidAttached(e):
            attached = e.device
            print("RFID %i Attached!" % (attached.getSerialNum()))
         
        def rfidDetached(e):
            detached = e.device
            print("RFID %i Detached!" % (detached.getSerialNum()))
         
        def rfidError(e):
            try:
                source = e.device
                print("RFID %i: Phidget Error %i: %s" % (source.getSerialNum(), e.eCode, e.description))
            except PhidgetException as e:
                print("Phidget Exception %i: %s" % (e.code, e.details))
         
        def rfidOutputChanged(e):
            source = e.device
            print("RFID %i: Output %i State: %s" % (source.getSerialNum(), e.index, e.state))
         
        def rfidTagGained(e):
            source = e.device
            rfid.setLEDOn(1)
            try:
                if tagStatus[tagsList.index(e.tag)]==0:
                    postdata="Welcome, have a good day"
                    tagStatus[tagsList.index(e.tag)]=1
                else:
                    postdata="Hi, see you tomorrow"    
                    tagStatus[tagsList.index(e.tag)]=0
                if e.tag in tagsList:   
                    query_args={'direction':postdata}
                    url='http://localhost/web/message.php'
                    user_agent = 'Mozilla/5.0 (X11; Linux armv7l) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.94 Safari/537.4'
                    headers = { 'User-Agent' : user_agent }
                    data=urllib.urlencode(query_args)
                    request=urllib2.Request(url,data,headers)
                    request.add_header('Referer', 'http://localhost/web/')
                    response=urllib2.urlopen(request).read()
                    
                    now = datetime.datetime.now()
                    fh = open("/home/pi/attendance.txt", "a")
                    #fh.write(now.strftime('%s'))
                    #fh.write(";{};{};\n".format( tagStatus[tagsList.index(e.tag)],  e.tag ))
                    fh.write("{};{};{};\n".format( now.strftime('%s'), tagStatus[tagsList.index(e.tag)],  e.tag ))
                    fh.close
            except ValueError:
                print("Error unknown tag %s" % (e.tag))
         
        def rfidTagLost(e):
            source = e.device
            rfid.setLEDOn(0)
            time.sleep(2)
            postdata="Ready.."
            query_args={'direction':postdata}
            url='http://localhost/web/message.php'
            user_agent = 'Mozilla/5.0 (X11; Linux armv7l) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.94 Safari/537.4'
            headers = { 'User-Agent' : user_agent }
            data=urllib.urlencode(query_args)
            request=urllib2.Request(url,data,headers)
            request.add_header('Referer', 'http://localhost/web/')
            response=urllib2.urlopen(request).read()
            
         
        #Main Program Code
        try:
            rfid.setOnAttachHandler(rfidAttached)
            rfid.setOnDetachHandler(rfidDetached)
            rfid.setOnErrorhandler(rfidError)
            rfid.setOnOutputChangeHandler(rfidOutputChanged)
            rfid.setOnTagHandler(rfidTagGained)
            rfid.setOnTagLostHandler(rfidTagLost)
        except PhidgetException as e:
            print("Phidget Exception %i: %s" % (e.code, e.details))
            print("Exiting....")
            exit(1)
         
        print("Opening phidget object....")
         
        try:
            rfid.openPhidget()
        except PhidgetException as e:
            print("Phidget Exception %i: %s" % (e.code, e.details))
            print("Exiting....")
            exit(1)
         
        print("Waiting for attach....")
         
        try:
            rfid.waitForAttach(10000)
        except PhidgetException as e:
            print("Phidget Exception %i: %s" % (e.code, e.details))
            try:
                rfid.closePhidget()
            except PhidgetException as e:
                print("Phidget Exception %i: %s" % (e.code, e.details))
                print("Exiting....")
                exit(1)
            print("Exiting....")
            exit(1)
        else:
            displayDeviceInfo()
         
        print("Turning on the RFID antenna....")
        rfid.setAntennaOn(True)
         
        print("Press Enter to quit....")
         
        chr = sys.stdin.read(1)
         
         
         
        try:
            lastTag = rfid.getLastTag()
            print("Last Tag: %s" % (lastTag))
        except PhidgetException as e:
            print("Phidget Exception %i: %s" % (e.code, e.details))
         
        print("Closing...")
         
        try:
            rfid.closePhidget()
        except PhidgetException as e:
            print("Phidget Exception %i: %s" % (e.code, e.details))
            print("Exiting....")
            exit(1)
         
        print("Done.")
        exit(0)

Run the script

sudo python /home/pi/rfid.py

Time and attendance system with Raspberry and Phidgets

The RFID reader is put on hold, if approaching a tag the monitor displays a welcome message.

At the same time the script save a new row in attendance.txt.

A variable stores the state of that tag and  approaching back the same tag it will display a message of greeting to the exit

Time and attendance system with Raspberry and Phidgets

Time and attendance system with Raspberry and Phidgets

Time and attendance system with Raspberry and Phidgets

Time and attendance system with Raspberry and Phidgets

Comments

rudolfpi (author)2015-08-29

Also an error when starting the python rfid.py:

File "/home/pi/rfid.py", line 6
import sys
^
IndentationError: unexpected indent

collinx3m (author)rudolfpi2015-11-09

Was this ever resolved?

rudolfpi (author)2015-09-15

Author where are you?

rudolfpi (author)2015-08-29

I get an error:

Warning: fread(): Length parameter must be greater than 0 in /home/pi/web/message.php on line 11

rudolfpi (author)2015-08-27

Will try this project, looks great!

Can you tell me how to add names to the tag numbers and add names to the attendance.txt file and show the name to the gui screen when checking in and checking out?

I would also like to upload (automatically or once/twice per day) to an other computer or server.