En este post te mostraré cómo implementar un pequeño monedero electrónico, tarjetas de saldo o tarjetas de débito usando PHP y etiquetas RFID.
Como bien sabes, las etiquetas RFID están presentes en varios componentes, entre ellos una tarjeta. Así que podemos usar esa tarjeta para guardar el saldo de un usuario.
Lo que te mostraré será cómo guardar y leer el dinero / saldo en las tarjetas, mostrarlo en una LCD para que el usuario lo pueda ver, y además implementar la parte del servidor con PHP para poder recargar y comprar cosas.
Básicamente será un monedero electrónico o una tarjeta con la que el usuario podrá comprar y recargar. A partir de aquí puedes mejorar el código para adaptarlo a tus necesidades.
Lo que yo usaré es la tarjeta NodeMCU ESP8266, el lector MFRC522 RFID-RC522 y una LCD de 16 x 2 usando un módulo I2C. La comunicación con el servidor la haremos a través del WiFi que ya viene integrado en la ESP8266.
El circuito de conexión queda como se ve a continuación. Obviamente tú puedes reemplazar componentes, mejorar conexiones u optimizar el modelo si es que sabes lo que haces.
En mi caso lo he montado así:
Aquí voy a saltarme algunos pasos básicos, así que te recomiendo ir a los posts que citaré a continuación en caso de que tengas dudas adicionales o quieras aprender a fondo. También me voy a saltar lo de las librerías, pues eso ya está en sus respectivos posts.
Yo usaré Visual Studio Code para programar la tarjeta. Vamos a hacer peticiones HTTP a PHP, además de leer y escribir datos en las tarjetas RFID. También vamos a imprimir en la LCD, para lo cual necesitamos conocer la dirección I2C.
Tan pronto se lea una tarjeta, vamos a mostrar el saldo del usuario en la LCD. Si la tarjeta es nueva, el saldo será 0. Además de mostrar el dinero de la tarjeta vamos a comenzar a hacer peticiones al servidor con PHP y Apache para esperar dos cosas:
Mientras no haya órdenes por parte del servidor, la ESP8266 va a estar consultando cada 5 segundos. Tan pronto reciba una orden, la va a ejecutar e indicar los resultados a través de la LCD.
Para realizar una compra o una recarga he escrito el frontend en JavaScript. Lo que se hace es simplemente indicarle al servidor PHP la orden que le tiene que dar a la tarjeta, y después de eso igualmente comenzamos a realizar peticiones cada 2 segundos para ver lo que la tarjeta ha respondido.
Aquí dejo el código completo de la tarjeta. No olvides cambiar la dirección del I2C, así como las credenciales para conectar a la red WiFi y la dirección de tu servidor, que puede ser de la red local o un servidor en internet (para esto último tendrás que configurar el certificado en caso de usar https).
Por cierto, fíjate en las funciones de guardarSaldo
y obtenerSaldo
, pues son muy importantes y se encargan de leer o escribir los bloques de la tarjeta RFID. Si te quedan dudas recuerda que anteriormente te dejé los posts en donde explico eso más a fondo.
/*
____ _____ _ _ _
| _ \ | __ \ (_) | | |
| |_) |_ _ | |__) |_ _ _ __ _____| |__ _ _| |_ ___
| _ <| | | | | ___/ _` | '__|_ / | '_ \| | | | __/ _ \
| |_) | |_| | | | | (_| | | / /| | |_) | |_| | || __/
|____/ \__, | |_| \__,_|_| /___|_|_.__/ \__, |\__\___|
__/ | __/ |
|___/ |___/
____________________________________
/ Si necesitas ayuda, contáctame en \
\ https://parzibyte.me /
------------------------------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
Creado por Parzibyte (https://parzibyte.me).
------------------------------------------------------------------------------------------------
| IMPORTANTE |
Si vas a borrar este encabezado, considera:
Seguirme: https://parzibyte.me/blog/sigueme/
Y compartir mi blog con tus amigos
También tengo canal de YouTube: https://www.youtube.com/channel/UCroP4BTWjfM0CkGB6AFUoBg?sub_confirmation=1
Twitter: https://twitter.com/parzibyte
Facebook: https://facebook.com/parzibyte.fanpage
Instagram: https://instagram.com/parzibyte
Hacer una donación vía PayPal: https://paypal.me/LuisCabreraBenito
------------------------------------------------------------------------------------------------
*/#include <ESP8266WiFiMulti.h>
#include <ESP8266HTTPClient.h>
#include <Arduino.h>
#include <SPI.h>
#include <MFRC522.h>
#include <LiquidCrystal_I2C.h>
#define LONGITUD_BYTES 18
#define LONGITUD_BYTES_ESCRITURA 16
#define SEPARADOR_ORDENES_SERVIDOR ";"
#define ORDEN_RECARGAR "r"
#define ORDEN_DESCONTAR "d"
/*
Pines para conectar el lector
*/#define RST_PIN D3
#define SS_PIN D4
// Credenciales para conectar a la red
const char *ssid = "Aquí va el nombre de tu red";
const char *password = "Aquí va la contraseña de tu red";
const String DIRECCION_SERVIDOR = "http://192.168.1.82/rfid_saldo";
// Conexión a WiFi
ESP8266WiFiMulti wifiMulti;
// La LCD
LiquidCrystal_I2C lcd(0x3f, 16, 2);
// El lector
MFRC522 lector(SS_PIN, RST_PIN);
MFRC522::MIFARE_Key clave;
int tarjetaLeidaDesdeLoop = 0;
double saldoGlobal;
void obtenerSaldo(double *saldo)
{
if (!lector.PICC_IsNewCardPresent())
{
*saldo = -1;
Serial.println("No hay nueva tarjeta presente");
return;
}
if (!lector.PICC_ReadCardSerial())
{
*saldo = -1;
Serial.println("Error leyendo serial");
return;
}
byte bloque, longitud, buferLectura[LONGITUD_BYTES];
MFRC522::StatusCode estado;
bloque = 1;
estado = lector.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, bloque, &clave, &(lector.uid));
if (estado != MFRC522::STATUS_OK)
{
Serial.println("Error autenticando");
Serial.println(lector.GetStatusCodeName(estado));
*saldo = -1;
return;
}
longitud = LONGITUD_BYTES;
estado = lector.MIFARE_Read(bloque, buferLectura, &longitud);
if (estado != MFRC522::STATUS_OK)
{
Serial.println("Error leyendo bloque");
Serial.println(lector.GetStatusCodeName(estado));
*saldo = -1;
return;
}
char mensaje[LONGITUD_BYTES] = "";
for (uint8_t i = 0; i < LONGITUD_BYTES - 2; i++)
{
mensaje[i] = buferLectura[i];
}
double saldoLeido = atof(mensaje);
Serial.println("Se lee el saldo");
Serial.println(saldoLeido);
*saldo = saldoLeido;
lector.PICC_IsNewCardPresent();
}
void guardarSaldo(double saldo)
{
if (!lector.PICC_IsNewCardPresent())
{
Serial.println("No hay nueva tarjeta presente al guardar saldo");
return;
}
if (!lector.PICC_ReadCardSerial())
{
Serial.println("Error leyendo serial");
return;
}
Serial.println("Se guarda el saldo");
Serial.println(saldo);
byte bloque, buferEscritura[LONGITUD_BYTES_ESCRITURA];
// Convertir saldo a cadena
char cadena[LONGITUD_BYTES_ESCRITURA] = "";
snprintf(cadena, LONGITUD_BYTES_ESCRITURA, "%.2lf", saldo);
// Copiar cadena al búfer
for (uint8_t i = 0; i < LONGITUD_BYTES_ESCRITURA; i++)
{
buferEscritura[i] = cadena[i];
}
MFRC522::StatusCode estado;
bloque = 1;
estado = lector.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, bloque, &clave, &(lector.uid));
if (estado != MFRC522::STATUS_OK)
{
Serial.println("Error autenticando");
Serial.println(lector.GetStatusCodeName(estado));
return;
}
estado = lector.MIFARE_Write(bloque, buferEscritura, LONGITUD_BYTES_ESCRITURA);
if (estado != MFRC522::STATUS_OK)
{
Serial.println("Error escribiendo bloque");
Serial.println(lector.GetStatusCodeName(estado));
return;
}
// Ya pueden retirar la tarjeta
lector.PICC_HaltA();
lector.PCD_StopCrypto1();
tarjetaLeidaDesdeLoop = 0;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("SALDO:");
lcd.setCursor(6, 0);
lcd.print(saldo);
lcd.setCursor(0, 1);
lcd.print("RETIRE LA TARJETA");
}
void setup()
{
// Iniciar comunicación Serial. Esto es útil solo para depurar, después se puede remover
Serial.begin(9600);
while (!Serial)
{
// Esperar serial. Nota: la tarjeta NO HARÁ NADA hasta que haya comunicación Serial (es decir, que el monitor serial sea abierto)
// si tú no quieres esto, simplemente elimina todas las llamadas a Serial
}
// Iniciar LCD
lcd.begin(16, 2); // <----------- En algunas versiones de NodeMCU (v2) debe llamarse antes de todo, antes de SPI.begin(); y antes de lector.PCD_Init();
lcd.init(); // Encender la LCD
lcd.backlight();
// Iniciar lector
SPI.begin();
lector.PCD_Init();
// Esperar algunos segundos
delay(4);
// Preparar la clave para leer las tarjetas RFID
for (byte i = 0; i < 6; i++)
{
clave.keyByte[i] = 0xFF;
}
// Aquí puedes agregar varias redes. La tarjeta se conectará a la más cercana
wifiMulti.addAP(ssid, password);
// wifiMulti.addAP("Otra red", "Contraseña");
// Esperar conexión WiFi. La tarjeta NO HARÁ NADA si no hay conexión WiFi
Serial.print("Conectando al WiFi...");
while (wifiMulti.run() != WL_CONNECTED)
{
delay(250);
Serial.print(".");
}
lcd.clear();
lcd.print("TODO OK");
lcd.setCursor(0, 1);
lcd.print("COLOCAR RFID");
Serial.println("Todo OK");
}
// Loop infinito...
void loop()
{
if (WiFi.status() != WL_CONNECTED)
{
// Si no hay WiFi, no hacemos nada
Serial.println("No hay WiFi");
lcd.clear();
lcd.print("NO HAY");
lcd.setCursor(0, 1);
lcd.print("WIFI");
return;
}
// Si no han colocado la tarjeta, vamos a ver si hay alguna presente
if (!tarjetaLeidaDesdeLoop)
{
// Si no hay ninguna, nos detenemos
if (!lector.PICC_IsNewCardPresent())
{
return;
}
// Si no se puede elegir la tarjeta, nos detenemos
if (!lector.PICC_ReadCardSerial())
{
return;
}
Serial.println("Tarjeta leída");
// hasta aquí ya hemos leído la tarjeta, así que marcamos la bandera en true (1)
tarjetaLeidaDesdeLoop = 1;
// Curiosamente esta línea hace que las siguientes llamadas a PICC_IsNewCardPresent devuelvan true
lector.PICC_IsNewCardPresent();
// Obtenemos el saldo de la tarjeta actualmente colocada en el lector
obtenerSaldo(&saldoGlobal);
// Lo imprimimos en la LCD
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("SALDO:");
lcd.setCursor(6, 0);
lcd.print(saldoGlobal);
lcd.setCursor(0, 1);
lcd.print("NO RETIRE RFID");
lector.PCD_StopCrypto1();
}
else
{
Serial.println("Tarjeta en lector. Verificando con servidor");
// Significa que la tarjeta ya está colocada en el lector, vamos a consultar el servidor para ver si hay que hacer algún cambio
HTTPClient http;
// Invocamos al servidor y le pasamos el saldo que hay actualmente
String url = DIRECCION_SERVIDOR + "/index.php?saldo=" + saldoGlobal;
http.begin(url);
int httpCode = http.GET();
if (httpCode > 0)
{
if (httpCode == HTTP_CODE_OK)
{
// si el servidor responde correctamente, obtenemos lo que nos haya respondido
String payload = http.getString();
// Leemos la respuesta en una cadena válida de C, no de la clase String
char payloadComoCadenaValida[50] = "";
for (uint8_t i = 0; i < payload.length(); i++)
{
payloadComoCadenaValida[i] = payload.charAt(i);
}
// El servidor nos dará una orden como "d;10" que quiere decir "descontar 10" así que debemos separar la cadena por ;
char delimitador[] = ";";
char *ordenExtraida = strtok(payloadComoCadenaValida, delimitador);
char *saldoExtraido = strtok(NULL, delimitador);
if (ordenExtraida != NULL && ordenExtraida != NULL)
{
// Extraemos el saldo que el servidor nos indica
double diferenciaSaldo = atof(saldoExtraido);
// Si se recarga, sumamos el saldo y lo guardamos
if (strcmp(ordenExtraida, ORDEN_RECARGAR) == 0)
{
guardarSaldo(saldoGlobal + diferenciaSaldo);
}
else if (strcmp(ordenExtraida, ORDEN_DESCONTAR) == 0)
{
// En este caso, se descuenta el saldo
double nuevoSaldo = saldoGlobal - diferenciaSaldo;
// Guardar el nuevo saldo solo si el usuario tiene lo suficiente
if (nuevoSaldo >= 0)
{
guardarSaldo(nuevoSaldo);
}
else
{
// Si el saldo fuera insuficiente, se indica y se guarda el mismo que había en la tarjeta. Es decir, no se hace ningún cambio
guardarSaldo(saldoGlobal);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("SALDO INSUFICIENTE");
lcd.setCursor(0, 1);
lcd.print("RETIRE TARJETA");
}
}
}
}
else
{
Serial.println("Error: httpCode es " + http.errorToString(httpCode));
}
}
else
{
Serial.println("Error en la solicitud" + http.errorToString(httpCode));
}
http.end(); //Cerramos la solicitud
// Y hacemos esta petición cada 5 segundos
delay(5000);
}
}
Fíjate en que para las órdenes del servidor estoy usando el separador de ;
y luego utilizo strtok para separar la orden y el saldo. Por otro lado estoy usando strcmp para comparar las cadenas.
Veamos un poco el lado del servidor para este monedero con PHP y la tarjeta ESP8266 que bien podría ser remplazada por un Arduino. Primero tenemos la interfaz con productos estáticos (más tarde se podrían obtener desde una base de datos):
Recuerda que debes acceder al lugar en donde hayas montado tu proyecto y acceder a comprar.php
, en mi caso lo he montado en C:\xampp\htdocs\rfid_saldo
así que la URL es localhost/rfid_saldo/comprar.php
.
Cada producto tiene un data-precio
para indicar el precio, así:
<!--
Guardamos el precio del producto en el data-precio
-->
<tbody>
<tr>
<td>Galletas</td>
<td>10.5</td>
<td>
<button class="button is-info comprar" data-precio="10.5">Comprar</button>
</td>
</tr>
<tr>
<td>Champú</td>
<td>5000</td>
<td>
<button class="button is-info comprar" data-precio="5000">Comprar</button>
</td>
</tr>
<tr>
<td>Audífonos</td>
<td>450</td>
<td>
<button class="button is-info comprar" data-precio="450">Comprar</button>
</td>
</tr>
<tr>
<td>Mi nuevo producto</td>
<td>2000</td>
<td>
<button class="button is-info comprar" data-precio="2000">Comprar</button>
</td>
</tr>
<tr>
<td>Mi otrooo producto</td>
<td>123</td>
<td>
<button class="button is-info comprar" data-precio="123">Comprar</button>
</td>
</tr>
</tbody>
Luego de eso se escucha el clic del botón, se extrae el precio y se le solicita al servidor que le indique al lector descontar esa cantidad:
// Si hacen clic en un botón para comprar...
for (const $boton of $botonesComprar) {
$boton.onclick = async () => {
// Extraemos precio y le decimos al servidor que se ponga en modo "descontar saldo" tan pronto el lector lo "contacte"
const precio = parseFloat($boton.dataset.precio);
$estado.textContent = "Estableciendo conexión con servidor...";
const respuestaRaw = await fetch("./establecer_modo_compra.php?saldo=".concat(precio));
const respuestaJson = await respuestaRaw.json();
if (respuestaJson) {
$estado.textContent = "OK. Coloque la tarjeta en el lector";
} else {
$estado.textContent = "Error estableciendo comunicación con servidor";
}
// Ahora el servidor ya está en espera de que el lector "le hable". Así que consultamos cada 2 segundos si hay novedades
const esperarLector = async () => {
// Deshabilitamos todos los botones, pues estamos esperando
$botonesComprar.forEach($boton => {
$boton.disabled = true;
if (!$boton.classList.contains("is-loading")) {
$boton.classList.add("is-loading");
}
});
// Verificamos...
$estado.textContent = "Verificando...";
const respuestaRaw = await fetch("./ver_mensaje_lector.php");
const texto = await respuestaRaw.text();
// Si se devuelve una cadena no vacía, entonces la mostramos (la cadena puede tener un mensaje de éxito o de error)
if (texto) {
$estado.textContent = texto;
$botonesComprar.forEach($boton => {
$boton.disabled = false;
$boton.classList.remove("is-loading")
});
} else {
// Si el servidor indica que el lector no se ha comunicado, lo indicamos y volvemos a intentar dentro de 2 segundos
$estado.textContent = "No se ha leído nada. Recuerde colocar la tarjeta en el lector. Intentando de nuevo...";
setTimeout(esperarLector, 2000);
}
};
esperarLector();
};
}
Y después de eso va a estar invocando a la función esperarLector
para que nos indique cuando el lector haya indicado que se ha descontado el saldo del usuario.
El código de PHP que establece el modo de compra es el siguiente:
<?php
/*
____ _____ _ _ _
| _ \ | __ \ (_) | | |
| |_) |_ _ | |__) |_ _ _ __ _____| |__ _ _| |_ ___
| _ <| | | | | ___/ _` | '__|_ / | '_ \| | | | __/ _ \
| |_) | |_| | | | | (_| | | / /| | |_) | |_| | || __/
|____/ \__, | |_| \__,_|_| /___|_|_.__/ \__, |\__\___|
__/ | __/ |
|___/ |___/
____________________________________
/ Si necesitas ayuda, contáctame en \
\ https://parzibyte.me /
------------------------------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
Creado por Parzibyte (https://parzibyte.me).
------------------------------------------------------------------------------------------------
| IMPORTANTE |
Si vas a borrar este encabezado, considera:
Seguirme: https://parzibyte.me/blog/sigueme/
Y compartir mi blog con tus amigos
También tengo canal de YouTube: https://www.youtube.com/channel/UCroP4BTWjfM0CkGB6AFUoBg?sub_confirmation=1
Twitter: https://twitter.com/parzibyte
Facebook: https://facebook.com/parzibyte.fanpage
Instagram: https://instagram.com/parzibyte
Hacer una donación vía PayPal: https://paypal.me/LuisCabreraBenito
------------------------------------------------------------------------------------------------
*/ ?>
<?php
// Le indicamos al lector lo que debe hacer. En este caso es "d;SALDO" es decir, descontar lo que haya en $saldo, misma variable que nos la darán al hacer click
// en "comprar"
include_once "constantes.php";
$saldo = $_GET["saldo"];
file_put_contents(ARCHIVO_RESPUESTA_LECTOR, ""); // Limpiar lo que haya dicho la ESP8266
file_put_contents(ARCHIVO_ORDEN_LECTOR, "d;$saldo"); // Indicarle al lector lo que tiene que hacer
// Decirle a la página de compra que la operación de cambio de operación de lector fue exitosa
echo json_encode(true);
Después de recibir una orden, el lector va a respondernos para saber si la transacción ha sido exitosa, ya que para este proyecto de tarjetas de saldo con PHP y RFID se puede dar el caso de que el saldo sea insuficiente o alguna otra situación.
Para ello PHP se encarga de establecer la respuesta del lector:
<?php
/*
____ _____ _ _ _
| _ \ | __ \ (_) | | |
| |_) |_ _ | |__) |_ _ _ __ _____| |__ _ _| |_ ___
| _ <| | | | | ___/ _` | '__|_ / | '_ \| | | | __/ _ \
| |_) | |_| | | | | (_| | | / /| | |_) | |_| | || __/
|____/ \__, | |_| \__,_|_| /___|_|_.__/ \__, |\__\___|
__/ | __/ |
|___/ |___/
____________________________________
/ Si necesitas ayuda, contáctame en \
\ https://parzibyte.me /
------------------------------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
Creado por Parzibyte (https://parzibyte.me).
------------------------------------------------------------------------------------------------
| IMPORTANTE |
Si vas a borrar este encabezado, considera:
Seguirme: https://parzibyte.me/blog/sigueme/
Y compartir mi blog con tus amigos
También tengo canal de YouTube: https://www.youtube.com/channel/UCroP4BTWjfM0CkGB6AFUoBg?sub_confirmation=1
Twitter: https://twitter.com/parzibyte
Facebook: https://facebook.com/parzibyte.fanpage
Instagram: https://instagram.com/parzibyte
Hacer una donación vía PayPal: https://paypal.me/LuisCabreraBenito
------------------------------------------------------------------------------------------------
*/ ?>
<?php
// Este archivo lo va a estar consultando el lector, recordemos que nos dará su saldo
include_once "constantes.php";
// Crear archivos en caso de que no existan
if (!file_exists(ARCHIVO_ORDEN_LECTOR)) {
touch(ARCHIVO_ORDEN_LECTOR);
}
if (!file_exists(ARCHIVO_RESPUESTA_LECTOR)) {
touch(ARCHIVO_RESPUESTA_LECTOR);
}
$saldo = floatval($_GET["saldo"]);
// Si no le han dado una orden, simplemente imprimimos "" y el lector no hará nada con la tarjeta
$contenido = trim(file_get_contents(ARCHIVO_ORDEN_LECTOR));
if ($contenido === "") {
echo "";
} else {
// En caso de que haya una orden...
$opciones = explode(";", $contenido);
// Extraemos la orden (descontar o recargar) y el saldo
$accion = $opciones[0];
$monto = floatval($opciones[1]);
if ($accion === "d") {
// Si la acción es descontar pero el saldo no es suficiente, lo indicamos en la página web (el lector hará la misma comprobación)
if ($saldo - $monto < 0) {
file_put_contents(ARCHIVO_RESPUESTA_LECTOR, "Saldo insuficiente. Retire la tarjeta");
} else {
file_put_contents(ARCHIVO_RESPUESTA_LECTOR, "Compra exitosa. Retire la tarjeta");
}
} else if ($accion == "r") {
file_put_contents(ARCHIVO_RESPUESTA_LECTOR, "Recarga exitosa. Retire la tarjeta");
}
echo $contenido;
// Y limpiamos la orden del lector
file_put_contents(ARCHIVO_ORDEN_LECTOR, "");
}
Misma que luego es consultada al comprar o recargar:
<?php
/*
____ _____ _ _ _
| _ \ | __ \ (_) | | |
| |_) |_ _ | |__) |_ _ _ __ _____| |__ _ _| |_ ___
| _ <| | | | | ___/ _` | '__|_ / | '_ \| | | | __/ _ \
| |_) | |_| | | | | (_| | | / /| | |_) | |_| | || __/
|____/ \__, | |_| \__,_|_| /___|_|_.__/ \__, |\__\___|
__/ | __/ |
|___/ |___/
____________________________________
/ Si necesitas ayuda, contáctame en \
\ https://parzibyte.me /
------------------------------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
Creado por Parzibyte (https://parzibyte.me).
------------------------------------------------------------------------------------------------
| IMPORTANTE |
Si vas a borrar este encabezado, considera:
Seguirme: https://parzibyte.me/blog/sigueme/
Y compartir mi blog con tus amigos
También tengo canal de YouTube: https://www.youtube.com/channel/UCroP4BTWjfM0CkGB6AFUoBg?sub_confirmation=1
Twitter: https://twitter.com/parzibyte
Facebook: https://facebook.com/parzibyte.fanpage
Instagram: https://instagram.com/parzibyte
Hacer una donación vía PayPal: https://paypal.me/LuisCabreraBenito
------------------------------------------------------------------------------------------------
*/ ?>
<?php
// Leemos lo que haya dicho el lector (por ejemplo: recarga exitosa, saldo insuficiente, dependiendo de lo que haya pasado en index.php)
include_once "constantes.php";
// Creamos en caso de que no exista
if (!file_exists(ARCHIVO_RESPUESTA_LECTOR)) {
touch(ARCHIVO_RESPUESTA_LECTOR);
}
$contenido = file_get_contents(ARCHIVO_RESPUESTA_LECTOR);
file_put_contents(ARCHIVO_RESPUESTA_LECTOR, "");
echo $contenido;
Ya vimos la operación de descontar saldo o crédito a la tarjeta con PHP y ESP8266 usando RFID, ahora vamos a ver cómo recargar saldo. El proceso es similar:
En este caso solicitamos que se recargue saldo:
<?php
/*
____ _____ _ _ _
| _ \ | __ \ (_) | | |
| |_) |_ _ | |__) |_ _ _ __ _____| |__ _ _| |_ ___
| _ <| | | | | ___/ _` | '__|_ / | '_ \| | | | __/ _ \
| |_) | |_| | | | | (_| | | / /| | |_) | |_| | || __/
|____/ \__, | |_| \__,_|_| /___|_|_.__/ \__, |\__\___|
__/ | __/ |
|___/ |___/
____________________________________
/ Si necesitas ayuda, contáctame en \
\ https://parzibyte.me /
------------------------------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
Creado por Parzibyte (https://parzibyte.me).
------------------------------------------------------------------------------------------------
| IMPORTANTE |
Si vas a borrar este encabezado, considera:
Seguirme: https://parzibyte.me/blog/sigueme/
Y compartir mi blog con tus amigos
También tengo canal de YouTube: https://www.youtube.com/channel/UCroP4BTWjfM0CkGB6AFUoBg?sub_confirmation=1
Twitter: https://twitter.com/parzibyte
Facebook: https://facebook.com/parzibyte.fanpage
Instagram: https://instagram.com/parzibyte
Hacer una donación vía PayPal: https://paypal.me/LuisCabreraBenito
------------------------------------------------------------------------------------------------
*/ ?>
<?php
// Lo mismo que "establecer_modo_compra" pero ahora la orden es "r" de recargar
include_once "constantes.php";
$saldo = $_GET["saldo"];
file_put_contents(ARCHIVO_RESPUESTA_LECTOR, ""); // Limpiar lo que haya dicho la ESP8266
file_put_contents(ARCHIVO_ORDEN_LECTOR, "r;$saldo"); // Le indicamos al lector la orden (recargar) y el saldo a recargar
echo json_encode(true);
Y la respuesta del lector se va a manejar del mismo modo que cuando hacíamos compras.
Así es como funciona todo este pequeño proyecto de monedero o saldo electrónico con tarjetas RFID y PHP. Me siento muy orgulloso de haberlo realizado, ya que se me hizo difícil al inicio y no me había enfrentado a algo así.
Yo utilicé PHP pero puedes portarlo fácilmente a Go, Java, C#, etcétera; todo depende de lo que tú necesitas.
Te dejo el código fuente completo en mi GitHub. Más adelante traeré un vídeo de YouTube para mostrarte una pequeña demostración.
También te invito a leer más sobre Electrónica y PHP en mi blog.
Ya te enseñé cómo convertir una aplicación web de Vue 3 en una PWA. Al…
En este artículo voy a documentar la arquitectura que yo utilizo al trabajar con WebAssembly…
En un artículo anterior te enseñé a crear un PWA. Al final, cualquier aplicación que…
Al usar Comlink para trabajar con los workers usando JavaScript me han aparecido algunos errores…
En este artículo te voy a enseñar cómo usar un "top level await" esperando a…
Ayer estaba editando unos archivos que son servidos con el servidor Apache y al visitarlos…
Esta web usa cookies.