Bogusław Kempny

Time & Attendance

×
Autor adres Polski
About HC-SR04 LCD Camera fork() Short Message Service strfry() GPIO pulses Keypad Gate GPIO PWM SG90 RFID Graphologist Time and attendance Shutdown Temperature ....











Sometimes, we have to monitor the working hours of our employees performing their duties outside the workplace or the company has a small number of employees, for example, 20.

A standard Time and Attendance system is of little use in this case. It has to have stationary readers, cabling, controller, server… A little too much. Imagine the installation of such a system for, let's say, 30 people working on a remote site for 20 days, then 30 days on another site, and then again in a different place.

The solution to this problem may be the MiniT&A system, containing all these elements in one small, 14x10x6 cm, housing box.

A power cord, button for switching between registration of an entry and exit from work, RFID proximity card reader, camera taking a photo of a registering employee, indicator showing that the card has been read, display.

The display always shows the exact time, synchronized with time servers in the network, the current state of the recorder (entry or exit registration), and, when the card is placed within range of the reader, the employee's name and surname. The camera saves photos in the 640x480 pixel format, about 25 kB, to save the disk space, but you can set a different resolution, up to 5 Mpx. It works even in poor lighting.

Communication with the Internet via an Ethernet port or GSM modem. Access to the registered data (entry/exit, photos, reports and summaries, administration of the employee data, etc.) from any browser through the HTTPS protocol with access requiring the cryptographic key.

And what is inside of this box?

The most important element - Raspberry Pi. It controls the display, proximity card reader, takes photos (the photo shows the unplugged ribbon cable for the camera), communicates with the Internet via Ethernet or GSM modem, and provides access to the device via the Apache server.

Employees' data and entry/exit time records are stored in the MariaDB (MySQL) database.

And here, an important note. Raspberry Pi uses a MicroSD card as a disk. This type of data storage wears out when it is written to. That is why the database files are placed on a USB flash drive. For safety, the daily backup of the data from the SD card is made to the USB flash drive, and data stored on the USB flash drive to the SD card.

What else? 5V power supply, a tiny buzzer and that's it.

How to connect it?

According to this scheme.

The camera we connect to the Raspberry Pi "CAMERA" socket.

How to bring it to life? I have described how to handle the display, camera, and RFID reader here:

LCD

Camera

RFID

The program for operating the recorder, available here, must be compiled with the MariaDB and WiringPi libraries using the following command:

cc pomiar.c -o pomiar -L/usr/lib/mysql -lmariadbclient  -L/usr/local/lib -lwiringPi -lwiringPiDev

Here we will focus only on the code that was not yet explained in the display, camera, or RFID reader sections.

First, let's talk about the display.

It seems like nothing to clarify here. I have already described it in the LCD section.

However, in this case, it is not so trivial.

When the employee's card is identified, using the fork() function, the /home/minircp/pstryk sript, responsible for taking a photo, is executed. It may take a few seconds. During this time, the parent process keeps running, writes to the database, each second displays the current time.

After taking the photo, our main process receives the SIGCHLD signal, handled by the clean_up_child_process(int signal_num) procedure.

If we would not handle this signal, with each pstryk() script execution, the child process would end up as a zombie process.

But this procedure also prints the "OK" text and starts the lateok thread which, after one second, switches off the "OK" text. And this is where the problem may arise. Each second, the main process displays the current time. If the SIGCHLD interrupt is handled while the main process is displaying the time, we will see garbage on the display's screen.

To avoid this, messages are not displayed directly on the display, but written with the wyswbuf() procedure to the bufwysw struct. Each second, the main process, while displaying the current time, reads potential messages from this struct and displays them with the wyswietl() procedure.

The bufwysw struct acts as a FIFO with the PIPESIZE capacity.

Below, the code we have covered:
#include <string.h>

...

// tablica na fifo do wyswietlacza
struct {
  int x;
  int y;
  char tresc[30];
} bufwysw[PIPESIZE];

int wyswp;
int wyswk;

...

PI_THREAD(lateok);

...

void clean_up_child_process(int signal_num)
{
/* remove child process */
int status, k;
wait (&status);
wyswbuf(9,2,"OK");
piThreadCreate (lateok) ;
}
...

void main (argc, argv)
int argc;
char *argv[];
{

...

wyswp =0;
wyswk =0;

...

/* handle SIGCHLD by calling clean_up_child_process */
struct sigaction sigchild_action;
memset(&sigchild_action, 0, sizeof(sigchild_action));
sigchild_action.sa_handler = &clean_up_child_process;
sigaction(SIGCHLD, &sigchild_action, NULL);

...

  if (czas2!= czas1)
    {
      loctime = localtime (&czas1);
      strftime (buffer, SIZE, "%Y-%m-%d  %H:%M:%S", loctime);
      wyswietl(0,3,buffer);
      czas2=czas1;
      if(wyswp != wyswk)
       {
         wyswietl(bufwysw[wyswk].x, bufwysw[wyswk].y, bufwysw[wyswk].tresc);
         wyswk ++;
         if (wyswk == PIPESIZE) wyswk = 0;
       }
    }

...

lcdClear(lcdHandle);
wyswietl(6,1,"WEJSCIE");

...

    if (! (m = fork()) )
    execl("/home/minircp/pstryk", "/home/minircp/pstryk", nrzdjchr, (char *)0);

...

}                               // od main

//*****************************************
void wyswietl(int x, int y, char* tresc)
{
  lcdPosition (lcdHandle, x, y) ; 
  strncpy(buf1, tresc, 20);
  lcdPuts (lcdHandle, buf1) ;
}

//*****************************************
void wyswbuf(int x, int y, char* tresc)
{
  bufwysw[wyswp].x = x;
  bufwysw[wyswp].y = y;
  strncpy(bufwysw[wyswp].tresc, tresc, 20);
  wyswp++;
  if (wyswp == PIPESIZE) wyswp = 0;
fflush(0);
}


//*************************************
PI_THREAD(lateok)
{
  sleep(1);
  wyswbuf(9,2,"  ");
  wyswbuf(0,0,"                    ");
}
Secondly, the database.

Nothing really unusual, standard MySQL/MariaDB C API.

However, there are two things worth notice. SD card doesn't like frequent writes, it's its nature. That is why we placed the database files on the USB flash drive connected to the USB port.

It may not be a super-fast interface, but write/read speed is not critical here. In case of the USB flash drive's memory damage, we do not lose the entire operating system, and the daily backups, using cron, of the SD card to the pen drive and of the databases from the pen drive to the SD card are made.

#! /bin/sh
cd /home/kopie_rcp
NAZWA=minircp_mysql.tgz
tar -czvf $NAZWA  /var/lib/mysql  --exclude="/home/minircp/zdjecia/*" --exclude=/home/minircp/kopie_system/* /home/minircp
cd /home/minircp/kopie_system
NAZWA=system_html.tgz
tar -czvf $NAZWA  /etc /var/www/html
And the second important thing. MySQL/MariaDB operates on copies of tables in RAM. This means that in the event of a power outage, the records for a certain period (even several hours) will disappear. To avoid this, after changes to the tables have been saved, we force to save those tables to the disk:
        sprintf (buf_sql,
            "flush tables czytnik, czytnik_rob, zdjecia");
        if (mysql_query (&mysql, buf_sql))
         {
...
How to turn off the device? Raspberry Pi does not have an On/Off button. You need to disconnect the power.

The operating system and applications do not necessarily like this kind of treatment. Therefore, when the system starts, the reset process is launched (compiled program reset.c). It monitors the state of the entry/exit button and if its long press for 6 seconds is detected, the shutdown procedure is initiated. The messages regarding the process will appear on the LCD display.

So you have reached the end of this post, congratulation on your perseverance! If you have any questions about this topic, feel free to contact me on my e-mail.