Nivel: Intermedio
¿Qué tengo que saber para este post?
- Haber programado alguna vez Arduino saber declarar entradas y salidas digitales.
- Saber utilizar el Serial y el SoftwareSerial.
- Saber SQL básico (INSERT y SELECT).
- Saber configurar y crear una base de datos MySQL o MariaDB (no voy a explicarlo).
—————————————
Para todo hay una primera vez. Saben que en mi blog nunca hice un post utilizando Arduino, pero no utilizarlo en este ejemplo implicaría una montaña de trabajo y muchas horas de prueba y error. Por eso, para mostrar un concepto este ejemplo me parece ideal. Para empezar, si bien lo suponía, no sabía que existiera una biblioteca (sí, se dice biblioteca, no librería) que tuviera la interfaz ya lista para hacer consultas en una base de datos MySQL (o MariaDB), pero por azares del destino vi un proyecto que utilizaba MySQL Connector aportado por el Dr. Charles Bell. Mis sinceros respetos y agradecimientos por el trabajo del don.
¿Qué necesito?
Para poder utilizar esta biblioteca, se necesita el Ethernet Shield o WiFi (no probé por eso no muestro ningún shield) y también es compatible con el ESP32 dando ejemplos concretos con esta placa. Además recomendaría utilizar un Arduino Mega, aunque yo el ejemplo lo hice con un UNO, pero el espacio que me quedó es muy marginal para una implementación más compleja. Además utilicé un módulo de lectura de tarjetas RFID de 125KHz RDM6300, aunque es trivial, pueden utilizar cualquier otra cosa que tengan a mano. Además utilicé 2 LEDs, un pulsador y resistencias. Les dejo el diagrama de conexión hecho con Fritzing:
En cuanto a materia de Software, necesitan tener una base de datos MySQL o MariaDB. Si estás en Windows siento lástima por vos podés usar XAMPP o similares, si están en GNU/Linux no están más lejos de hacer una instalación simple con apt, yum, pacman o con Docker. Pero deben tener en cuenta configurar su DB para poder acceder de manera remota cosa que no voy a cubrir en este post. También puede utilizar algún servicio gratuito de prueba online (p.e. Free Remote MySQL, hay otros), pero para eso necesitan modificar el ejemplo para utilizar el dnsclient.
La base de datos la llame arduino y tiene una sola tabla llamada personas. Aquí les dejo el dump. Para administrar la base de datos, si no tiene mucha idea pueden utilizar el phpMyAdmin o DBeaver. En cuanto al entorno de programación, utilicé PlatformIO, pero el Arduino IDE no supondría ningún cambio de código.
CREATE DATABASE `arduino`;
USE `arduino`;
DROP TABLE IF EXISTS `personas`;
CREATE TABLE `personas` (
`id` varchar(12) NOT NULL,
`nombre` varchar(50) DEFAULT NULL,
`apellido` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
¿Cómo funciona y qué hace?
En sí, el ejemplo es bastante simple. Creo que me tomó más tiempo aplicar el protocolo de validación de las tarjetas que la conexión a la base de datos en sí. El esquema es simple, el Arduino lee la tarjeta utilizando el RDM6300 y conectado por un SoftwareSerial conectado en los terminales 2 (Rx) y 3 (Tx) que transmite los 14 bytes del protocolo de la tarjeta RFID. Luego se hace una consulta a través del cable ethernet a la IP del Servidor MariaDB (en mi caso 192.168.1.105) que si encuentra ese código de tarjeta devolverá el nombre y apellido de la persona, y en caso contrario devolverá una respuesta vacía.
Cuando la tarjeta pasa por el lector llega por el objeto RFID y se examina que la lectura sea correcta. Estas tarjetas tienen códigos de 5 bytes que son transmitidos en formato ASCII arrancando con un Start of Text (0x02) y finaliza con un End of Text (0x03), los bytes son transmitidos en caracteres hexadecimales (por lo tanto serán 10 bytes) y luego un checksum (2 bytes más) siendo en total 14 bytes transmitidos del RDM6300 al Arduino.
Cada vez que se lee una tarjeta que se encuentra en la base de datos se enciende el LED verde y se muestra el nombre de la persona por el Monitor Serie. Si la tarjeta no se encuentra en la base de datos parpadeará 2 veces el LED rojo.
Además le programe un modo de registro para nuevas tarjetas, para eso está el pulsador en el esquema del principio. Una vez presionado tenemos 5 segundos (indicados por el LED rojo) para pasar la tarjeta nueva. Cada vez que hay una lectura correcta de una tarjeta se enciende el LED verde, y si hay una lectura incorrecta o si no es posible registrar parpadeará 2 veces el LED rojo. Al momento del registro solo el ID de 5 bytes de la tarjeta queda en la DB dejando la columna de nombre y apellido con valor NULL. Eso quiere decir que debemos completarla a mano en la DB (o podría ser otra aplicación de software que administre fichadas, por ejemplo).
¡Ya!¡Dame el maldito código!
El código completo en gitlab. A continuación voy a hacer un par de aclaraciones, para que sea un poquito más digerible, o al menos voy a intentarlo. Lo primero que hay que hacer es cambiar la configuración de la base de datos para que coincida con la tuya:
IPAddress server_addr(192, 168, 1, 105); // IP del MySQL *server*
const char user[] = "root"; // MySQL login username
const char password[] = "admin"; // MySQL login password
Allí se completa lo obvio, la IP donde está corriendo el servidor el usuario y contraseña para el acceso a la base de datos con los permisos correctos. En el setup()
se hará el intento de conexión a la base de datos, y en el port serie deberá verse el nombre de tu servidor y versión del mismo:
Serial.println(F("Conectando..."));
if (conn.connect(server_addr, 3306, user, password)) {
delay(1000);
} else { // Si no se puede conectar a la base muere ahí
Serial.println(F("No se pudo conectar"));
while(true); // halt
}
En caso de que no se haya establecido la conexión con la DB el programa queda «colgado» en el while(true)
hasta que se resetee el Arduino.
En el estado «normal» (si el pulsador no fue presionado), simplemente esperamos a que llegue una tarjeta por el puerto serie del RFID. Si llega una tarjeta haremos la query de consulta para saber si está o no registrado que no es más que un simple SELECT
:
SELECT nombre,apellido FROM arduino.personas WHERE id='tarjeta_leida'
Y se ve más o menos así:
if(check_rfid()) {
MySQL_Cursor *cur_mem = new MySQL_Cursor(&conn);
String query = "SELECT apellido,nombre FROM arduino.personas WHERE id='"+tarjeta_leida+"'";
if(cur_mem->execute(query.c_str())) {
row_values *row = NULL;
column_names *columns = cur_mem->get_columns();
row = cur_mem->get_next_row();
if (row != NULL) {
Serial.print(row->values[0]);
Serial.print(", ");
Serial.println(row->values[1]);
show_ok();
while((row = cur_mem->get_next_row()) != NULL);
} else {
show_error();
}
} else { // si hubo un error en la query:
show_error();
}
delete cur_mem;
}
En la linea 6, debemos obligatoriamente leer el nombre de las columnas, aunque no vayamos a utilizarlas. Y luego en la linea 13 consumimos cualquier otra fila que podría haber llegado a devolver la query, porque sino se rompe el programa. Si la fila llegó vacía entonces titila el LED rojo 2 veces indicando que la tarjeta no está registrada (show_error()
), esto también ocurre si es que llega a haber un error al ejecutarse la query. En caso de que la tarjeta se haya encontrado en la base de datos mostramos el nombre y apellido de la persona en el monitor Serie y prendemos el LED verde (show_ok()
).
Ahora veamos qué pasa si alguien apreta el botón para registrar una nueva tarjeta. En ese caso debemos hacer un simple INSERT:
INSERT INTO arduino.personas (id) VALUES ('tarjeta_leida')
Que en el código se ve algo así:
uint32_t time_out = now+5000; // 5 segundos para el time_out
digitalWrite(led_error, HIGH); // Se mantiene prendido el LED rojo...
while(now < time_out) {
if(check_rfid()) {
digitalWrite(led_error, LOW);
MySQL_Cursor *cur_mem = new MySQL_Cursor(&conn);
String query = "INSERT INTO arduino.personas (id) VALUES ('"+tarjeta_leida+"')";
if(cur_mem->execute(query.c_str()))
show_ok(); // Se registró con éxito
else
show_error(); // sino titila el rojo 2 veces.
delete cur_mem;
break;
}
now = millis();
}
digitalWrite(led_error, LOW); // Si se llegó al time_out se apaga el LED rojo
Como se observa simplemente se deja correr un tiempo con la función millis()
que dura 5 segundos, al menos que se lea una tarjeta, donde sin importar si se pudo o no registrar termina el bucle con un break
.
Hay algunos detalles que tienen que ver con la implementación en sí, pero no vienen al caso, pueden analizarlo en el código completo en gitlab. Pero además les dejo el video de la prueba que hice, que ya he compartido en otras redes sociales:
AcoranTf
Muy interesante articulo, que mezcla varios aspectos poco explotados de Arduino.
Voy a intentar adaptarlo para conseguir un registrador, (datalogger), de red electrica por horas. Este incluira: voltaje, corriente, potencia, energia y precio. Todo ello una vez cada hora.
No estoy seguro de conseguir todo lo que tengo en mente al respecto.
Ya comentare.
Che, me gusto tu autodefinicion, que comparto en ideas e intereses, aunque desgraciadamente no en conocimientos.
Gracias por compartir.
Un abrazo.
msavalos
Espero ver ese datalogger! Manda tu progreso. Quedó atento y si tenés dudas consultame. Exitos!
Frans
si puede conectar la tarjeta rfid -rc522a
msavalos
Frans, claro, pero deberías adaptar tu código para que funcione con ese tipo de tarjetas/módulo. Te dejo un link a un tutorial de naylamp: https://naylampmechatronics.com/blog/22_tutorial-modulo-lector-rfid-rc522.html