Limite d'accès aux unités par contactless Card avec NodeMCU et le module RC522 module tiers-WPA, une interface Web avec une protection par mot de passe, des informations d'état et une barre de menus extensible.
Après avoir été au première partie si vous avez défini le matériel et que vous pouvez utiliser une carte pour activer le relais, nous pouvons utiliser notre ESP dans la troisième partie de cette série, un WPS Push Button pour configurer automatiquement la configuration sans fil, et une page de connexion à notre ESP afin de protéger la configuration contre les modifications non autorisées.
Connexion WPA:
Pour pouvoir continuer à stocker les données WPA Push Button dans notre Push, nous devons développer nos services de base dans la partie 1.
Nous avons besoin de 3 résistances précises avec 6,8 Kohm et un palpier. Ce palpeur n'inclut pas la révolte moyenne du diviseur de tension afin que notre ESP puisse enregistrer la pression sur les touches. L'image de la figure montre le débranchement nécessaire et doit devenir le circuit du premier Aritkel AJOUTER.
Voici le code:
#include <SPI.h> #include <MFRC522.h> #include <ESP8266WiFi.h> #include <ESP8266WebServer.h> #include <ESP8266mDNS.h> #include <EEPROM.h> #define RST_PIN 5 // SPI Reset Pin (D1 sortant) #define RELAIS-RELAIS 16 // Relais (D0 Sortie) [LOW Actif]-Le LED interne est également proche du port USB #define SS_PIN 15 // SPI esclave Select Pin #define RGBLED_R 2 // Rouge (D4 Sortie) #define RGBLED_G 0 // vert (D3 sorties)-LED interne sur le module ESP #define RGBLED_B 4 // bleu (D2 Sortie) #define WiFiPwdLen 25 // Longueur de mot de passe WiFi maximale #define STANameLen 20 // Longueur maximale du SSID WiFi #define ESPHostNameLen 20 // Nombre maximal de caractères ESPHostName #define LED_BUILTIN 16 #define PIN_WIRE_SDA 4 #define PIN_WIRE_SCL 5 ADC_MODE(ADC_TOUT); // L'entrée analogique A0 doit être configurée de manière externe. ADC_TOUT (for external voltage), ADC_VCC (for system voltage). MFRC522 mfrc522(SS_PIN, RST_PIN); // Créer une instance de MFRC522 MFRC522::MIFARE_Key clé; ESP8266WebServer serveur(80); // Crée une instance de serveur Web struct WiFiEEPromData { char ESPHostName[ESPHostNameLen]; char APSTAName[STANameLen]; // STATION /AP Point Name TO Connect, if definded char WiFiPwd[WiFiPwdLen]; // WiFiPAssword, if definded char ConfigValid[3]; // If Config is Vaild, jour "TK" is required " }; struct PICCardEEPRomData { char CardVaildUID[4]; char Réservé[4]; }; WiFiEEPromData MyWiFiConfig; PICCardEEPRomData MyEEPROMValidCardUID; // Variable Global Guste bool Résultats = false; bool LearnNewCard = false; Chaîne temp =""; unsigned long SessionID; void setup() { rose(RST_PIN,SORTIES); digitalWrite(RST_PIN,ÉLEVÉ); rose(RELAIS-RELAIS,SORTIES); rose(RGBLED_R,SORTIES); rose(RGBLED_G,SORTIES); rose(RGBLED_B,SORTIES); digitalWrite(RELAIS-RELAIS,ÉLEVÉ); // Relais inactif SetRGBLed(0,0,0,false); // Led FROM série.begin(115200); // Initialiser la communication en série avec le PC avec 115200 bauds yield(); série.println(""); temp = "ATSN:"+ Chaîne(DE.getChipId()); série.println(temp); // Serial.print( "ADC Value: "); Serial.println (analogique (A0)) ; SPI.begin(); // Initialiserai SPI Communication DE.wdtEnable(WDTO_4S); // Starte Watchdog DE.wdtFeed(); digitalWrite(RST_PIN,LOW); SessionID = millièmes(); DE.wdtFeed(); Résultats = startWiFiClient(); DE.wdtFeed(); yield(); EEPROM.begin(512); EEPROM.get(100,MyEEPROMValidCardUID); // A partir de l'adresse 100, le KArte valide est classé EEPROM.end(); InitalizeHTTPServer(); digitalWrite(RST_PIN,ÉLEVÉ); mfrc522.PCD_Reset(); mfrc522.PCD_Init(); // Initialiserai MFRC522 Lecture mfrc522.PCD_AntennaOn(); yield(); DE.wdtFeed(); SetRGBLed(255,0,255,false); // Léd Couleur Lila Initalisation terminée } // ******************* Démarrer l'auxiliaire / Optimization Functions ******************************** void SetRGBLed(octets RedValue,octets GreenValue,octets BlueValue,boolean Slovaque) // Radio à la gestion du RGB Led { digitalWrite(RGBLED_R,LOW); digitalWrite(RGBLED_G,LOW); digitalWrite(RGBLED_B,LOW); if (RedValue == 255) { digitalWrite(RGBLED_R,ÉLEVÉ); } if (GreenValue == 255) { digitalWrite(RGBLED_G,ÉLEVÉ); } if (BlueValue == 255) { digitalWrite(RGBLED_B,ÉLEVÉ); } } // ******************* Arrêter l'auxiliaire / Optimization Functions ********************************* // ******************* Start Functions Webserver ******************************************* // Les cookies de base sont basés sur GIT Extracte: //https://github.com/esp8266/ESPWebServer/blob/master/examples/SimpleAuthentification/SimpleAuthentification.ino bool is_authentified() { if (serveur.hasHeader("Cookie")){ // Cookie trouvé temp = serveur.en-tête("Cookie"); // Serial.println (temp) ; Chaîne SessionStr = Chaîne(DE.getChipId()) + "=" + Chaîne(SessionID); if (temp.indexOf(SessionStr) != -1) { // Web a réussi temp = ""; return vrai; } } // Echec de la tentative Web temp = ""; SessionID = millièmes(); return false; } void handleLogin(){ Chaîne msg; // String cookie = server.header ("Cookie"); // Serial.println (cookie) ; if (serveur.hasArg("DISCONNECT")){ // Disconnection utilisateur ; serveur.sendHeader("Location","/login"); serveur.sendHeader("Contrôle de la mémoire cache","no-cache"); SessionID = millièmes(); temp = Chaîne(DE.getChipId()) + "= NA ; HttpOnly ; SameSite = Strict"; serveur.sendHeader("Cookie Setok",temp); temp = ""; serveur.send(301); return; } if (serveur.hasArg("NOM_UTILISATEUR") && serveur.hasArg("PASSWORD")){ temp = Chaîne(DE.getChipId()); if (serveur.arg("NOM_UTILISATEUR") == "admin" && serveur.arg("PASSWORD") == temp ){ serveur.sendHeader("Location","/"); serveur.sendHeader("Contrôle de la mémoire cache","no-cache"); SessionID = millièmes(); temp = Chaîne(DE.getChipId()) + "=" + Chaîne(SessionID) + "; HttpOnly ; SameSite = Strict"; serveur.sendHeader("Cookie Setok",temp); temp = ""; serveur.send(301); return; } msg = "<script>alert (nom d'utilisateur incorrect ou mot de passe incorrect, ') ;</script>"; } CSS_Header_Template(); temp = "<head><title>Login</title></head><body><DIV ALIGN=CENTER>"; serveur.sendContent(temp); temp = "<h2>Connexion au lecteur de cartes RC522</h2><body><br><br><table border=0 bgcolor=black><tr><th><th><DIV ALIGN=RIGHT><DIV ALIGN=RIGHT>; serveur.sendContent(temp); temp = "<form action='/login' method='post'>Nom d'utilisateur: <input type=text Name='USERNAME' Size=17 required><br>"; serveur.sendContent(temp); temp = "Mot de passe: <input type=password Name='PASSWORD' Size=17 required><br><br><br>< button type = 'submit'"; serveur.sendContent(temp); temp = "name= 'Login_Button' value= '1' style = 'height: 30px; width: 100px' > Login</button></th><br></th></tr></tr></DIV></DIV></table>"; serveur.sendContent(temp); temp = "<br><SMALL>Pour que la connexion fonctionne, les cookies sont permis pour cette page Web.</SMALL>"; serveur.sendContent(temp); temp = msg + "</DIV></body></HTML></HTML>; serveur.sendContent(temp); temp = ""; } void handleNotFound() { SessionID = millièmes(); temp = "Page introuvable. \n \n"; temp += "URI:"; temp += serveur.uri(); temp += "\nMethod:"; temp += (serveur.method() == HTTP_GET)?"GET":"POST"; temp += "\nArguments:"; temp += serveur.args(); temp += "\n"; pour (uint8_t i=0; i<serveur.args(); i++){ temp += " " + serveur.argName(i) + ": " + serveur.arg(i) + "\n"; } serveur.send(404, "text/plain", temp); temp = ""; } void handleNewPICC() { if (!is_authentified()) { serveur.sendHeader("Location","/login"); serveur.sendHeader("Contrôle de la mémoire cache","no-cache"); serveur.send(301); return; } CSS_Header_Template(); temp = "<head><title>Lecteur de cartes RC522</title></head><body>"; serveur.sendContent(temp); HtmlNavStructure(); temp = "<script>Alerte ('Veuillez tenir la carte JETZT avant le lecteur!') ;</script>"; serveur.sendContent(temp); SetRGBLed(255,255,0,false); // Led couleur jaune mode de programmation LearnNewCard = vrai; temp = "</body></html>"; serveur.sendContent(temp); serveur.client().stop(); temp = ""; } void handleRoot(){ if (!is_authentified()){ serveur.sendHeader("Location","/login"); serveur.sendHeader("Contrôle de la mémoire cache","no-cache"); serveur.send(301); return; } // Contenu HTML CSS_Header_Template(); temp = "<head><title>Lecteur de cartes RC522</title></head><body>"; serveur.sendContent(temp); HtmlNavStructure(); temp = "<div ALIGN=CENTER><br><br><br><br><br><br><BIG><BIG>sur le lecteur de carte à puce RC522.</BIG><br>"; serveur.sendContent(temp); temp = "Fond de réserve:" + Chaîne(DE.getResetReason()) + "<br>"; serveur.sendContent(temp); temp = "Espace de segment libre:" + Chaîne(DE.getFreeHeap()) + "Octets<br>"; serveur.sendContent(temp); temp = "Int. Flash:" + Chaîne(DE.getFlashChipRealSize()) + "Octets<br>"; serveur.sendContent(temp); Résultats = mfrc522.PCD_PerformSelfTest(); mfrc522.PCD_Init(); // Initialiserai MFRC522 Lecture mfrc522.PCD_AntennaOn(); if (Résultats) {temp = "Etat RC522 PCD: OK<br>"; } else {temp = "Etat RC522 PCD: erreur!<br>"; } serveur.sendContent(temp); temp = "CPU ID:" + Chaîne(DE.getChipId()) + " @ " + Chaîne(DE.getCpuFreqMHz()) + "MHz<br>"; serveur.sendContent(temp); temp = "<br>Vous êtes connecté avec succès!<br><br><form action='/login' method='get'>"; serveur.sendContent(temp); temp = "<button type='submit' name='DISCONNECT' value='YES' style='height: 30px; width: 200px' >Logout</button>"; serveur.sendContent(temp); temp = "</form></div></body></html></html>; serveur.sendContent(temp); if (serveur.hasArg("Reboot") ) // Système Reboot { DE.wdtFeed(); DE.wdtDisable(); temp = "<script>alert (Le système va redémarrer le système JETZT.)</script>"; serveur.sendContent(temp); serveur.client().stop(); temp = ""; Délay(1000); DE.reset(); Délay(4000); } serveur.client().stop(); temp = ""; } void CSS_Header_Template() // Feuille de style pour tous les pages Web ESP internes. https://wiki.selfhtml.org/wiki/CSS { serveur.setContentLength(CONTENT_LENGTH_UNKNOWN); temp = " <!DOCTYPE HTML PUBLIC '-/-//W3C//DTD HTML 4.01 Transitional / /EN' ><html lang='de'><meta charset='UTF-8'>"; serveur.send (200, "text/html", temp); temp = "<style type='text/css'>* {margin: 0 ; padding: 0 ;} body {background:black; color:darkorchid; font-size: 16px;"; server.sendContent(temp); temp = "font-family: sans-serif, arial;} .nav {width: 1300px; height: 30px; margin: 0 auto ; rayon du border: 5px;} "; serveur.sendContent(temp); temp = "ul li {list-style: none ; width: 200px; line-height: 60px ; position: relative ; background: darkorchid ;"; server.sendContent(temp); temp = "box-shadow: 0px 2px 5px 5px égal ; texte-align: center ; float: left ; background-color: #010000;} ul ul ul {"; serveur.sendContent(temp); temp = "position: absolue ;} .nav > ul > li:nth-of-type (1) {border-radius: 5px 0px 0px 5px ;} .nav > ul > li:nth-of-of-type (5)"; serveur.sendContent(temp); temp = "{border-radius: 0px 5px 5px 0px 0px ;} ul li a {color: rgb (182, 18, 18) ; width: 200px; height: 58px ; display: inline-block;"; server.sendContent(temp); temp = "text-decoration: none ;} ul ul a:hover {font-weight: bold ; bottom hborder: 2px solid #fff;} ul li ul {display: none ;} "; serveur.sendContent(temp); temp = ". nav ul li: hover ul {display: block ;} .fa {margin-right: 5px;} .container {width: 1000px; height: 200px;"; server.sendContent(temp); temp = "margin: 0 auto ; padding:20px 20px;}@media screen and (max-width: 480px) {header {width: 100% ;}"; serveur.sendContent(temp); temp = ". nav {display: none ; width: 100% ; height: auto ;} ul li {width: 100% ; float: none ;} ul li a {width: 100% ;"; server.sendContent(temp); temp = "display: block ;} ul li ul {position: static ;} ul li li ul ul li li {background: #222;}.fa-list.modify {display: block ;} "; serveur.sendContent(temp); temp = ". conteneur {width: 100% ; height: auto ;} body {overflow-x:hidden;}}</style>"; serveur.sendContent(temp); temp = ""; } void HtmlNavStructure() { temp = "<div class='menu'><nav class='nav'><ul>"; serveur.sendContent(temp); temp = "<li><a href='#'>Système</a>"; serveur.sendContent(temp); temp = "<ul><li><a href="/fr"><a href="/fr"></a></li>"; serveur.sendContent(temp); temp = "<li>< a href= ' /?Reboot=YES ' > Redémarrage</a></li>"; serveur.sendContent(temp); temp = "</ul>"; serveur.sendContent(temp); temp = "</li><li><a href='#'>PICC</a>"; serveur.sendContent(temp); temp = "<ul><li><a href="/fr/newPICC"><a href="/fr/newPICC">d'une carte</a></li></ul>"; serveur.sendContent(temp); temp = "</li>"; serveur.sendContent(temp); temp = "</ul></nav></div></div>; serveur.sendContent(temp); temp = ""; } void InitalizeHTTPServer() { bool initok = false; const char * headerkeys[] = {"Agent User-Agent","Cookie"} ; // En-tête de trace size_t headerkeyssize = sizeof(headerkeys)/sizeof(char*); // En-tête de trace serveur.on("/", handleRoot); serveur.on("/login", handleLogin); serveur.on("/newPICC", handleNewPICC); serveur.onNotFound ( handleNotFound ); serveur.collectHeaders(headerkeys, headerkeyssize );// les serveurs, les traceurs serveur.begin(); // Web server start } // ******************* Serveur Web de bout en bout ********************************************* // ******************* Start Functions WiFi Management ************************************* // Fonction de https://www.az-delivery.de/blogs/azdelivery-blog-fur-arduino-und-raspberry-pi/wps-mit-dem-esp8266?ls=de bool startWPS() { bool wpsSuccess = WiFi.beginWPSConfig(); if(wpsSuccess) { // ne doit pas toujours être un nom de réussite! Le SSID est vide après un délai d'attente Chaîne newSSID = WiFi.SSID(); if(newSSID.longueur() > 0) { // Si un SSID a été trouvé, nous avons réussi. yield(); série.println("ATWPS: OK"); saveCredentials(); // Save Credentials to EEPROM } else { série.println("ATWPS: NOK"); } } return wpsSuccess; } bool startWiFiClient() { bool WiFiClientStarted = false; size_t A0_ADCValue = 0; octets i = 0; octets connRes = 0; série.setDebugOutput(false); // A des fins de débogage. WiFi.nom_hôte("CrdRdr41667"); WiFi.softAPdisconnect(vrai); WiFi.disconnect(); WiFi.mode(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 (". "); // Connect sur l'interface série DE.wdtFeed(); Délay(500); yield(); connRes = WiFi.waitForConnectResult(); } if (connRes == 4 ) { // if password is incorrect série.println("ATWIFI:PWDERR"); WiFi.disconnect(); } if (connRes == 6 ) { // modules is not configured in station station série.println("ATWIFI:STAERR"); WiFi.disconnect(); } } if(WiFi.état() == WL_CONNECTED) { DE.wdtFeed(); série.print("ATIP:"); série.println(WiFi.localIP()); WiFi.setAutoReconnect(vrai); // Set whether module will attempt to reconnect to an access point in case it is disconnected. // Setup MDNS responder if (!MDNS.begin("CrdRdr41667")) { série.println("ATMDNS: NOK"); } else { MDNS.addService("http", "tcp", 80); } WiFiClientStarted = vrai; } else { A0_ADCValue = analogique(A0); // Nous n'avions pas de succès, donc nous lançons WPS quand WPS Taster a été poussé à A0 pendant le reste if (A0_ADCValue > 499) { if(startWPS()) { DE.wdtFeed(); Délay(500); WiFi.disconnect(); WiFi.mode(WIFI_STA); WiFi.begin(WiFi.SSID().c_str(), WiFi.psk().c_str()); DE.wdtFeed(); WiFiClientStarted = vrai; } else { WiFiClientStarted = false; WiFi.disconnect(); } } else { WiFi.disconnect(); } } 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 (Chaîne(MyWiFiConfig.ConfigValid) == "TK") { RetValue = vrai; } else { RetValue = false; // Paramètres de WLAN non trouvés. } DE.wdtFeed(); return RetValue; } void saveCredentials() // Ecrier une connexion Wi-fi sur une mémoire EEPROM { size_t i; pour (i = 0 ; i < sizeof(MyWiFiConfig) ; i++) // Loeschen l'ancienne configuration { EEPROM.write(i, 0); } pour (i = 0 ; i < STANameLen ; i++) // Loeschen l'ancienne configuration { MyWiFiConfig.WiFiPwd[i] = 0; } pour (i = 0 ; i < WiFiPwdLen ; i++) // Loeschen l'ancienne configuration { MyWiFiConfig.APSTAName[i] = 0; } temp = WiFi.SSID().c_str(); i = temp.longueur(); temp.toCharArray(MyWiFiConfig.APSTAName,i+1); temp = WiFi.psk().c_str(); i = temp.longueur(); temp.toCharArray(MyWiFiConfig.WiFiPwd,i+1); temp = ""; strncpy(MyWiFiConfig.ConfigValid , "TK", sizeof(MyWiFiConfig.ConfigValid) ); EEPROM.begin(512); EEPROM.put(0, MyWiFiConfig); EEPROM.commit(); EEPROM.end(); DE.wdtFeed(); } // ******************* END Functions StoreCredentialsto EEPROM *************************** void boucle() // Boucle principale { // Uniquement lorsqu'une carte est trouvée et lue, le contenu de la IF est exécuté if (mfrc522.PICC_IsNewCardPresent() && mfrc522.PICC_ReadCardSerial() ) // PICC = approximity integrated card = carte à puce sans contact { série.print("UID PICC:"); pour (octets i = 0; i < mfrc522.uid.size; i++) { // Ecart entre les nombres HEX et les zéros à gauche de l'octet < 16 série.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " "); série.print(mfrc522.uid.uidByte[i], HEX); } bool IsValid = vrai; if (LearnNewCard) { pour (octets i = 0; i < sizeof(MyEEPROMValidCardUID.CardVaildUID); i++) { MyEEPROMValidCardUID.CardVaildUID[i] = mfrc522.uid.uidByte[i]; EEPROM.begin(512); EEPROM.put(100,MyEEPROMValidCardUID); EEPROM.commit(); EEPROM.end(); LearnNewCard = false; } IsValid = vrai; } else { pour (octets i = 0; i < sizeof(MyEEPROMValidCardUID.CardVaildUID); i++) { if (mfrc522.uid.uidByte[i] != MyEEPROMValidCardUID.CardVaildUID[i]) { IsValid = false; } } } if (IsValid) { bool PinState= numérisé(RELAIS-RELAIS); PinState = !PinState; digitalWrite(RELAIS-RELAIS, PinState); SetRGBLed(0,255,0,false); // Led vert série.print("valide".); Délay(2000); SetRGBLed(0,0,255,false); // Led couleur Bleu lecteur est en état de base } else { SetRGBLed(255,0,0,false) ; // Led rouge-La dernière carte n'était pas valide série.print("non valide."); Délay(2000); } série.println(); mfrc522.PICC_Atpha(); // Remplace la carte lue en mode veille afin de pouvoir rechercher d'autres cartes. Délay(100); } serveur.handleClient(); // Editer les demandes du serveur Web yield(); // Appel de fonctions ESP8266 internes DE.wdtFeed(); // Replacez le watchdog. Délay(20); }
Nous compilez le code et chargez-le sur notre ESP. Nous lançons le moniteur série et voyez la sortie suivante:
Le numéro de série du ESP est affiché sur la première ligne. Nous les notons, car nous avons besoin de ceux-ci pour la première inscription sur le site web. La seconde ligne indique l'adresse IP sur notre réseau local. Cette adresse IP est une image dans le navigateur et l'image suivante est obtenue:
Numéro d'identification de connexion: #
Nom d'utilisateur: admin
Mot de passe: numéro de série de la puce ESP. (numéro ATSN)
Si la demande échoue, nous voyons l'image suivante:
Sinon, nous arrivons au menu principal:
PICC = Proximity Integrated Circuit Card
Pour autoriser une nouvelle carte, cliquez sur Enregistrer la carte sous le menu PICC:
Dans l'article suivant de la série, il est dit: " Down the the Rabbit Hole .. Nous nous occupons des fonctions de la carte Classic Mifare nous écrivent des données pour la première fois sur la carte à puce.
1 commentaire
Martin Kurth
Ich würde damit eine Wallbox Für ein E-Auto freischalten wollen. Es muss nur ein 12 V / 30mA Kontakt geschaltet werden. Da nehme ich dann ein Omron G3VM Halbleiterrelais.
Sinnvoll wäre auch eine feste IP. Dann muss man nicht im Terminal nach der Adresse schauen, wenn man später darauf zugreifen will. Helfen würde mir eine Routine, die die Freigabe nach einer definierten Zeit wieder entzieht, also den Ausgang wieder abschaltet. Der Ladevorgang dauert Max ca. 8h im ungünstigsten Fall.