Zugangsbeschränkung zu Geräten per Contactless Card mit der NodeMCU und dem RC522 Modul Teil 5 – Sicherheit. - AZ-Delivery

Hola y bienvenidos a un nuevo artículo de blog para el lector de tarjetas MiFare.

En el presente y en el próximo Blog de la serie, nos dedicamos a la seguridad y a la flexibilidad.

Queremos aclarar un poco la seguridad y la flexibilidad de nuestro lector de tarjetas y garantizar una mayor transparencia en las operaciones de lectura de tarjetas. Un gran defecto que tenían las partes anteriores de esta serie era que, si bien la palabra de acceso del administrador (administrador) en la interfaz web era diferente de un lector de tarjetas a un lector de Tarjetas, esta contraseña no podía modificarse individualmente.
Hoy queremos cambiar esto. A partir de ahora, es posible acceder a través de la

interfaz de la Ebba en Sistema - & gt; Seguridad introduzca su propio nombre de acceso para el usuario "administrador".

Menú: Cambio De Contraseña

Esta contraseña puede tener una longitud de entre 3 y 16 caracteres.
Puede configurar esta gama de caracteres definida con las definiciones de PwMinLength y PwMaxLength en el código. Si se desean límites de contraseña más cortos o más largos, los valores pueden ajustarse individualmente.

 

El procedimiento para cambiar la contraseña del usuario "administrador" es::

• Primera entrada a la interfaz web con el nombre de usuario "administrador" y la contraseña de ESP ChipId. (Como ya se ha descrito en las partes anteriores de la serie))
* Navegación en Sistema - > Seguridad introduzca la misma (nueva) contraseña y botón ... empuja.
* Logout en Sistema - > cierre. La nueva contraseña es válida inmediatamente.

Así que hemos aumentado la seguridad un poco antes para que alguien que conoce nuestro proyecto y tiene acceso al puerto serial y a través de la red no pueda averiguar inmediatamente la contraseña de acceso válida.
Pasemos ahora a otro punto de la seguridad de Rubrick: desde el punto de vista de la seguridad, sería deseable saber quién ha utilizado con éxito o no nuestro lector de tarjetas con qué tarjeta. Ahora podemos hacerlo. En el nuevo elemento de menú "Registro de eventos" vemos ahora varias entradas para ciertas acciones o eventos en torno a nuestro lector.
Por ejemplo, ahora vemos en el Acta de eventos todos los intentos de convencer a nuestros lectores de que hagan algo con cartas válidas e inválidas.

El siguiente Screenshot muestra esto de forma ejemplar:

Registro de eventos

 

Como se puede ver en el Screenshot o. g, la lista de la hora y la fecha está todavía genérica a un valor fijo, ya que nos falta una fuente de tiempo válida. Añadiremos esta fuente a una de las siguientes partes.
Para el registro de eventos es esencial la correcta inicialización y utilización del sistema de filtrado interno ESP SPIFFS. Para ello, configuramos las opciones de compilación de forma que se formateen 2 MB como sistema de archivos Spiff de nuestros 4 MB de memoria de programas disponibles. ¿Cómo funciona esto? ¿ya hice otro artículo en el blog "ESP8266-todos SPIFFS o qué?"lo describí en una instalación.

Importante: Sin la configuración correcta del Spiff, si bien el código se compila y se carga en el ESP, la navegación de la ESP con el mensaje "ATFS:NOK" permanece en el puerto serie "colgado" y no se consigue una mayor Initalización. Esta es la actitud de Spiff que debemos mantener en todas las partes siguientes de esta fila.

 

El código para nuestro Blog de hoy es ... :

 

# include <SPI.h>
# include <MFRC522.h>
# include <ESP8266WiFi.h>
# include <ESP8266WebServer.h>
# include <ESP8266mDNS.h>
# include <EEPROM.h>
# include <FS.h>           // Include the SPIFFS library

# define RST_PINA     5     // SPI Reset Pin (D1 salida))
# define RELAIS_PIN  16    // Relés (D0 salida) [Low activado] - LED interno cerca de USB Port
# define SS_PIN      15    // Pin de selección de esclavo SPI

#definir RGBLED_R    2     // rojo (salida D4) 
#definir RGBLED_G    0     // Verde (salida D3): también LED interno en el módulo ESP
#definir RGBLED_B    4     // azul (salida D2)

#definir WiFiPwdLen 25     // Longitud máxima de la contraseña de WiFi
#definir STANAMELEN 20     // Longitud máxima de SSID WiFi
#definir ESPHostNameLen 20 // Número máximo de caracteres ESPHostName

#definir KEYA cierto         // Definición del indicador PICC
#definir KEYB falso        // Definición del indicador PICC

#definir LED_BUILTIN 16
#definir PIN_WIRE_SDA 4
#definir PIN_WIRE_SCL 5

#definir PwMinLength 3  // Longitud mínima de contraseña de inicio de sesión
#definir PwMaxLength 16  // Longitud máxima de la contraseña de inicio de sesión
#definir LoginNameMaxLength 16  // Longitud máxima del nombre de inicio de sesión

#definir USED_Sector 1  // Sector de la tarjeta que se utiliza para los datos de autenticación y configuración (válido: 1-15)

ADC_MODE(ADC_TOUT);   // Configure la entrada analógica A0 a externa. ADC_TOUT (para voltaje externo), ADC_VCC (para voltaje del sistema).
MFRC522 mfrc522(SS_PIN, RST_PIN);   // Crear una instancia del MFRC522
MFRC522::MIFARE_Key clave;
ESP8266WebServer servidor(80);        // Crear instancia de servidor web
Archivo myfile;               // crea una variable de manejo SPIFFS
FSInfo fs_info;

estructura WiFiEEPromData // 68 bytes de longitud del objeto
{   char ESPHostName[ESPHostNameLen]; // 20   char APSTAName[STANAMELEN]; // STATION / AP Point Name TO Connect, si está definido 20   char WiFiPwd[WiFiPwdLen]; // WiFiPAssword, si se define 25   char ConfigValid[3]; // Si Config es Vaild, se requiere la etiqueta "TK" "3
};

estructura MiFareClassicKeyTable
{   byte Clave_A[6] = {0x22, 0x44, 0xFA, 0xAB, 0x90, 0x11}; // Cambie la clave de la tarjeta PICC.   byte Clave_B[6] = {0xFE, 0xE1, 0xAA, 0x3D, 0xDF, 0x37}; // Cambie la clave de la tarjeta PICC.   char ConfigValid[3]; // Si Config es Vaild, se requiere la etiqueta "TK" "
};

estructura SysConf //
{   char LoginName[LoginNameMaxLength]; // 16   char LoginPassword[PwMaxLength];  // 16   bool PCD_Disabled; // 1   byte USED_PICC_Sector; // 1   char ConfigValid[3]; // Si Config es Vaild, se requiere la etiqueta "TK" "// 3
};




MiFareClassicKeyTable MiFareClassicKey;
WiFiEEPromData MyWiFiConfig;
SysConf Configuración del sistema;


// Variables utilizadas globalmente
bool Resultado  = falso;
bool LearnNewCard = falso;
bool EraseCard = falso;
bool Caducidad Fecha Activo = falso;
bool PCD_Disabled = falso;
Cadena Apellido;
Cadena Nombre dado;
Cadena Fecha de caducidad;
Cadena temp;
sin firmar largo ID de sesión;
sin firmar largo PCD_ServiceCall_Handler = 0;
sin firmar largo PCD_WatchDog_Handler = 0;
uint8_t DataBuffer[18]  = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };


nulo configuración()
{   pinMode(RST_PIN, SALIDA);   digitalWrite(RST_PIN, ALTO);   pinMode(RELAIS_PIN, SALIDA);   pinMode(RGBLED_R, SALIDA);   pinMode(RGBLED_G, SALIDA);   pinMode(RGBLED_B, SALIDA);   digitalWrite(RELAIS_PIN, ALTO);   // relé inactivo   SetRGBLed(255, 0, 255, falso);    // El color del led morado comienza la inicialización   De serie.comenzar(115200);               // Inicializa la comunicación serial con la PC con 115200 baudios   De serie.println(F(" "));   temp = "ATSN:" + Cadena(ESP.getChipId());   De serie.println(temp);   // Serial.print ("Valor ADC:"); Serial.println (analogRead (A0));   SPI.comenzar();                      // Inicializa la comunicación SPI   PCDHardReset();   ID de sesión = millis();   Resultado = loadSysConfig();   Resultado = InitalizeFileSystem();   Resultado = startWiFiClient();   InitalizeHTTPServer();   temp = "Inicio del sistema:";   temp += Cadena(ESP.getResetReason());   WriteToLog(temp, 0);   temp = "";   ESP.wdtEnable(4000);             // Iniciar vigilancia   SetRGBLed(0, 0, 255, falso);    // Inicialización de color de led azul completada
}


// ******************* Start Helper / Optimization Functions ************************ ********

nulo SetRGBLed(byte RedValue, byte GreenValue, byte BlueValue, booleano SlowFade) // Función para controlar el led RGB
{   write digital(RGBLED_R, LOW);   write digital(RGBLED_G, LOW);   write digital(RGBLED_B, LOW);   if (RedValue == 255)   {     write digital(RGBLED_R, HIGH);   }   if (GreenValue == 255) {     write digital(RGBLED_G, HIGH);   }   if (BlueValue == 255)  {     write digital(RGBLED_B, HIGH);   }
}

// ******************* Stop Helper/ Optimization Functions *********************************

// ******************* Start Functions Servidor Web *******************************************

// Cookie las rutinas de base se basan en la salida GIT:
//https://github.com/esp8266/ESPWebServer/blob/master/examples/SimpleAuthentification/SimpleAuthentification.ino
bool is_authentified()
{   if (servidor.hasHeader("Cookie")) {     // Cookie encontrada     temp = servidor.cabecera("Cookie");     // Serial.println (temp));     Cadena SessionStr = Cadena(ESP.getChipId()) + "=" + Cadena(Sessionida);     yield();     if (temp.indexOf(SessionStr) != -1) {       // Web Authentification exitosa       temp = "";       return true;     }   }   // Web Authentification falló   temp = "";   Sessionida = Milis();   return false;
}

void línea de mano() {   Cadena msg;   // String cookie = servidor.cabecera("Cookie")");   // Serial.println(cookie));   if (servidor.hasArg("DISCONNECT")) {     // Disconnect Usuarios;     Sessionida = Milis();     temp = Cadena(ESP.getChipId()) + "=NA ; HTTP: / / SameSite=Strict";     servidor.radiotelefonía("Set-Cookie", temp);     temp = "Desconexión de interfaz web.";     WriteToLog(temp, 0);     temp = "";     PCD_Disabled = false; // PCD activar en logout ;     SetRGBLed(0, 0, 255, false);    // Led Color Azul Modelo Estándar     servidor.radiotelefonía("Location", "/login");     servidor.radiotelefonía("Cache-Control", "no-cache");     servidor.send(301);     servidor.send(301);     // yield();   }   if (servidor.hasArg("USERNAME") && servidor.hasArg("PASSWORD")) {     temp = Cadena(ESP.getChipId());     if (servidor.arg("USERNAME") == Configuración del sistema.Loginaname &&  servidor.arg("PASSWORD") == Configuración del sistema.Login password ) {       servidor.radiotelefonía("Location", "/");       servidor.radiotelefonía("Cache-Control", "no-cache");       Sessionida = Milis();       temp = Cadena(ESP.getChipId()) + "=" + Cadena(Sessionida) + "; HttpOnly ; SameSite=Strict";       servidor.radiotelefonía("Set-Cookie", temp);       temp = "Notificación de " + servidor.arg("USERNAME") + "a Internet.";       WriteToLog(temp, 0);       temp = "";       servidor.send(301);       PCD_Disabled = true; // PCD inhabilitar mientras se esté trabajando en la Web;       SetRGBLed(255, 0, 255, false);    // Led color púrpura en un escritorio de servicio       return;     }     msg = "<script>alert ('nombre de usuario falso o contraseña incorrecta !'); < / script>";     temp = "Intento de autenticación incorrecto de " + servidor.arg("USERNAME") + "a Internet. Contraseña: " + servidor.arg("PASSWORD") ;     WriteToLog(temp, 1);     temp = "";   }   CSS_Header_Template();   temp = "<head><title>Login< / title>< / head> & lt;body><DIV ALIGN=CENTER>";   servidor.sendContent(temp);   temp = "<h2>inscripción a lector de tarjetas RC522< / h2><body><br>< br>< table border=0 bgcolor=negro><tr><th>< DIV ALIGN=RIGHT>;";   servidor.sendContent(temp);   temp = "<form action='/login 'method=' post ' >Nombre de usuario: <input type=text Name=' USERNAME ' Size=17 required><br>;";   servidor.sendContent(temp);   temp = "Contraseña: <input type=password Name='PASSWORD' Size=17 required><br / ><br / ><br / ><button type='submit' ";   servidor.sendContent(temp);   temp = "nombre='Login_Button' value='1' style='height: 30px; width: 100px' >Login</button><br / ></th></tr></form></DIV></table>";   servidor.sendContent(temp);   temp = "<br><SMALL>para que el acceso funcione, se permiten Cookies para este sitio web.& lt; / SMALL>";   servidor.sendContent(temp);   temp = msg + "< / DIV>< / cuerpo>< / HTML>;";   servidor.sendContent(temp);   temp = "";
}

void pista de acción()
{   Sessionida = Milis();   temp = "Página no encontrada.\n\n";   temp += "URI: ";   temp += servidor.uri();   temp += "\nmetod: ";   temp += (servidor.método() == HTTP_GET) ? "GET" : "POST";   temp += "\nArguments: ";   temp += servidor.args();   temp += "\n";   for (uint8_t i = 0; i < servidor.args(); i++) {     temp += " " + servidor.argName(i) + ": " + servidor.arg(i) + "\n";   }   yield();   servidor.send(404, "texto / plain", temp);   temp = "Llamada a la URL no válida: " + servidor.uri() + "Parámetros: " + Cadena(servidor.args()) ;   WriteToLog(temp, 2);   temp = "";
}



void handleErasePICC()
{   if (!is_authentified())   {     servidor.radiotelefonía("Location", "/login");     servidor.radiotelefonía("Cache-Control", "no-cache");     servidor.send(301);     yield();     return;   }   CSS_Header_Template();   yield();   temp = "<head><title>lector de mapas RC522< / title></head> & lt;body>";   servidor.sendContent(temp);   HtmlNavStructure();   temp = "<script>alert ('por favor, mantenga la carta que debe eliminarse delante del lector.'); < / script>";   servidor.sendContent(temp);   yield();   EraseCard = true;   PCD_Disabled = false;   SetRGBLed(0, 255, 255, false);    // LED Color modo de programación cian   temp = "< / cuerpo>< / html>";   servidor.sendContent(temp);   servidor.cliente().stop();   temp = "";
}

void leetings de mano()
{   if (!is_authentified())   {     servidor.radiotelefonía("Location", "/login");     servidor.radiotelefonía("Cache-Control", "no-cache");     servidor.send(301);     return;   }   CSS_Header_Template();   temp = "<head><title>lector de mapas RC522< / title></head> & lt;body>";   servidor.sendContent(temp);   HtmlNavStructure();   temp = "<br / ><br / ><br / ><div align=center><form method=post action='/settings' method='post'>";   servidor.sendContent(temp);   temp = "<p><label>nueva contraseña de acceso< / label><br> <input type= 'password' name= 'newPassword' >";   servidor.sendContent(temp);   temp = "</p><p><label>la Repetición Contraseña de inicio de sesión</label><br / > <input type='password' name='confirmNewPassword'><br / ><br / ><br / >";   servidor.sendContent(temp);   temp = "<button type='submit' name='Save' value='1' style='height: 30px; width: 200px' >Guardar</button></p></form></div>";   servidor.sendContent(temp);   // temp = "</p><p><button type='submit' name='save'>Guardar</button></p></form></div></body></html>";   if (servidor.hasArg("Save"))   {     if (servidor.arg("confirmNewPassword") == servidor.arg("newPassword"))     {       temp = servidor.arg("newPassword");       if ((temp.length() < PwMinLength ) |  (temp.length() > PwMaxLength ))       {         temp = "<br><div align=center><br> La contraseña debe estar entre al menos: ";         servidor.sendContent(temp);         temp = Cadena(PwMinLength) + "y máximo " + Cadena(PwMaxLength) + "Ser largo.& lt; / div>";         servidor.sendContent(temp);       } else       {         temp = servidor.arg("newPassword");         temp.toCharArray(Configuración del sistema.Login password , PwMaxLength);         savesisconfig();         temp = "La palabra de acceso del usuario " + Cadena(Configuración del sistema.Loginaname) + "ha sido cambiado.";         WriteToLog(temp, 0);         temp = "<script>alert ('la palabra de acceso ha sido modificada con éxito.'); < / script>";         servidor.sendContent(temp);       }     } else     {       temp = "<br><div align=center><br> Las contraseñas introducidas no coinciden. Introduzca De nuevo.& lt; / div>";       servidor.sendContent(temp);     }   }   temp = "< / cuerpo>< / html>";   servidor.sendContent(temp);   servidor.cliente().stop();   temp = "";
}

void handleNewPICC()
{   if (!is_authentified())   {     servidor.radiotelefonía("Location", "/login");     servidor.radiotelefonía("Cache-Control", "no-cache");     servidor.send(301);     return;   }   if (servidor.hasArg("Surname") && servidor.hasArg("Givenname"))   {     Surname = servidor.arg("Surname");     Givenname = servidor.arg("Givenname");     ExpirationDate = servidor.arg("ExpDate");     if (servidor.hasArg("Opción de exploración")) {       ExpirationDateActive = true;     } else {       ExpirationDateActive = false;     }     temp = "Crear un nuevo mapa para: " + servidor.arg("Givenname") + ", " + servidor.arg("Surname");     WriteToLog(temp, 0);     PCD_Disabled = false;     LearnNewCard = true;     CSS_Header_Template();     temp = "<head><title>lector de mapas RC522< / title></head> & lt;body>";     servidor.sendContent(temp);     HtmlNavStructure();     temp = "<script>alert ('por favor, mantenga la nueva carta delante del lector!'); < / script>";     servidor.sendContent(temp);     temp = "< / cuerpo>< / html>";     servidor.sendContent(temp);     servidor.cliente().stop();     SetRGBLed(255, 255, 0, false);    // LED Color Amarillo Modo De Programación     yield();     return;   }   CSS_Header_Template();   temp = "<head><title>lector de mapas RC522< / title></head> & lt;body>";   servidor.sendContent(temp);   HtmlNavStructure();   temp = "";   temp = "<br / ><br / ><br / ><br / ><table border=0 ALIGN=CENTER><th>";   servidor.sendContent(temp);   temp = "<table border=1 bgcolor = black><form action=' / newPICC 'method=' post ' >;";   servidor.sendContent(temp);   temp = "<tr><th> titular de la tarjeta:<br>< div ALIGN=RIGHT>";   servidor.sendContent(temp);   temp = "Nombre: <input type=text Name= 'Surname' Size=17 maxlenght=16 placeholder= 'Max' required><br>";   servidor.sendContent(temp);   temp = "Apellido: <input type=text Name= 'Givenname' Size=17 maxlenght=16 placeholder= 'modelo' required><br>";   servidor.sendContent(temp);   temp = "< / div>< / th><th>metadatos de cartas:<br><DIV ALIGN=RIGHT>;";   servidor.sendContent(temp);   temp = "<input Name='ExpDateOption' TYPE=checkbox VALUE=1 >Fecha de caducidad:<input type=date Name= 'ExpDate' Size = 17 >;";   servidor.sendContent(temp);   temp = "<br / ><th><tr><th></table><br / >";   servidor.sendContent(temp);   temp = "<button type= 'submit' name= 'NewCard' value= '1' style= 'height: 30px; width: 200px' >Crear una nueva tarjeta inteligente< / button>";   servidor.sendContent(temp);   temp = "<br>< / form>< / tr>< / th>< / table>;";   servidor.sendContent(temp);   temp = "< / cuerpo>< / html>";   servidor.sendContent(temp);   servidor.cliente().stop();   temp = "";
}


void barra de mano()
{   int FileSize =  0;   if (!is_authentified())   {     servidor.radiotelefonía("Location", "/login");     servidor.radiotelefonía("Cache-Control", "no-cache");     servidor.send(301);     return;   }   if (servidor.hasArg("ClearLog"))   {     if (SPIFFS.exists ("/usage_log.csv") )  // Verifica si el archivo usage_log.csv exisado.     {       SPIFFS.remove("/usage_log.csv");  // Borrar Archivo       Serial.println(F("ATFS: Cuaderno Diario de pesca"));       temp = "Archivo de registro de eventos borrado.";       WriteToLog(temp, 0);       temp = "";     } else {       Serial.println(F("ATFS: LogDelete_ERR"));     }     yield();   }   CSS_Header_Template();   yield();   temp = "<head><title>lector de mapas RC522< / title></head> & lt;body>";   servidor.sendContent(temp);   HtmlNavStructure();   temp = "<br / ><br / ><br / ><br / ><table border=4 ALIGN=CENTER><th>";   servidor.sendContent(temp);   temp = "<textarea rows= '20' cols= ' 110 ' warp=soft readonly>";   servidor.sendContent(temp);   if (SPIFFS.exists ("/usage_log.csv"))  // Verifica si el archivo usage_log.csv exisado.   {     myfile = SPIFFS.open("/usage_log.csv", "r");  // Abre el archivo usage_log.csv en el directorio raíz para lectura     if (!myfile)     {       temp = "Error interno: archivo de registro usage_log.¡csv no se pudo abrir !";       servidor.sendContent(temp);     } else     {       FileSize = myfile.size();       while (myfile .posición() < myfile.size())       {         temp = myfile.readStringUntil('\n');         temp.trim();         temp += "\n"; // Add Character Line Feed         servidor.sendContent(temp);       }       myfile.close();     }   } else   {     temp = "Error interno: archivo de registro usage_log.¡csv no encontrado !";     servidor.sendContent(temp);   }   temp = "</textarea>< / th>< / table><table border=0 ALIGN=CENTER>";   servidor.sendContent(temp);   SPIFFS.info(fs_info);   temp = "<br><div ALIGN=CENTER> Loggroesse " + Cadena(FileSize) + Bytes.<br>";   servidor.sendContent(temp);   temp = Cadena(fs_info.usedBytes) + "Bytes de " + Cadena(fs_info.totalBytes) + Bytes ocupados.& lt; / div>";   servidor.sendContent(temp);   temp = "<th><form action=' / log 'method=' post ' >< br><br>";   servidor.sendContent(temp);   temp = "<button type= 'submit' name='RefreshLog' value= '1' style= 'height: 30px; width: 100px' >Refresh< / button>";   servidor.sendContent(temp);   temp = "<button type= 'submit' name= 'ClearLog' value= '1' style= 'height: 30px; width: 100px' > Clear Log</button>";   servidor.sendContent(temp);   temp = "< / form>< / th>< / table>< / HTML>";   servidor.sendContent(temp);   servidor.cliente().stop();   temp = "";
}

void handleRoot()
{   if (!is_authentified()) {     servidor.radiotelefonía("Location", "/login");     servidor.radiotelefonía("Cache-Control", "no-cache");     servidor.send(301);     return;   }   // HTML Content   CSS_Header_Template();   yield();   temp = "<head><title>lector de mapas RC522< / title></head> & lt;body>";   servidor.sendContent(temp);   HtmlNavStructure();   temp = "<div ALIGN=CENTER><br><br><br> & lt;br><BIG> Bienvenido al sitio web del lector de tarjetas inteligentes RC522.< / BIG><br>";   servidor.sendContent(temp);   temp = "Fondo de reinicio: " + Cadena(ESP.getresetreasona()) + "<br>";   servidor.sendContent(temp);   temp = "Espacio De Cabeza Libre: " + Cadena(ESP.getfreap()) + "Bytes<br>";   servidor.sendContent(temp);   temp = "Int. Flash: " + Cadena(ESP.chiprealsize de getflash()) + "Bytes<br>";   servidor.sendContent(temp);   Resultado = mfrc522.Pcd_performselfest();   mfrc522.PCD_Init();                       // Inicializando módulo de lectura MFRC522   mfrc522.PCD_SetAntennaGain(mfrc522.RxGain_max); // Pone antena en max. Recepción   mfrc522.Pcd_antennaona();   yield();   if (Resultado) {     temp = "Estado del PCD RC522: OK< br>";   } else {     temp = "Estado PCD RC522: ¡error!<br>";   }   servidor.sendContent(temp);   temp = "ID DE LA CPU: " + Cadena(ESP.getChipId()) + " @ " + Cadena(ESP.getCpuFreqMHz()) + "MHz<br>";   servidor.sendContent(temp);   temp = "<br> ¡ha sido registrado con éxito !<br>";   servidor.sendContent(temp);   temp = "<br / >Programado de <a href='mailto:tobias.kuch@googlemail.com'>Tobias Kuch</a><br / ></div></body></html>";   servidor.sendContent(temp);   if (servidor.hasArg("Reboot") )  // Reboot System   {     temp = "<script>alert('el sistema se reiniciará ahora.'); < / script>";     servidor.sendContent(temp);     servidor.cliente().stop();     yield();     temp = "";     ESP.reset();     delay(4000);   }   servidor.cliente().stop();   temp = "";
}

void CSS_Header_Template() // Estilo para todas las páginas web de ESP internas. https://wiki.selfhtml.org/wiki/CSS
{   servidor.setContentLength(CONTENT_LENGTH_UNKNOWN);   temp = "";   servidor.send (200, "texto / html", temp);   temp = "¡<!DOCTYPE HTML PUBLIC '- / / / W3C/ / DTD HTML 4.01 Transitional//EN'><html lang= ' de '><meta charset= 'UTF-8' >";   servidor.sendContent(temp);   temp = "<style type='text/css'>*{margin: 0;padding: 0;}body{background:black;color:darkorchid;font-size: 16px;"; servidor.sendContent(temp); temp = "font-family: sans-serif,arial;}.nav{width: 1300px;height: 30px;margin: 0 auto;radio de la frontera: 5px;}";   servidor.sendContent(temp);   temp = "ul li{list-style: none;width: 200px;line-height: 60px;position: relative;background: darkorchid;"; servidor.sendContent(temp); temp = "box-shadow: 0px 2px 5px 0px grey;text-align: center;float: left;background-color: #010000;}ul li ul{";   servidor.sendContent(temp);   temp = "posición: absolute;}.nav > ul > li: nth-of-type (1) {radio de la frontera: 5px 0px 5px;}.nav > ul > li:nth-of-type (5)";   servidor.sendContent(temp);   temp = "{border-radius: 0px 5px 5px 0px;}ul li a{color: rgb(182, 18, 18);width: 200px;height: 58px;display: inline-block;"; servidor.sendContent(temp); temp = "text-decoration: none;}ul li a:hover{font-weight: bold;border-bottom: 2px solid #fff;}ul li ul{display: none;}";   servidor.sendContent(temp);   temp = ".nav ul li:hover ul{display: block;}.fa{margin-right: 5px;}.contenedor{width: 1000px;height: 200px;"; servidor.sendContent(temp); temp = "margin: 0 auto;padding:20px 20px;}@media screen and (max-width: 480px){header{width: 100%;}";   servidor.sendContent(temp);   temp = ".nav{display: none;width: 100%;height: auto;}ul li{width: 100%;float: none;}ul li a{width: 100%;"; servidor.sendContent(temp); temp = "display: block;}ul li ul{position: static;}ul li ul li a{background: #222;}.fa-list.modify{display: block;}";   servidor.sendContent(temp);   temp = ".container{width: 100%;height: auto;} body{overflow-x:hidden;}< / style>";   servidor.sendContent(temp);   temp = "";
}

void HtmlNavStructure()
{   temp = "<div class= 'menu' ><nav class= ' nav ' ><ul>";   servidor.sendContent(temp);   temp = "<li>< a href= ' # ' > Sistema</a>;";   servidor.sendContent(temp);   temp = "<ul>< li>< a href=' / '>Información</a>< / li>";   servidor.sendContent(temp);   temp = "<li>< a href=' / settings ' >Seguridad< / A>< / li>";   servidor.sendContent(temp);   temp = "<li>< a href=' / login?DISCONNECT=1'>cancelar & lt; / A>< / li>;";   servidor.sendContent(temp);   temp = "<li>< a href="/es/?Reboot=YES">reinicio< / A>< / li>;";   servidor.sendContent(temp);   temp = "< / ul>";   servidor.sendContent(temp);   temp = "< / li>< li>< a href= ' #'>PICC</A>;";   servidor.sendContent(temp);   temp = "<ul><li>< a href=' / newPICC ' >Crear un nuevo mapa</a>< / li>;";   servidor.sendContent(temp);   temp = "<li>< a href=' / erasePICC ' >borrar mapa</a>< / li>< / ul>;";   servidor.sendContent(temp);   temp = "< / li>";   temp = "< / li>< li>< a href=' / log ' >Acta de eventos</a>< / li>;";   servidor.sendContent(temp);   temp = "< / ul>< / nav>< / div>;";   servidor.sendContent(temp);   temp = "";
}

void Servidor initalizhtp()
{   bool initok = false;   const char * headerkeys[] = {"User-Agent", "Cookie"} ; // Cabecera de pista   size_t headerkeysize = sizeof(headerkeys) / sizeof(char*); // Cabecera de pista   servidor.on("/", handleRoot);   servidor.on("/login", línea de mano);   servidor.on("/newPICC", handleNewPICC);   servidor.on("/erasePICC", handleErasePICC);   servidor.on("/settings", leetings de mano);   servidor.on("/log", barra de mano);   servidor.onNotFound ( pista de acción );   servidor.colectheaders(headerkeys, headerkeysize );// Server   servidor.begin(); / Inicio del servidor Web
}

// ******************* End Functions Servidor Web *********************************************

// ******************* Sistema De Filtrado De Funciones De Inicio ******************************************
boolean Sistema de filtración de initaliz()
{   bool initok = false;   initok = SPIFFS.begin();   delay(200); // Without delay i've seen the IP address blank   if (!(initok)) // Formato SPFS, of not formatted. - Try 1   {     Serial.println(F("ATFS: FRM"));     SPIFFS.formato();     initok = SPIFFS.begin();   }   if (!(initok)) // Formato SPFS, of not formatted. - Try 2   {     SPIFFS.formato();     initok = SPIFFS.begin();   }   if (initok) {     Serial.println(F("ATFS: OK"));   } else {     Serial.println(F("ATFS: NOK"));   }   return initok;
}

boolean WriteToLog(Cadena Logtry, bytes Logtype)
{   bool writeok = false;   SPIFFS.info(fs_info);   if (fs_info.totalBytes - fs_info.usedBytes - 2000 > 1) // Comprobar espacio en disco   {     myfile = SPIFFS.open("/usage_log.csv", "a");  // Abre el archivo usage_log.csv en el directorio de escritura de Root     if (!myfile)     {       myfile.close();       Serial.println(F("ATFS: InitLog_ERR"));       return writeok;     }     temp = "";     temp += "01.01.1980 12:00:00 "; // Añadir fecha real     switch (Logtype)     {       case 0:         temp += "Info: ";         break;       case 1:         temp += "Aviso: ";         break;       case 2:         temp += "Error: ";         break;       default:         temp += "Info: ";         break;     }     temp += Logtry;     writeok = myfile.println(temp);     if (!(writeok)) {       Serial.println(F("ATFS:WriteLog_ERR"));     }     myfile.close();     temp = "";   }   return writeok;
}


// ******************* End Functions Filesystem ********************************************

// ******************* Start Functions WiFi Management *************************************
// Función de https://www.az-delivery.de/blogs/azdelivery-blog-fur-arduino-und-raspberry-pi/wps-mit-dem-esp8266?ls=de
bool startWPS()
{   bool wpsuccess = WiFi.beginWPSConfig();   if (wpsuccess) {     /¡No debe ser siempre un éxito! Después de un tiempo, la SSID está vacía.     Cadena newsida = WiFi.SSID();     if (newsida.length() > 0) {       // Sólo cuando se encontró una SSID tuvimos éxito       yield();       Serial.println(F("ATWPS: OK"));       saveCredentials(); // Save Credentials to EEPROM     } else {       Serial.println(F("ATWPS:NOK"));     }   }   return wpsuccess;
}

bool startWiFiClient()
{   bool WiFiClientStarted = false;   size_t A0_ADCValue = 0;   bytes i = 0;   bytes connRes = 0;   Serial.setDebugOutput(false);  // Activar para depuración.   WiFi.hostname("Crdrr417667");   WiFi.softAPdisconnect(true);   WiFi.disconnect();   WiFi.modo(WIFI_STA);   if (loadCredentials())   {     WiFi.begin(MyWiFiConfig.APSTAName, MyWiFiConfig.WiFiPwd);     while (( connRes != 3 ) and ( connRes != 4 ) and (i != 30)) // if connRes = = 0 " IDLE_STATUS-change Statius"     {       i++;       // Serial.print (F) ("."); / / Connect observar el proceso en el puerto serie       // ESP.wdtFeed();       delay(500);       yield();       connRes  = WiFi.waitForConnectResult();     }     if (connRes == 4 ) { // if password is incorporrect       Serial.println(F("ATWIFI: PWDERR"));       WiFi.disconnect();     }     if (connRes == 6 ) { // module is not configured in station mode       Serial.println(F("ATWIFI: STAERR"));       WiFi.disconnect();     }   }   if (WiFi.estado() == WL_CONNECTED)   {     // ESP.wdtFeed();     Serial.print(F("ATIP:"));     Serial.println(WiFi.localIP());     WiFi.setAutoReconnect(true); // Set whether module will attempt to reconnect to an access point in case it is disconnected.     // Setup MDNS respondedor     if (!MDNS.begin("Crdrr417667"))     {       Serial.println(F("ATMDNS: NOK"));     } else {       MDNS.addService("http", "tcp", 80);     }     WiFiClientStarted = true;   } else   {     A0_ADCValue = analogRead(A0);     //No hemos tenido éxito, así que empezamos WPS cuando WPS Taster está presionado a A0 durante el Reset     if (A0_ADCValue > 499)     {       if (startWPS())       {         // ESP.wdtFeed();         delay(500);         WiFi.disconnect();         WiFi.modo(WIFI_STA);         WiFi.begin(WiFi.SSID().c_str(), WiFi.psk().c_str());         // ESP.wdtFeed();         WiFiClientStarted = true;       } else       {         WiFiClientStarted = false;         WiFi.disconnect();       }     } else     {       WiFi.disconnect();     }   }   /WiFi.printDiag (Serial); / / para depuración.   return WiFiClientStarted;
}
// ******************* END Functions WiFi Management *************************************

// ******************* Start Functions Store WiFi Credentials to EEPROM ******************
bool loadCredentials()
{   bool RetValue;   EEPROM.begin(512);   EEPROM.get(0, MyWiFiConfig);   EEPROM.end();   if (Cadena(MyWiFiConfig.Configvalida) == "TK")   {     RetValue = true;   } else   {     RetValue = false; // WLAN Settings no encontrado.   }   // ESP.wdtFeed();   return RetValue;
}

void saveCredentials() // Memoria WLAN credentials en EEPROM
{   size_t i;   for (i = 0 ; i < sizeof(MyWiFiConfig) ; i++) // Abrir la configuración anterior   {     EEPROM.write(i, 0);   }   for (i = 0 ; i < STANameLen  ; i++) // Abrir la configuración anterior   {     MyWiFiConfig.WiFiPwd[i] = 0;   }   for (i = 0 ; i < WiFiPwdLen ; i++) // Abrir la configuración anterior   {     MyWiFiConfig.APSTAName[i] = 0;   }   temp = WiFi.SSID().c_str();   i = temp.length();   temp.toCharArray(MyWiFiConfig.APSTAName, i + 1);   temp = WiFi.psk().c_str();   i = temp.length();   temp.toCharArray(MyWiFiConfig.WiFiPwd, i + 1);   temp = "";   strncpy(MyWiFiConfig.Configvalida , "TK", sizeof(MyWiFiConfig.Configvalida) );   EEPROM.begin(512);   EEPROM.put(0, MyWiFiConfig);   EEPROM.commit();   EEPROM.end();   // ESP.wdtFeed();
}

void savesisconfig()
{   bytes i;   strncpy(Configuración del sistema.Configvalida , "TK", sizeof(Configuración del sistema.Configvalida) );   EEPROM.begin(512);   EEPROM.put(80, Configuración del sistema);   EEPROM.commit();   EEPROM.end();   // ESP.wdtFeed();

}

bool loadSysConfig()
{   bool RetValue;   EEPROM.begin(512);   EEPROM.get(80, Configuración del sistema);   EEPROM.end();   if (Cadena(Configuración del sistema.Configvalida) == "TK")   {     RetValue = true;   } else   {     temp = Cadena(ESP.getChipId());     temp.toCharArray(Configuración del sistema.Login password , PwMaxLength);     temp = "";     strncpy(Configuración del sistema.Loginaname , "administrador", sizeof(Configuración del sistema.Loginaname) );     Configuración del sistema.PCD_Disabled = false;     Configuración del sistema.USED_PICC_Sector = 1;     savesisconfig();     RetValue = false; // Config Settings no válido / / ejecución de la inicialización predeterminada   }   // ESP.wdtFeed();   return RetValue;
}

// ******************* END Functions StoreCredentialsto EEPROM ***************************

// ******************* Start Functions CardServices  *************************************

void PCDHardReset()
{   write digital(RST_PINA, LOW);   delay(200);   write digital(RST_PINA, HIGH);   mfrc522.PCD_Reset();   mfrc522.PCD_Init();                              // Inicializando módulo de lectura MFRC522   mfrc522.PCD_SetAntennaGain(mfrc522.RxGain_max); // Pone antena en max. Recepción   mfrc522.Pcd_antennaona();
}

boolean Cardautenticate(boolean Abreviatura, bytes Sector, bytes ikey[6])
{   const bytes sectorkeytable [16] = {3, 7, 11, 15, 19, 23, 27, 31, 35, 39, 43, 47, 51, 55, 59, 63};   bytes statusA;   statusA = 0;   for (int a = 0; a < 6; a++)   {     clave.keyByte[a] = ikey[a];   }   // Key A   if (Abreviatura)   {     statusA = mfrc522.Pcd_autenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, sectorkeytable[Sector], &clave, &(mfrc522.uid));     if (statusA != MFRC522::STATUS_OK)     {       Serial.println(F("ATAUTH: ERR_A"));       return false;     }   }   // Clave B   else if (not Abreviatura)   {     statusA = mfrc522.Pcd_autenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_B, sectorkeytable[Sector], &clave, &(mfrc522.uid));     if (statusA != MFRC522::STATUS_OK)     {       Serial.println(F("ATAUTH: ERR_B"));       return false;     }   }   return true;
}

/ WriteData . uses Global Variable DataBuffer for Data Return
boolean CardDataWrite(bytes Sector, bytes bloque, bytes value[16])
{   bytes estado;   bytes writevector;   bytes sectorkeytable [16] = {3, 7, 11, 15, 19, 23, 27, 31, 35, 39, 43, 47, 51, 55, 59, 63};   writevector = Sector * 4 + bloque - 1 ;   for (bytes a = 0; a < 16; a++)   {     if (writevector ==  sectorkeytable[a])     {       // Serial.println ("NAK");       return false;     }   }   estado = mfrc522.MIFARE_Write(writevector, value, 16);   if (estado != MFRC522::STATUS_OK)   {     Serial.println(F("ATPCD: W_ERR"));     // Serial.println(mfrc522. GetStatus Codename(estado)));     return false;   } else   {     // Serial.print (F ("ATPC: Write_Card_OK"));     return true;   }
}

// Read Data-uses Global Variable DataBuffer for Data Return
boolean CardDataRead(bytes Sector, bytes bloque)
{   bytes estado;   bytes readvector;   const bytes sectorkeytable [16] = {3, 7, 11, 15, 19, 23, 27, 31, 35, 39, 43, 47, 51, 55, 59, 63};   bytes sized = 18;   readvector = Sector * 4 + bloque - 1 ;   for (bytes a = 0; a < 16; a++)   {     if (readvector ==  sectorkeytable[a])     {       Serial.println(F("ATPCD: R_ERR"));       return false;     }   }   estado = mfrc522.MIFARE_Read(readvector, Buffer de datos, &sized);   if (estado != MFRC522::STATUS_OK)   {     Serial.println(F("ATPCD: R_ERR"));     return false;   } else   {     return true;   }
}

boolean ResetCardToDefault()
{   bytes ikey[16];   bytes estado, i;   bytes writevector;   const bytes sectorkeytable [16] = {3, 7, 11, 15, 19, 23, 27, 31, 35, 39, 43, 47, 51, 55, 59, 63};   writevector = sectorkeytable[USED_Sector];   if (Cardautenticate(KEYB, USED_Sector, MiFareClassicKey.Key_B)) // Sector Autenticate for WRITE Access   {     for (i = 0; i <= 16; i++) {       Buffer de datos[i] = 0;     }     if (!(CardDataWrite(USED_Sector, 1, Buffer de datos))) {       return false;     }     for (i = 0; i <= 16; i++) {       Buffer de datos[i] = 0;     }     if (!(CardDataWrite(USED_Sector, 2, Buffer de datos))) {       return false;     }     for (i = 0; i <= 16; i++) {       Buffer de datos[i] = 0;     }     if (!(CardDataWrite(USED_Sector, 3, Buffer de datos))) {       return false;     }   }   for (bytes i = 0; i <= 16; i++) {     ikey[i] = 255;  //Load Default Key for all Sectors   }   ikey[6] = 0xFF; // Default Setting for Access Bits   ikey[7] = 0x07; //   ikey[8] = 0x80; //   ikey[9] = 0x69;   estado = mfrc522.MIFARE_Write(writevector, ikey, 16);   if (estado != MFRC522::STATUS_OK)   {     return false;   }   return true;
}

boolean SetSectorAccessControl (bytes Sector, bytes Akey[6], bytes Bkey[6])
{   bytes ikey[16];   bytes estado;   bytes writevector;   const bytes sectorkeytable [16] = {3, 7, 11, 15, 19, 23, 27, 31, 35, 39, 43, 47, 51, 55, 59, 63};   writevector = sectorkeytable[Sector];   ikey[0] = Akey[0];   ikey[1] = Akey[1];   ikey[2] = Akey[2];   ikey[3] = Akey[3];   ikey[4] = Akey[4];   ikey[5] = Akey[5];   ikey[6] = 0x78; // Data Block 0-3 Access Conditions: Key B write / Key A Read   ikey[7] = 0x77; // KEY A & KEY B & Acces Bits Write:Key B / Key A Read Access Bits   ikey[8] = 0x88; // Calculator: http://calc.gmss.ru/Mifare1k/   ikey[9] = 0x69; // Valor fijo - > default hex 69   ikey[10] = Bkey[0];   ikey[11] = Bkey[1];   ikey[12] = Bkey[2];   ikey[13] = Bkey[3];   ikey[14] = Bkey[4];   ikey[15] = Bkey[5];   estado = mfrc522.MIFARE_Write(writevector, ikey, 16);   if (estado != MFRC522::STATUS_OK)   {     Serial.println(F("ATPCD: W_KEY_ERR"));     return false;   } else   {     return true;   }
}

boolean CheckforDefaultCardKey ()
{   bytes tkey[6];   boolean CardResult;   bytes readvector;   bytes estado;   const bytes sectorkeytable [16] = {3, 7, 11, 15, 19, 23, 27, 31, 35, 39, 43, 47, 51, 55, 59, 63};   bytes sized = 18;   for (bytes i = 0; i <= 6; i++) {     tkey[i] = 255;  //Load Default Key for all Sectors   }   CardResult = true;   if (!Cardautenticate(KEYA, USED_Sector, tkey)) {     CardResult = false;   };   readvector = sectorkeytable[USED_Sector];   estado = mfrc522.MIFARE_Read(readvector, Buffer de datos, &sized);   if (estado != MFRC522::STATUS_OK) {     CardResult = false;   }   /¡if!((Memoria de datos[7] = 0x07) & (memoria de datos [7] = 0x80))) { CardResult = false; };   return CardResult;
}

boolean Writenewmifareclassicpiccpicc ()
{   bytes tkey[6];   bytes i, a;   boolean CardResult;   if (CheckforDefaultCardKey())   {     for (i = 0; i <= 6; i++) {       tkey[i] = 255;  //Load Default Key for all Sectors     }     for (i = 0; i <= 16; i++) {       Buffer de datos[i] = 0;  // Clear Variable Buffer     }     CardResult = true;     if (Cardautenticate(KEYA, USED_Sector, tkey)) // Sector Autenticate     {       // Serial.println ("Auth Sec 0 OK");       if (Surname.length() > 15) {         a = 15;       } else {         a = Surname.length();       }       if (Surname.length() > 0)       {         for (i = 0; i <= 16; i++) {           Buffer de datos[i] = 0;         }         for (i = 0; i <= a; i++) {           Buffer de datos[i] = Surname[i];         }         if (!(CardDataWrite(USED_Sector, 2, Buffer de datos))) {           CardResult = false;  // Sector 0 Block 2 Nombre con Key A         }       }       if (Givenname.length() > 15) {         a = 15;       } else {         a = Givenname.length();       }       if (Givenname.length() > 0)       {         for (i = 0; i <= 16; i++) {           Buffer de datos[i] = 0;         }         for (i = 0; i <= a; i++) {           Buffer de datos[i] = Givenname[i];         }         if (!(CardDataWrite(USED_Sector, 3, Buffer de datos))) {           CardResult = false;  // Sector 0 Block 3 escribir el apellido con Key A         }       }       if (!(SetSectorAccessControl (USED_Sector, MiFareClassicKey.Key_A, MiFareClassicKey.Key_B))) {         CardResult = false;  // (byte Sector, byte Akey[6], byte Bkey[6])       }     } else {       CardResult = false;       return CardResult;     }   } else {     CardResult = false;     return CardResult;   }   if (CardResult)   {     // Serial.println ("PICC written");     CardResult = true;   }   else   {     // Serial.println ("PICC not empty");     CardResult = false;   }   yield();   return CardResult;
}


boolean Readmifareclassicpiccpicc ()
{   boolean CardResult;   bytes i ;   CardResult = true;   if (Cardautenticate(KEYA, USED_Sector, MiFareClassicKey.Key_A)) // Sector Autenticate with READ Key A   {     Givenname = "               "; // PlaceHolder     Surname   = "               "; // PlaceHolder     for (i = 0; i < 18; i++) {       Buffer de datos[i] = 0;  // Clear Variable Buffer     }     if (CardDataRead(USED_Sector, 2)) // Campo extraer nombre     {       for (i = 0; i < 16; i++) {         Surname[i] = char(Buffer de datos[i]);       }     } else {       return false;     }     for (i = 0; i < 18; i++) {       Buffer de datos[i] = 0;  // Clear Variable Buffer     }     if (CardDataRead(USED_Sector, 3)) // Campo extraer apellido     {       for (i = 0; i < 16; i++) {         Givenname[i] = char(Buffer de datos[i]);       }     } else {       return false;     }   } else   {     return false;   }   return true;
}

void CardServer()
{   bytes i ;
# define PCD_Poll_Interval 400
# define PCD_Watchdog_Interval 60000   if (Milis() - PCD_ServiceCall_Handler >= PCD_Poll_Interval)   {     PCD_ServiceCall_Handler = Milis();     if (mfrc522.PICC_IsNewCardPresent())   // PICC = tarjeta inteligente sin contacto     {       mfrc522.PICC_ReadCardSerial();       yield();       // Distinción por tipo de tarjeta       // 0x08 para MIFARE Classic 1K       // 0x18 para MIFARE Classic 4K       // 0x11 para MIFARE PLUS       if (mfrc522.uid.sak == 0x08 || mfrc522.uid.sak == 0x18)       {         // MiFare_Classic_Processor START (mfrc522. uid.sak); / / / ejecutar sólo si una tarjeta Mifare Classic se ha mantenido delante del lector.         bytes tkey[6];         for (bytes i = 0; i <= 6; i++) {           tkey[i] = 255;  //Load Default Key for all Sectors         }         if (LearnNewCard) // se aprenderá un nuevo mapa.         {           if (Writenewmifareclassicpiccpicc()) {             SetRGBLed(0, 255, 0, false);             LearnNewCard = false;           } else           {             SetRGBLed(255, 0, 0, false);             LearnNewCard = false;           }         }         else if (EraseCard)  // Eliminar datos de tarjetas.         {           if (ResetCardToDefault()) {             SetRGBLed(0, 255, 0, false);             EraseCard = false;           } else           {             SetRGBLed(255, 0, 0, false);             EraseCard = false;           }         }         else         {           if (Readmifareclassicpiccpicc())           { /¡Tarjeta válida !             Serial.print (F("ATAUTH_S:"));             Serial.println (Surname);             Serial.print (F("ATAUTH_G:"));             Serial.println (Givenname);             temp = "Tarjeta Válida. Usuario: ";             for (i = 0; i < 16; i++)             {               if  (Givenname[i] == 0)               {                 break;               }               temp += char(Givenname[i]);             }             temp += ", ";             for (i = 0; i < 16; i++)             {               if  (Surname[i] == 0)               {                 break;               }               temp += char(Surname[i]);             }             temp += "- UUID del mapa: ";             for (bytes i = 0; i < 4; i++) {               temp += Cadena(mfrc522.uid.uidByte[i], HEX) + " ";             }             WriteToLog(temp, 0);             temp = " ";             //Do actions if correct Card is detected             bool PinState = digitalRead(RELAIS_PIN);             PinState = !PinState;             write digital(RELAIS_PIN, PinState);             SetRGBLed(0, 255, 0, false);     // Led Verde             temp = "";           } else {             SetRGBLed(255, 0, 0, false);             temp = "";             for (bytes i = 0; i < 4; i++) {               temp += Cadena(mfrc522.uid.uidByte[i], HEX) + " ";             }             temp = "Tarjeta Clásica MiFare Desconocida. UID del mapa: " + temp ;             WriteToLog(temp, 1);             temp = "";           }         }         LearnNewCard = false;         // MiFare_Classic_Processor STOP (mfrc522. uid.sak);       } else if (mfrc522.uid.sak == 0x00) // Mifare Ultralight       {         SetRGBLed(255, 0, 0, false);         temp = "";         for (bytes i = 0; i < 7; i++) {           temp += Cadena(mfrc522.uid.uidByte[i], HEX) + " ";         }         temp = "Mifare UltraLight Mapa no soportado. UID del mapa: " + temp;         WriteToLog(temp, 1);         temp = "";       } else       {         SetRGBLed(255, 0, 0, false);         temp = "";         for (bytes i = 0; i < mfrc522.uid.size; i++) {           temp += Cadena(mfrc522.uid.uidByte[i], HEX) + " ";         }         temp = "Tarjeta desconocida y tipo de tarjeta. Número de tipo: " + Cadena(mfrc522.uid.sak) + "UUID del mapa: " + temp ;         WriteToLog(temp, 1);         temp = "";       }       mfrc522.PCD_StopCrypto1();       mfrc522.PICC_HaltA();       delay(2000);       SetRGBLed(0, 0, 255, false);     // Led Color Azul lector básico     }   }   if (Milis() - PCD_WatchDog_Handler >= PCD_Watchdog_Interval)   {     PCD_WatchDog_Handler = Milis();     Resultado = mfrc522.Pcd_performselfest();     yield();     mfrc522.PCD_Init();                       // Reiniciando módulo de lectura MFRC522     mfrc522.PCD_SetAntennaGain(mfrc522.RxGain_max); // Pone antena en max. Recepción     mfrc522.Pcd_antennaona();     yield();     if (!(Resultado))     {       PCDHardReset();       Serial.println(F("ATPCD: ERR_H"));     }   }
}

// ******************* Stop Functions CardServices  *************************************

void loop()  // Bucle principal
{   servidor.handleClient();                    // Editar solicitudes de servidor web   if (!(PCD_Disabled) | !(Configuración del sistema.PCD_Disabled)) {     CardServer();  // Editar peticiones específicas del lector de tarjetas   }   ESP.wdtFeed();                            // Watchdog. Desactivar con " wdt_disable();"
}

 

Les deseo mucha diversión y éxito en la reconstrucción del proyecto y hasta la próxima vez.

Projekte für fortgeschrittene

3 comentarios

Markus

Markus

Hallo,
vielen Dank für das wunderbare Projekt.
Ich habe es mir einmal durchgelesen und bin gespannt wie es funktionieren wird.
Freundliche Grüße!

Martin Kurth

Martin Kurth

Leider hat Tobias dieses Projekt nicht weiter verfolgt oder veröffentlicht. Ich würde es wirklich gerne einsetzen. Aber leider hat er wohl keine Zeit mehr dafür.

Martin Kurth

Martin Kurth

Ich bekomme die Fehler nicht weg. IDE 1.8.10.

G:\BOX.heidelberg.projekt\MiFare_CardReader-master\CardReader_ESP8266_-Teil_5\CardReader_ESP8266_-Teil_5.ino:27:0: warning: "PINWIRESDA" redefined [enabled by default]

#define PIN_WIRE_SDA 4 ^

In file included from C:\Users\Martin\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.5.2\cores\esp8266/Arduino.h:302:0,

from sketch\CardReader_ESP8266_-_Teil_5.ino.cpp:1:

C:\Users\Martin\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.5.2\variants\nodemcu/pins_arduino.h:29:0: note: this is the location of the previous definition

#define PIN_WIRE_SDA (4) ^

G:\BOX.heidelberg.projekt\MiFare_CardReader-master\CardReader_ESP8266_-Teil_5\CardReader_ESP8266_-Teil_5.ino:28:0: warning: "PINWIRESCL" redefined [enabled by default]

#define PIN_WIRE_SCL 5 ^

In file included from C:\Users\Martin\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.5.2\cores\esp8266/Arduino.h:302:0,

from sketch\CardReader_ESP8266_-_Teil_5.ino.cpp:1:

C:\Users\Martin\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.5.2\variants\nodemcu/pins_arduino.h:30:0: note: this is the location of the previous definition

#define PIN_WIRE_SCL (5) ^

G:\BOX.heidelberg.projekt\MiFare_CardReader-master\CardReader_ESP8266_-Teil_5\CardReader_ESP8266_-_Teil5.ino: In function ‘void saveCredentials()’:

G:\BOX.heidelberg.projekt\MiFare_CardReader-master\CardReader_ESP8266_-Teil_5\CardReader_ESP8266_-_Teil5.ino:806:34: warning: iteration 20u invokes undefined behavior [-Waggressive-loop-optimizations]

MyWiFiConfig.APSTAName[i] = 0; ^

G:\BOX.heidelberg.projekt\MiFare_CardReader-master\CardReader_ESP8266_-Teil_5\CardReader_ESP8266_-_Teil5.ino:804:3: note: containing loop

for (i = 0 ; i < WiFiPwdLen ; i++) // Loeschen der alten Konfiguration ^

In file included from C:\Users\Martin\Documents\Arduino\libraries\MFRC522\src\MFRC522Extended.cpp:8:0:

C:\Users\Martin\Documents\Arduino\libraries\MFRC522\src\MFRC522Extended.h: In constructor ‘MFRC522Extended::MFRC522Extended(uint8_t)’:

C:\Users\Martin\Documents\Arduino\libraries\MFRC522\src\MFRC522Extended.h:81:44: warning: ‘MFRC522::MFRC522’ is deprecated (declared at C:\Users\Martin\Documents\Arduino\libraries\MFRC522\src\MFRC522.h:339): use MFRC522 [-Wdeprecated-declarations]

MFRC522Extended(uint8_t rst) : MFRC522 {}; ^

C:\Users\Martin\Documents\Arduino\libraries\MFRC522\src\MFRC522.cpp: In member function ‘bool MFRC522::MIFARE_SetUid(byte*, byte, bool)’:

C:\Users\Martin\Documents\Arduino\libraries\MFRC522\src\MFRC522.cpp:1853:39: warning: ‘bool MFRC522::MIFARE_OpenUidBackdoor(bool)’ is deprecated (declared at C:\Users\Martin\Documents\Arduino\libraries\MFRC522\src\MFRC522.cpp:1709): will move to extra class in next version [-Wdeprecated-declarations]

if (!MIFARE_OpenUidBackdoor(logErrors)) { ^

C:\Users\Martin\Documents\Arduino\libraries\MFRC522\src\MFRC522.cpp: In member function ‘bool MFRC522::MIFARE_UnbrickUidSector(bool)’:

C:\Users\Martin\Documents\Arduino\libraries\MFRC522\src\MFRC522.cpp:1882:34: warning: ‘bool MFRC522::MIFARE_OpenUidBackdoor(bool)’ is deprecated (declared at C:\Users\Martin\Documents\Arduino\libraries\MFRC522\src\MFRC522.cpp:1709): will move to extra class in next version [-Wdeprecated-declarations]

MIFARE_OpenUidBackdoor(logErrors); ^

Deja un comentario

Todos los comentarios son moderados antes de ser publicados