Proyecto N° 2: Control de Empleados.

Buenas tardes a todos , Estoy trabajando en un 2do proyecto. El cual este es para mi Pymes.

Cuento con casi 15 Empleados

Y quiero hacer un Control de Entrada y Salida de cada 1.

Lista de materiales:

La idea se basa, en un sistema de control de usuarios

Mediante un Telcado o Tarjetas RFID.

Cuando el empleado pase la tarjeta o ingrese su clave , en el display muestra Su nombre y asi mismo deberia guardar fecha , hora , y nombre de empleado en una tabla de una base de datos.

Si la hora es de 7 Am a 2 PM Los datos se guardan en la tabla "INGRESO"
Si la hora es de 2 PM a 9 PM Los datos se guardan en la tabla "EGRESO"

(Las funciones de la HORA todavia no estan ECHAS)

Tengo Varias dudas.

En el caso de que la luz se corte , el Codigo quedara intacto ?
En caso de que la luz se corte , el reloj guardara la hora ya que cuenta con una bateria.

Problemas:

1. El RFID que compre 1ro, Usa pins (MOSI , MISO , SDA , SCK , RST) los cuales no son compatibles o no puedo usarlos debidamente ya que me tira muchos errores (POST DONDE HICE EL RECLAMO) PROBLEMA RESUELTO - SOLCION EN COMENTARIO

  1. El codigo no esta muy hay que optimizarlo mucho

  2. No me esta guardando los DATOS.

  3. El Selector de tablas por horario lo hago por php o por arduino ?

Paso a mostrar las cosas como las tengo armadas.

Codigos , Librerias, Imagenes entre otras cosas.

Codigo Usuado Actualmente en el Arduino:

#include <Wire.h>
#include "RTClib.h"
#include <LiquidCrystal_I2C.h>
#include <Keypad.h>
#include <SPI.h>
#include <Ethernet.h>
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xEE}; // Ethernet Shield MAC
byte ip[] = { 192,168,0,254 }; // Ethernet Shield IP
byte server[] = { 192,168,0,7 }; // Server IP

EthernetClient client;
String location = "http://192.168.0.7/arduino_sensor.php HTTP/1.0";


char* empleado;
const byte ledind=13;    //Rele del Abrepuertas
unsigned long clearlcd;
boolean er; 
const int  timetoclean=3000;  //msecs en quitar información display
LiquidCrystal_I2C lcd(0x3f, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
RTC_DS1307 RTC;

const byte ROWS = 4;
const byte COLS = 4; 

char keys[ROWS][COLS] =
{
  {
    '1','2','3','A'  }
  ,
  {
    '4','5','6','B'  }
  ,
  {
    '7','8','9','C'  }
  ,
  {
    '*','0','#','D'  }
};

byte rowPins[ROWS] = {
  33, 34, 35, 36};
byte colPins[COLS] = {
  37, 38, 39, 40};
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
const byte ncodigos=10;  //Nº de codigos que queremos usar
//Detallamos los codigos que darán paso
char* Codkeypad[ncodigos]={
  "123451",
  "123452",
  "123453",
  "123454",
  "123455",
  "123456",
  "123457",
  "123458",
  "123459",
  "123460"}; 
//Detallamos los saludos correspondientes a cada código
char* nombreskeypad[ncodigos]={
  "Marcos Silva",
  "Empleado2",
  "Empleado3",
  "Empleado4",
  "Empleado5",
  "Empleado6",
  "Empleado7",
  "Empleado8",
  "Empleado9",
  "Empleado10"};
String pass;
byte pos= 0;



void setup () {
  
  Wire.begin();
  RTC.begin();
  lcd.begin(20,4);
  limpialcd();
  lcd.backlight();
  RTC.adjust(DateTime(__DATE__, __TIME__));
  Ethernet.begin(mac, ip); // Init Ethernet Shield
  
  lcd.backlight();
  pinMode(ledind, OUTPUT);  //Definimos el pin13 de salida
  digitalWrite(ledind, LOW); 
}

void loop () {

  if (er==true) if (clearlcd+timetoclean<millis()) limpialcd();
  char keypadkey = keypad.getKey();
  if (keypadkey != NO_KEY) password(keypadkey);
  lcd.setCursor(1,0);
  fecha();
}

void limpialcd(){
  lcd.clear();
  lcd.setCursor(2,0);
  lcd.print("Ingrese Su clave");
  er=false;
  pos=0;
  pass=""; 
} 

void password(char key) {
  pass+= key;
  lcd.setCursor(0+pos,5);
  lcd.print(key);
  if (pos<5) 
    pos++;
  else {
    comprueba_codigos();
    pos=0;
  }

}  

void comprueba_codigos() {
  boolean encontrada=false;
  for (byte a=0; a<ncodigos;a++){ 
    String pwd = String(Codkeypad[a]);
    if (pwd==pass) {
      lcd.setCursor(0,3);
      lcd.print(nombreskeypad[a]);
      empleado=nombreskeypad[a];
      encontrada=true;
    }
  }
  lcd.setCursor(2,2);
  if (encontrada) {
    lcd.print("Codigo valido");
    digitalWrite(ledind, HIGH); 
    delay(500);  //Activamos el led durante 0,5 seg
    digitalWrite(ledind, LOW); 
    
     if (client.connect(server, 80)>0) {  // Connect to server
   client.print("GET /kevin.php?valor="); // Send the DATA with GET
   client.print(empleado);
   client.println(" HTTP/1.0");
   client.println("User-Agent: Arduino 1.0");
   client.println();
 }
 else
 {
   Serial.println("Connection FAIL");
 }

   }
  else 
  {
    lcd.print("Codigo invalido");
    lcd.setCursor(0,3); 
    lcd.print("Reintenta Nuevamente");
     if (client.connected()) {}
   else {
   Serial.println("Disconnected!");
    client.stop();
   client.flush();
 }
  }
  er=true;
  clearlcd=millis();
}

void fecha(){
  DateTime now = RTC.now();
  lcd.setCursor(1,1);
    lcd.print(now.day(), DEC);
    lcd.print('/');
    lcd.print(now.month(), DEC);
    lcd.print('/');
    lcd.print(now.year(), DEC);
    lcd.print(' ');
    lcd.print(now.hour(), DEC);
    lcd.print(':');
    lcd.print(now.minute(), DEC);
    lcd.print(':');
    lcd.print(now.second(), DEC);
    delay(100);
}

Codigo php

<?php
    $conexion = mysql_connect("localhost", "root", "******");
    mysql_select_db("horarios",$conexion);
                     
    mysql_query("INSERT INTO `horarios`.`ingreso` (`Empleado`, `Fecha`, `Hora`) VALUES ('" . $_GET['valor'] . "',CURDATE(),CURTIME())", $conexion);
 
?>

Librerias:

Wire.h
RTClib.h (Link)
LiquidCrystal_I2C.h (Link)
Keypad.h
SPI.h
Ethernet.h

Imagenes:

FALTAN SUBIRLAS :wink:

Lo que necesitara que me ayuden es a Resolver el problema del guardado que no lo hace y Optimizar un poco el codigo , se que hay muchas cosas que no sirven pero bueno , quiero tratar de hacerlo lo mejor posible.

Saludos a todos.

Ojo que hay gente que ha trabajado en cosas similiar Kevin. Ahora es tarde pero mañana te paso.
Varios estan con la misma idea y sería bueno que se unan para obtener un buen producto entre todos.

Te agrego un buen post que puede ayudarte con MySQL y PHP mas ARDUINO

Arduino, MYSQL and PHP

Solucion al problema N° 1.

EL que interfiere con los puertos MISO , MOSI y SDA en el arduino MEGA + Ethernet Shield ( SD CARD).

La solucion es desactivar la SD.

  pinMode(4,OUTPUT);
  digitalWrite(4,HIGH);

Eso deben poner antes del SPI.begin();

Nuevo codigo que uso para

Arduno Mega - Ethernet Shield - LCD Display 20x4 Blue + i2c - Reloj - Keypad 4 x 4

//WWW.arduteca.blogspot.com.es

#include <SPI.h>
#include <MFRC522.h>
#include <Wire.h>  // Comes with Arduino IDE
#include <LiquidCrystal_I2C.h>
#include <Keypad.h>
#include <Ethernet.h>
#include "RTClib.h"
LiquidCrystal_I2C lcd(0x3f, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xEE}; // Ethernet Shield MAC
byte ip[] = { 192,168,0,254 }; // Ethernet Shield IP
byte server[] = { 192,168,0,7 }; // Server IP

EthernetClient client;
RTC_DS1307 RTC;

char* empleado;

#define SS_PIN 53    //Arduino Mega
#define RST_PIN 5
MFRC522 mfrc522(SS_PIN, RST_PIN);        // Create MFRC522 instance.

const byte ledind=13;    //Rele del Abrepuertas
const int  timetoclean=3000;  //msecs en quitar información display
const int numcards=2;                                 //numero de tarjetas rfids que hay definidas
unsigned long rfid[numcards]={0x753B1102,0x537C7565}; //definimos los codigos de las tarjetas (4 primeros digitos en formato hexadecimal)
char* individuo[numcards]={"Hola Fernando","Hola Susan"};      //aqui podemos introducir las personas a la que pertenecen los targetas 
unsigned long clearlcd;
boolean er;  //Cambia de estado cuando hay información en el display
//se utiliza para hacer limpieza del display
const byte ROWS = 4; //four rows
const byte COLS = 4; //three columns

char keys[ROWS][COLS] =
  {{'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}};
 
byte rowPins[ROWS] = {33, 34, 35, 36};
byte colPins[COLS] = {37, 38, 39, 40};
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

const byte ncodigos=3;  //Nº de codigos que queremos usar
//Detallamos los codigos que darán paso
char* Codkeypad[ncodigos]={"123456",
                           "654321",
                          "000000"}; 
//Detallamos los saludos correspondientes a cada código
char* nombreskeypad[ncodigos]={"Bienvenido Marcos",
                               "Hola Sr. Rajoy",
                               "Buenas Sr. Pujol"};
String pass;
byte pos= 0;

void setup() {
  pinMode(4,OUTPUT);
  digitalWrite(4,HIGH);
  Serial.begin(9600);
  SPI.begin();                // Init SPI bus
  mfrc522.PCD_Init();        // Init MFRC522 card
  lcd.begin(20,4); 
  lcd.backlight();   //iluminación de fondo del display
  limpialcd();       //Procedimiento borrado display
  pinMode(ledind, OUTPUT);  //Definimos el pin13 de salida
  digitalWrite(ledind, LOW); 
  RTC.begin();
  RTC.adjust(DateTime(__DATE__, __TIME__));
  Ethernet.begin(mac, ip); 
}

void loop() {
  
  if (er==true) if (clearlcd+timetoclean<millis()) limpialcd();
  //limpia la información del display 
  //LEE keypad
  char keypadkey = keypad.getKey();
  if (keypadkey != NO_KEY) password(keypadkey);
  fecha();
  MFRC522::MIFARE_Key key;
  for (byte i = 0; i < 6; i++) key.keyByte[i] = 0xFF;
   // Look for new cards
  if ( ! mfrc522.PICC_IsNewCardPresent()) {
    
    return;
     }                //MIENTRAS NO LEA UNA NUEVA TARJETA EL PROGRAMA NO PASA DE AQUI
   // Select one of the cards
   if ( ! mfrc522.PICC_ReadCardSerial())    return; 
   byte piccType = mfrc522.PICC_GetType(mfrc522.uid.sak);
   byte buffer[18];  
   byte block  = 0;
   byte status;
   status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, block, &key, &(mfrc522.uid));
   if (status != MFRC522::STATUS_OK) {
           error();
           return;
        }
        // Read block
   byte byteCount = sizeof(buffer);
   status = mfrc522.MIFARE_Read(block, buffer, &byteCount);  
   if (status != MFRC522::STATUS_OK) {
	    error();
	}
        else  // Dump data
	{
        
        
        //transforma los 4 primeros numeros del bloque 0 en una variable de 4 bytes para poderla comparar con las numeraciones registradas 
   unsigned long card=0;
   byte b=0;
   for (int a=3;a>-1;a--) {
   switch (a){
        case 3:  card += buffer[b]*16777216; break;
        case 2:  card += buffer[b]*65536; break;
        case 1:  card += buffer[b]*256; break;
        case 0:  card += buffer[b];break;
        }
        b++;}
   boolean encontrada2=false;
   for (byte a=0;a<numcards;a++) {                      
          if (rfid[a]==card) {
            lcd.setCursor(0,3);
            lcd.print(individuo[a]);
            empleado=individuo[a];
            encontrada2=true;}} //si el num de la tarjeta coincide con alguno de los definidos dice el nombre
   lcd.setCursor(0,2);
   if (encontrada2) {
              lcd.print("Tarjeta valida");
              digitalWrite(ledind, HIGH); 
              delay(500);  //Activamos el led durante 0,5 seg
              digitalWrite(ledind, LOW); }
              if (client.connect(server, 80)>0) {  // Connect to server
              client.print("GET /kevin.php?valor="); // Send the DATA with GET
              client.print(empleado);
              client.println(" HTTP/1.0");
              client.println("User-Agent: Arduino 1.0");
              client.println();
       }
   else 
            {lcd.print("Tarjeta invalida");
            lcd.setCursor(0,3); 
            lcd.print("Vuelvase a casa");
            if (client.connected()) {}
             else {
            client.stop();
            client.flush();
            }
         }
            
            er=true;
            clearlcd=millis();}
   mfrc522.PICC_HaltA(); // Halt PICC
   mfrc522.PCD_StopCrypto1();  // Stop encryption on PCD       
}
//Procedimiento para cuando ha habido un error en la lectura
//de la numeración de la tarjeta
void error() {
  lcd.clear();
  lcd.setCursor(0,4);
  lcd.print("Error de lectura");
  clearlcd=millis();
  limpialcd();
  er=true;}
void limpialcd(){
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("  Codigo o Tarjeta");
  er=false;
  pos=0;
  pass=""; } 

//Hace de contador de digitos al introducir codigo y cuando
//ya se han introducido 6 digitos llama al procedimiento para
//su compruebacion
void password(char key) {
   pass+= key;
  lcd.setCursor(0+pos,3);
  lcd.print("*");
  if (pos<5) 
    pos++;
    else {comprueba_codigos();pos=0;}

}  
//Comprueba si el codigo introducido esta registrado
//si lo está da acceso
void comprueba_codigos() {
  boolean encontrada=false;
  for (byte a=0; a<ncodigos;a++){ 
          String pwd = String(Codkeypad[a]);
          if (pwd==pass) {
            lcd.setCursor(0,3);
            lcd.print(nombreskeypad[a]);
            encontrada=true;}}
           lcd.setCursor(0,2);
    if (encontrada) {
              lcd.print("Codigo Valido");
              digitalWrite(ledind, HIGH); 
              delay(500);  //Activamos el led durante 0,5 seg
              digitalWrite(ledind, LOW); }
              if (client.connect(server, 80)>0) {  // Connect to server
              client.print("GET /kevin.php?valor="); // Send the DATA with GET
              client.print(empleado);
              client.println(" HTTP/1.0");
              client.println("User-Agent: Arduino 1.0");
              client.println();
              }
   else 
            {lcd.print("Codigo invalido");
            lcd.setCursor(0,3); 
            lcd.print("Vuelvase a casa");
            if (client.connected()) {}
             else {
            client.stop();
            client.flush();
                   }
         
            er=true;
            clearlcd=millis();}  
       }


void fix1 (){
  lcd.setCursor(0,3);
  delay(100);
  limpialcd();
  
 }  
 void fecha(){
  DateTime now = RTC.now();
  lcd.setCursor(1,1);
    lcd.print(now.day(), DEC);
    lcd.print('/');
    lcd.print(now.month(), DEC);
    lcd.print('/');
    lcd.print(now.year(), DEC);
    lcd.print(' ');
    lcd.print(now.hour(), DEC);
    lcd.print(':');
    lcd.print(now.minute(), DEC);
    lcd.print(':');
    lcd.print(now.second(), DEC);
    delay(100);
}

Repito a este codigo le falta mucha optimizacion :heart:

Saludos

surbyte:
Te agrego un buen post que puede ayudarte con MySQL y PHP mas ARDUINO

Arduino, MYSQL and PHP

Gracias ! , se mucho de php. La parte PHP es facil el tema es Arduino que la variable char* "Empleado" no tiene ningun valor.

Tal vez te ayude que vi una librería que permite la conexión de arduino con mysql. La busco y te la agrego.

Hola!

Me parece un proyecto interesante. Te doy mi humilde punto de vista por si te puede orientar:

En primer lugar, yo no usaría el reloj, ya que la hora puede registrarse desde el servidor al que le envías los datos. En todo caso lo dejaría para mostrarle la información de la hora al trabajador que esté fichando. Pero para asegurar que si se va la luz la hora seguirá siendo correctamente registrada, ese dato lo obtendría mediante php directamente en el server. (Si la luz se va, y la pila del reloj coincide que se ha agotado, en el lcd saldrá mal la hora, pero en la base de datos estará bien registrada). Incluso, dependiendo del tiempo que le quieras dedicar al desarrollo, se podría hacer que el arduino cuando arranque el programa, se ponga en hora automáticamente haciendo una petición al servidor web...

El lector RFID realmente depende de la seguridad que quieras tener para las tarjetas. El Lector RFID-RC522 tiene la ventaja que puedes escribir tu en la tarjeta (y ponerle contraseña para acceder a los datos), pero son mas caros tanto el grabador como las tarjetas/llaveros RFID, necesita más conexiones para poder interactuar y no creo que sea necesario para el fin que buscas. El módulo EM4100 125Khz RFID funciona con menos cables mediante uart (RX-TX) que es muy fácil de usar. Las tarjetas tienen su numero de serie propio y pueden ser totalmente válidas para identificarse.

Si vas a usar RFID ¿para que un keypad? Yo tampoco lo pondría.

El display I2C me parece una buena opción para notificar al usuario de la acción efectuada correcta o incorrectamente. (yo añadiría un buzzer para notificación sonora también).

Hasta aquí todo es bastante fácil (tanto el código como el hardware).

La parte difícil desde mi punto de vista es el cálculo de las horas por la cantidad de posibles excepciones que tiene. (trabajador que enferma y se va a mitad de su jornada, el que no viene directamente, el que sale a hacer un trabajo y termina fuera su jornada, el que sale por algún motivo personal, pero luego vuelve al trabajo, etc...).

Todo lo que puedas hacer desde el servidor, yo lo haría desde allí ya que un servidor es mas potente, rápido y fácil de programar que un arduino. Y en cuanto a los datos, los enviaría desde el arduino haciendo peticiones GET al archivo php que corresponda (es lo mas sencillo).

Espero haberte ayudado y estaré atento a tus avances.

Creo que suma el keypad porque muchos Relojes de este tipo tienen la opción de pasar la huella y el pin, o el TAG y el pin y para cargar el pin requieres de un teclado.

Si esa es su idea me parece bien usarlo. Pero en el proyecto no he entendido esa intención.

Voy a ver si saco un poco de tiempo y puedo hacer alguna prueba para ver el problema de la comunicación.

EscuderoKevin - ¿has probado a ver si el nombre del empleado llega a recibirse en el servidor? guardándolo en un txt o algo así...

Yo hice un proyecto similar pero con NFC

Como conectas el c++ del arduino al PhP?????, yo lo hago recogiendo los datos por el COM y luego los envio a un fichero que posteriormente es disparado con un CROW en Windows.

buenos días compañeros, yo estoy en las mismas que ustedes con la diferencia que mi proyecto lo tengo funcionando de esta manera.

esta basado en un mega con un RC522 y un ethernet, mi experiencia con este proyecto ha sido un poco traumatica ya que en su momento no manejaba ni php y muchos medos msql jajaj pero bueno me toco aprender un poco a la fuerza ya que esto es para empresa donde laboro y no podía salir con un chorro de babas

aquí de jo mi código esta funcionando 100% full, estoy resolviendo problemas con la estabilidad del modulo ethernet por el tema del reset luego de un apagón y he notado que estos módulos aveces se cuelgan y dejan de enviar la los datos según he leído por la cantidad de trafico tcp y udp de la red de la compañía

codigo.ino (26.1 KB)

Y el php?