Portal cautivo propio con el ESP 8266

Hola y bienvenidos a un blog especial:

 

Hoy, no debería ser un proyecto terminado, sino más bien una ayuda para muchos de sus propios proyectos relacionados con los datos de acceso WLAN y ESP8266. A menudo existe el problema con los propios proyectos de que los datos de acceso a WLAN se programan permanentemente en su propio código, pero ya no se pueden cambiar posteriormente o el ESP "olvida" sus datos de acceso a WLAN tan pronto como se reinicia. Ambos son problemáticos para una cierta flexibilidad en la configuración. La solución para esto es almacenar los datos de acceso a WLAN en la EEPROM interna y garantizar que se puedan cambiar en cualquier momento, incluso durante el tiempo de ejecución del firmware.

Para hacer esto, el ESP se instala con nuestro código de portal cautivo a continuación en el primer paso Portal cautivo  activado, una WLAN con el nombre "My_WLANDevice" y la contraseña "12345678". Con esto podemos conectarnos a nuestro teléfono móvil y luego se nos dirige automáticamente desde el teléfono móvil al sitio web de Captive Portal. Se ve así:

 

Portal cautivo

 

En esto, ahora podemos hacer clic en el enlace del sistema "Configuración de WiFi", y ahora llegamos a una extensa página de configuración de WiFi, con la que ahora podemos seleccionar una red con la que se debe conectar el ESP:

 

Portal cautivo - Instalaciones WiFi

 

La red de radio seleccionada aquí y la contraseña ingresada se guardan en la EEPROM. En el próximo arranque, el ESP intenta conectarse a esta red. Si el intento falla porque, por ejemplo, ya no se puede acceder a la red o se ha cambiado la contraseña, el ESP vuelve al modo de punto de acceso y espera una nueva configuración.

El código para el portal cautivo es:

 

 

#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <Servidor DNS.h>
#include <EEPROM.h>

estática const byte WiFiPwdLen = 25;
estática const byte APSTANAMELEN = 20;

estática const uint8_t D0   = 16;
estática const uint8_t D1   = 5;
estática const uint8_t D2   = 4;
estática const uint8_t D3   = 0;
estática const uint8_t D4   = 2;
estática const uint8_t D5   = 14;
estática const uint8_t D6   = 12;
estática const uint8_t D7   = 13;
estática const uint8_t D8   = 15;
estática const uint8_t D9   = 3;
estática const uint8_t D10  = 1;

estructura WiFiEEPromData
{   bool APSTA = cierto; // Punto de acceso o modo de estación - modo AP verdadero   bool PwDReq = falso; // Contraseña requerida   bool CapPortal = cierto ; // CaptivePortal activado en modo AP   char APSTAName[APSTANAMELEN]; // ESTACIÓN / AP Nombre del punto PARA CONECTAR, si está definido   char WiFiPwd[WiFiPwdLen]; // WiFiPAssword, si está definido   char ConfigValid[3]; // Si Config es Vaild, se requiere la etiqueta "TK" "
};

estática const corta int BUILTIN_LED0 = D0; // GPIO0
/ * nombre de host para mDNS. Debería funcionar al menos en Windows. Prueba http://esp8266.local */
const char *ESPHostname = "ESP";

// servidor DNS
const byte DNS_PORT = 53;
Servidor DNS dnsServer;

// Conmmon Paramenters
bool SoftAccOK  = falso;

// servidor web
ESP8266WebServer servidor(80);

/ * Parámetros de red de Soft AP * /
IPAddress apIP(172, 20, 0, 1);
IPAddress netMsk(255, 255, 255, 0);


/ ** ¿Debo conectarme a WLAN lo antes posible? * /
booleano conectar;

/ ** La última vez que intenté conectarme a WLAN * /
// long lastConnect Try = 0;
sin firmar largo currentMillis = 0;
sin firmar largo startMillis;
const corta periodo = 10;  // Dormir después de estos minutos de inactividad.


/ ** Estado actual de la WLAN * /
corta estado = WL_IDLE_STATUS;

WiFiEEPromData MyWiFiConfig;
Cadena temp = "";

nulo configuración()
{   bool ConnectSuccess = falso;   bool CreateSoftAPSucc  = falso;   bool Sistema CInitFS  = falso;   bool CInitHTTPServer  = falso;   byte Len;   pinMode(D0, SALIDA); // Inicializa el pin BUILTIN_LED1 como salida   De serie.comenzar(9600);   De serie.println();   Wifi.nombre de host(ESPHostname); // Establece el nombre de host DHCP asignado a la estación ESP.   Si (loadCredentials()) // Cargue las credenciales de WLAN para la configuración de WiFi   {     // Credenciales válidas encontradas.     Si (MyWiFiConfig.APSTA == cierto)  // Modo AP     {       //Serial.println("AP Mode ");       //Serial.println(MyWiFiConfig.APSTA);       Len = Strlen(MyWiFiConfig.APSTAName);       MyWiFiConfig.APSTAName[Len + 1] = '\0';       Len = Strlen(MyWiFiConfig.WiFiPwd);       MyWiFiConfig.WiFiPwd[Len + 1] = '\0';       CreateSoftAPSucc = CreateWifiSoftAP();     } más     {       //Serial.println("STA Mode ");       Len = Strlen(MyWiFiConfig.APSTAName);       MyWiFiConfig.APSTAName[Len + 1] = '\0';       Len = Strlen(MyWiFiConfig.WiFiPwd);       MyWiFiConfig.WiFiPwd[Len + 1] = '\0';       Len = ConnectWifiAP();       Si ( Len == 3 ) {         ConnectSuccess = cierto;       } más {         ConnectSuccess = falso;       }     }   } más   { // Establecer configuración predeterminada - Crear AP     De serie.println("DefaultWiFi Cnf");     SetDefaultWiFiConfig ();     CreateSoftAPSucc = CreateWifiSoftAP();     guardar credenciales();     // Parpadeo     digitalWrite(D0, BAJO); // Tire hacia BAJO _LED ENCENDIDO     retrasar(500);     digitalWrite(D0, ALTO);     retrasar(500);     digitalWrite(D0, BAJO); // Tire hacia BAJO _LED ENCENDIDO     retrasar(500);     digitalWrite(D0, ALTO);     retrasar(500);     digitalWrite(D0, BAJO); // Tire hacia BAJO _LED ENCENDIDO   }   Si ((ConnectSuccess o CreateSoftAPSucc) y CInitFSSystem)   {     InitalizeHTTPServer();     digitalWrite(D0, BAJO); // Tire hacia BAJO _LED ENCENDIDO     De serie.println("OKAY");   }   más   {     De serie.setDebugOutput(cierto); // Salida de depuración para WLAN en la interfaz en serie.     De serie.impresión("Errar");     SetDefaultWiFiConfig ();     CreateSoftAPSucc = CreateWifiSoftAP();     guardar credenciales();     InitalizeHTTPServer();   }   startMillis = millis();  // hora de inicio inicial
}

vacío InitalizeHTTPServer()
{   bool initok = falso;   / * Configurar páginas web: raíz, páginas de configuración wifi, detectores de portal cautivo SO y no encontrado. * /   servidor.en("/", manejarRoot);   servidor.en("/Wifi", handleWifi);   Si (MyWiFiConfig.CapPortal) {     servidor.en("/ generate_204", manejarRoot);  // Portal cautivo de Android. Quizás no sea necesario. Puede ser manejado por el controlador notFound.   }   Si (MyWiFiConfig.CapPortal) {     servidor.en("/favicon.ico", manejarRoot);  // Otro portal cautivo de Android. Quizás no sea necesario. Puede ser manejado por el controlador notFound. Comprobado en Sony Handy   }   Si (MyWiFiConfig.CapPortal) {     servidor.en("/ fwlink", manejarRoot);  // portal cautivo de Microsoft. Quizás no sea necesario. Puede ser manejado por el controlador notFound.   }   //server.on("/generate_204 ", handleRoot); // Portal cautivo de Android. Quizás no sea necesario. Puede ser manejado por el controlador notFound.   //server.on("/favicon.ico ", handleRoot); // Otro portal cautivo de Android. Quizás no sea necesario. Puede ser manejado por el controlador notFound. Comprobado en Sony Handy   //server.on("/fwlink ", handleRoot); // portal cautivo de Microsoft. Quizás no sea necesario. Puede ser manejado por el controlador notFound.   servidor.onNotFound ( handleNotFound );   // Speicherung Header-Elemente anfordern   // server.collectHeaders (Encabezados, sizeof (Encabezados) / sizeof (Encabezados [0]));   servidor.empezar(); // Inicio del servidor web
}

booleano CreateWifiSoftAP()
{   Wifi.desconectar();   De serie.impresión("SoftAP");   Wifi.softAPConfig(apIP, apIP, netMsk);   Si (MyWiFiConfig.PwDReq)   {     SoftAccOK  =   Wifi.softAP(MyWiFiConfig.APSTAName, MyWiFiConfig.WiFiPwd); // Passwortlänge mindestens 8 Zeichen!   } más   {     SoftAccOK  =  Wifi.softAP(MyWiFiConfig.APSTAName); // Punto de acceso SIN contraseña     // Función de sobrecarga :; WiFi.softAP (ssid, contraseña, canal, oculto)   }   retrasar(600); // Sin demora he visto la dirección IP en blanco   Si (SoftAccOK)   {     De serie.println("OKAY");     De serie.println(MyWiFiConfig.APSTAName);     De serie.println(MyWiFiConfig.WiFiPwd);     / * Configurar el servidor DNS redirigiendo todos los dominios a la apIP * /     servidor DNS.setErrorReplyCode(DNSReplyCode::No hay error);     servidor DNS.comienzo(DNS_PORT, "*", apIP);   } más   {     De serie.println("errar");     De serie.println(MyWiFiConfig.APSTAName);     De serie.println(MyWiFiConfig.WiFiPwd);   }   regreso SoftAccOK;
}


byte ConnectWifiAP()
{   // Serial.println ("Inicializando el Cliente Wifi");   byte connRes = 0;   byte yo = 0;   Wifi.desconectar();   Wifi.softAPdisconnect(cierto); // La función establecerá el SSID y la contraseña configurados actualmente del soft-AP en valores nulos. El parámetro es opcional. Si se establece en verdadero, desactivará el modo soft-AP.   Wifi.empezar(MyWiFiConfig.APSTAName, MyWiFiConfig.WiFiPwd);   connRes  = Wifi.waitForConnectResult();   retrasar(500);   mientras (( connRes == 0 ) y (yo != 10))  // if connRes == 0 "IDLE_STATUS - cambiar Statius"   {     connRes  = Wifi.waitForConnectResult();     retrasar(1000);     yo++;     De serie.println(".");     // declaración (s)   }   mientras (( connRes == 1 ) y (yo != 10))  // if connRes == 1 NO_SSID_AVAILin - SSID no puede ser alcanzado   {     connRes  = Wifi.waitForConnectResult();     retrasar(1000);     yo++;     De serie.println(".");     // declaración (s)   }   Si (connRes == 3 ) {     De serie.impresión("STA");     Wifi.setAutoReconnect(cierto); // Establezca si el módulo intentará volver a conectarse a un punto de acceso en caso de que esté desconectado.     // Configurar el respondedor MDNS     Si (!MDNS.empezar(ESPHostname)) {       De serie.println("Err: MDNS");     } más {       MDNS.addService("http", "tcp", 80);     }   }   Si (connRes == 4 ) {     De serie.println("STA Pwd Err");     //Serial.print("PwLen: ");     //Serial.println(strlen(MyWiFiConfig.WiFiPwd));     //Serial.print("PwSize ");     //Serial.println(sizeof(MyWiFiConfig.WiFiPwd));     De serie.println(MyWiFiConfig.APSTAName);     De serie.println(MyWiFiConfig.WiFiPwd);     Wifi.desconectar();   }   // if (connRes == 6) {Serial.println ("DESCONECTADO - No en modo estación"); }   // WiFi.printDiag (serie);   regreso connRes;
}

bool loadCredentials()
{   bool RetValue;   EEPROM.empezar(512);   EEPROM.obtener(0, MyWiFiConfig);   EEPROM.final();   Si (Cuerda(MyWiFiConfig.ConfigValid) = Cuerda("TK"))   {     RetValue = cierto;   } más   {     RetValue = falso; // Configuración de WLAN no encontrada.   }   regreso RetValue;
}


/ ** Almacenar credenciales de WLAN en EEPROM * /

bool guardar credenciales()
{   bool RetValue;   // Verificar errores lógicos   RetValue = cierto;   Si  (MyWiFiConfig.APSTA == cierto ) // Modo AP   {     Si (MyWiFiConfig.PwDReq y (tamaño de(Cuerda(MyWiFiConfig.WiFiPwd)) < 8))     {       RetValue = falso;  // Configuración inválida     }     Si (tamaño de(Cuerda(MyWiFiConfig.APSTAName)) < 1)     {       RetValue = falso;  // Configuración inválida     }   } más // Modo de estación   {   }   // Errores lógicos de verificación final   Si (RetValue)   {     EEPROM.empezar(512);     para (En t yo = 0 ; yo < tamaño de(MyWiFiConfig) ; yo++)     {       EEPROM.escribir(yo, 0);     }     strncpy( MyWiFiConfig.ConfigValid , "TK", tamaño de(MyWiFiConfig.ConfigValid) );     EEPROM.poner(0, MyWiFiConfig);     EEPROM.cometer();     EEPROM.final();   }   regreso RetValue;
}

vacío SetDefaultWiFiConfig ()
{   byte Len;   MyWiFiConfig.APSTA = cierto;   MyWiFiConfig.PwDReq = cierto;  // se requiere PW predeterminado   MyWiFiConfig.CapPortal = cierto;   strncpy( MyWiFiConfig.APSTAName, "My_WLANDevice", tamaño de(MyWiFiConfig.APSTAName) );   Len = Strlen(MyWiFiConfig.APSTAName);   MyWiFiConfig.APSTAName[Len + 1] = '\0';   strncpy( MyWiFiConfig.WiFiPwd, "12345678", tamaño de(MyWiFiConfig.WiFiPwd) ); // Sin contraseña   Len = Strlen(MyWiFiConfig.WiFiPwd);   MyWiFiConfig.WiFiPwd[Len + 1] = '\0';   strncpy( MyWiFiConfig.ConfigValid, "TK", tamaño de(MyWiFiConfig.ConfigValid) );   Len = Strlen(MyWiFiConfig.ConfigValid);   MyWiFiConfig.ConfigValid[Len + 1] = '\0';   De serie.println("RstWiFiCrd");
}

/ ** ¿Es esto una IP? * /
booleano isIp(Cuerda str) {   para (En t yo = 0; yo < str.longitud(); yo++) {     En t C = str.CharAt(yo);     Si (C != '.' && (C < '0' || C > '9')) {       regreso falso;     }   }   regreso cierto;
}

Cuerda GetEncryptionType(byte este tipo) {   Cuerda Salida = "";   // lee el tipo de cifrado e imprime el nombre:   cambiar (este tipo) {     caso ENC_TYPE_WEP:       Salida = "WEP";       regreso Salida;       descanso;     caso ENC_TYPE_TKIP:       Salida = "WPA";       de retorno Salida de;       romper;     caso ENC_TYPE_CCMP:       Salida = "WPA2";       retorno Salida de;       romper;     caso ENC_TYPE_NONE:       Salida = "Ninguno";       de retorno Salida de;       romper;     caso ENC_TYPE_AUTO:       Salida = "Auto";       retorno Salida de;       romper;   }
}

/** IP a la Cadena? */
Cadena toStringIp(IPAddress ip) {   de la Cadena de res = "";   para (int i = 0; i < 3; i++) {     res += de la Cadena de((ip >> (8 * me)) & 0xFF) + ".";   }   res += de la Cadena de(((ip >> 8 * 3)) & 0xFF);   volver res;
}


de la Cadena de formatBytes(size_t bytes) {            // lesbare Anzeige der Speichergrößen   si (bytes < 1024) {     de retorno de la Cadena de(bytes) + " Byte";   } otra cosa si (bytes < (1024 * 1024)) {     de retorno de la Cadena de(bytes / 1024.0) + " KB";   } otra cosa si (bytes < (1024 * 1024 * 1024)) {     de retorno de la Cadena de(bytes / 1024.0 / 1024.0) + " MB";   }
}






vacío handleRoot() {   // Página Principal:   // FSInfo fs_info;   temp = "";   corto PicCount = 0;   byte ServArgs = 0;   //la Construcción de la Página   // Cabecera HTML   de servidor.sendHeader("Cache-Control",, "no-cache, no-store, must-revalidate");   servidor.sendHeader("Pragma", "no-cache");   servidor.sendHeader("Caduca", "-1");   servidor.setContentLength(CONTENT_LENGTH_UNKNOWN);   // Contenido HTML   del servidor.enviar ( 200, "text/html", temp );   // Speichersparen - Schon mal dem Cleint senden   temp = "";   temp += "<!DOCTYPE HTML><html lang='de'><head><meta charset= "UTF-8" ><meta name= área de visualización de contenido='width=device-width, initial-scale=1.0,'>";   servidor de.sendContent(temp);   temp = "";   temp += "<style type='text/css'><!-- DIV.contenedor { min-altura: 10em; display: table-cell; vertical-align: middle }.botón {height:35px; ancho:90px; font-size:16px}";   servidor.sendContent(temp);   temp = "";   temp += "body {background-color: powderblue;}</style>";   temp += "<head><title>Portal Cautivo</title></head>";   temp += "<h2>Portal Cautivo</h2>";   temp += "<body>";   servidor de.sendContent(temp);   temp = "";   temp += "<br><table border=2 bgcolor = white width = 500 cellpadding =5 ><caption><p><h3>Sytemlinks:</h2></p></caption>";   temp += "<tr><th><br>";   temp += "<a href='/wi-fi WIFI>Opciones</a><br><br>";   temp += "</th></tr></table><br><br>";   // temp += "<footer><p>Programado y diseñado por: Tobias Kuch</p><p>información de Contacto: <a href='mailto:tobias.kuch@googlemail.com'>tobias.kuch@googlemail.com</a>.</p></pie>";   temp += "</body></html>";   servidor de.sendContent(temp);   temp = "";   servidor de.cliente de().parada(); // Stop es necesario porque hemos enviado ningún contenido de longitud
}



nula handleNotFound() {   si (captivePortal())   { // Si caprive portal de redirección en lugar de mostrar la página de error.     return;   }   temp = "";   // Cabecera HTML   de servidor.sendHeader("Cache-Control",, "no-cache, no-store, must-revalidate");   servidor.sendHeader("Pragma", "no-cache");   servidor.sendHeader("Caduca", "-1");   servidor.setContentLength(CONTENT_LENGTH_UNKNOWN);   // Contenido HTML   temp += "<!DOCTYPE HTML><html lang='de'><head><meta charset= "UTF-8" ><meta name= área de visualización de contenido='width=device-width, initial-scale=1.0,'>";   temp += "<style type='text/css'><!-- DIV.contenedor { min-altura: 10em; display: table-cell; vertical-align: middle }.botón {height:35px; ancho:90px; font-size:16px}";   temp += "body {background-color: powderblue;}</style>";   temp += "<head><title>no se encuentra el Archivo</title></head>";   temp += "<h2> 404 Archivo No Encontrado " </h2><br>";   temp += "<h4>Información de Depuración:</h4><br>";   temp += "<body>";   temp += "URI: ";   temp += servidor.uri();   temp += "\nMethod: ";   temp += ( server.método() == HTTP_GET ) ? "GET" : , "POST";   temp += "<br / >Argumentos: ";   temp += servidor.args();   temp += "\n";   para ( uint8_t me = 0; he < servidor.args(); i++ ) {     temp += " " + de servidor.argName ( yo ) + ": " + server.arg ( i ) + "\n";   }   temp += "<br / >Servidor de encabezado de host: " + servidor.de encabezado de host();   para ( uint8_t me = 0; he < servidor.encabezados(); i++ ) {     temp += " " + de servidor.headerName ( yo ) + ": " + server.encabezado ( i ) + "\n<br>";   }   temp += "</table></form><br><br><table border=2 bgcolor = white width = 500 cellpadding =5 ><caption><p><h2>puede Que desee examinar a:</h2></p></caption>";   temp += "<tr><th>";   temp += "<a href='/'>Página Principal</a><br>";   temp += "<a href='/wi-fi WIFI>Ajustes</a><br>";   temp += "</th></tr></table><br><br>";   //temp += "<pie de página><p>Programado y diseñado por: Tobias Kuch</p><p>información de Contacto: <a href='mailto:tobias.kuch@googlemail.com'>tobias.kuch@googlemail.com</a>.</p></pie>";   temp += "</body></html>";   servidor de.enviar ( 404, "", temp );   servidor de.cliente de().parada(); // Stop es necesario porque hemos enviado ningún contenido de longitud   temp = "";

}




/** Redirigir a portal cautivo si recibimos una solicitud de otro dominio. Devolver true en ese caso, de modo que la página de controlador no trate de controlar la solicitud de nuevo. */
boolean captivePortal() {   si (!isIp(servidor.de encabezado de host()) && del servidor.de encabezado de host() != (de la Cadena de(ESPHostname) + ".local")) {     // Serial.println("Solicitud de redirigido al portal cautivo");     servidor.sendHeader("Ubicación", de la Cadena("http://") + toStringIp(servidor de.cliente().localIP()), verdadero);     servidor.enviar ( 302, "text/plain", ""); // Vacía de contenido inhibe el encabezado Content-length así que tenemos que cerrar el socket a nosotros mismos.     servidor de.cliente de().parada(); // Stop es necesario porque hemos enviado ningún contenido de longitud     return true;   }   return false;
}



/** Wifi config página manejador */
void handleWifi()
{   // Página: /wifi   byte i;   byte len ;   temp = "";   // Verificación de Parámetros de Sitio   si (el servidor de.hasArg("Reboot") )  // Reiniciar el Sistema   {     temp = "Reiniciar el Sistema en 5 Segundos..";     servidor.enviar ( 200, "text/html", temp );     retraso(5000);     de servidor de.cliente().deje de();     WiFi.de desconexión();     retardo(1000);     pinMode(D6, SALIDA);     digitalWrite(D6, BAJA);   }   si (el servidor de.hasArg("WiFiMode") y (server.arg("WiFiMode") == "1")  )  // STA Estación Modo de Conectarse a otro WIFI de la Estación de   {     startMillis = millis(); // Tiempo de Restablecimiento Hasta Contador para evitar Modo Inactivo whiole operativo     // Conectarse a una ESTACIÓN existente     si ( sizeof(server.arg("WiFi_Network")) > 0  )     {       de Serie.println("STA Mode");       MyWiFiConfig.APSTA = false; // Punto de Acceso o Estación Modo - Estación de falsa Modo       temp = "";       para ( que yo = 0; me < APSTANameLen; me++) {         MyWiFiConfig.APSTAName[i] =  0;       }       temp = server.arg("WiFi_Network");       len =  temp.longitud();       para ( que yo = 0; me < len; me++)       {         MyWiFiConfig.APSTAName[i] =  temp[i];       }       // MyWiFiConfig.APSTAName[len+1] = '\0';       temp = "";       para ( que yo = 0; me < WiFiPwdLen; me++)  {         MyWiFiConfig.WiFiPwd[i] =  0;       }       temp = server.arg("STAWLanPW");       len =  temp.longitud();       para ( que yo = 0; me < len; yo++)       {         si (temp[i] > 32) //Steuerzeichen raus         {           MyWiFiConfig.WiFiPwd[i] =  temp[i];         }       }       // MyWiFiConfig.WiFiPwd[len+1] = '\0';       temp = "WiFi Conectarse a AP: -";       temp += MyWiFiConfig.APSTAName;       temp += "-<br / >wi-fi PW: -";       temp += MyWiFiConfig.WiFiPwd;       temp += "-<br>";       temp += "Conexión a Modo STA en 2 Segundos..<br>";       servidor.enviar ( 200, "text/html", temp );       servidor.sendContent(temp);       retraso(2000);       de servidor de.cliente().detener();       el servidor.deje de();       temp = "";       WiFi.se desconecte();       el WiFi.softAPdisconnect(cierto);       retraso(500);       // ConnectWifiAP       bool SaveOk = saveCredentials();       pinMode(D6, SALIDA);       digitalWrite(D6, BAJA);       me = ConnectWifiAP();       retraso(700);       si (yo != 3) // 4: WL_CONNECT_FAILED - la Contraseña es incorrecta 1: WL_NO_SSID_AVAILin - Configurar el SSID no puede ser alcanzado       {         de Serie.impresión("Err STA");         de Serie.println(yo);         de servidor de.cliente().deje de();         retraso(100);         WiFi.setAutoReconnect (falso);         retraso(100);         WiFi.desconexión();         retardo(1000);         pinMode(D6, SALIDA);         digitalWrite(D6, BAJA);         return;       } else       {         // Safe Config         bool SaveOk = saveCredentials();         InitalizeHTTPServer();         de retorno;       }     }   }   si (el servidor de.hasArg("WiFiMode") y (servidor de.arg("WiFiMode") == "2")  )  // Cambio del Modo de AP   {     startMillis = millis(); // Tiempo de Restablecimiento Hasta Contador para evitar Modo Inactivo whiole operativo     // Configurar el Punto de Acceso     temp = server.arg("APPointName");     len =  temp.longitud();     temp = server.arg("APPW");     si (el servidor de.hasArg("PasswordReq"))     {       i =  temp.de longitud();     } otra cosa {       yo = 8;     }     si (  ( len > 1 ) y (servidor.arg("APPW") == server.arg("APPWRepeat")) y ( yo > 7)          )     {       temp = "";       Serie.println("APMode");       MyWiFiConfig.APSTA = true; // Punto de acceso o Estación Modo cierto Modo AP       si (el servidor de.hasArg("CaptivePortal"))       {         MyWiFiConfig.CapPortal = true ; //CaptivePortal en Modo AP       } más {         MyWiFiConfig.CapPortal = false ;       }       si (el servidor de.hasArg("PasswordReq"))       {         MyWiFiConfig.PwDReq = true ; //se necesita la Contraseña en Modo AP       } más {         MyWiFiConfig.PwDReq = falsa ;       }       para ( que yo = 0; me < APSTANameLen; me++) {         MyWiFiConfig.APSTAName[i] =  0;       }       temp = server.arg("APPointName");       len =  temp.longitud();       para ( que yo = 0; me < len; me++) {         MyWiFiConfig.APSTAName[i] =  temp[me];       }       MyWiFiConfig.APSTAName[len + 1] = '\0';       temp = "";       para ( que yo = 0; me < WiFiPwdLen; me++)  {         MyWiFiConfig.WiFiPwd[i] =  0;       }       temp = server.arg("APPW");       len =  temp.longitud();       para ( que yo = 0; me < len; me++)  {         MyWiFiConfig.WiFiPwd[i] =  temp[me];       }       MyWiFiConfig.WiFiPwd[len + 1] = '\0';       temp = "";       si (saveCredentials()) // Guardar AP ConfigCongfig       {         temp = "Daten des AP Modos de erfolgreich gespeichert. Reinicio notwendig.";       } otra cosa  {         temp = "Daten des AP Modos de fehlerhaft.";       }     } otra cosa si (el servidor de.arg("APPW") != server.arg("APPWRepeat"))     {       temp = "";       temp = "WLAN Contraseña nicht gleich. Abgebrochen.";     } otra cosa     {       temp = "";       temp = "WLAN Contraseña o Nombre de AP zu kurz. Abgebrochen.";     }     // Final WifiAP   }   // Cabecera HTML   de servidor.sendHeader("Cache-Control",, "no-cache, no-store, must-revalidate");   servidor.sendHeader("Pragma", "no-cache");   servidor.sendHeader("Caduca", "-1");   servidor.setContentLength(CONTENT_LENGTH_UNKNOWN);   // Contenido HTML   temp += "<!DOCTYPE HTML><html lang='de'><head><meta charset= "UTF-8" ><meta name= área de visualización de contenido='width=device-width, initial-scale=1.0,'>";   servidor.enviar ( 200, "text/html", temp );   temp = "";   temp += "<style type='text/css'><!-- DIV.contenedor { min-altura: 10em; display: table-cell; vertical-align: middle }.botón {height:35px; ancho:90px; font-size:16px}";   temp += "body {background-color: powderblue;}</style><head><title>Smartes Tuerschild - Configuración WiFi</title></head>";   servidor de.sendContent(temp);   temp = "";   temp += "<h2>WiFi Einstellungen</h2><body><izquierda>";   temp += "<table border=2 bgcolor = white width = 500 ><td><h4>Actual Configuración WiFi: </h4>";   si (el servidor de.cliente().localIP() == apIP) {     temp += "Modo : Suave Punto de Acceso (AP)<br/>";     temp += "SSID : " + Cadena de (MyWiFiConfig.APSTAName) + "<br><br>";   } más {     temp += "Modo de : Estación (STA) <br/>";     temp += "SSID : " + Cadena de (MyWiFiConfig.APSTAName) + "<br>";     temp += "BSSID : " + WiFi.BSSIDstr() + "<br><br>";   }   temp += "</td></table><br>";   servidor de.sendContent(temp);   temp = "";   temp += "<form action='/wifi' method='post'>";   temp += "<table border=2 bgcolor = white width = 500><tr><th><br/>";   si (MyWiFiConfig.APSTA == 1)   {     temp += "<input type='radio' value='1' name='WiFiMode' > wi-fi Modo de Estación<br>";   } más   {     temp += "<input type='radio' value='1' name='WiFiMode' checked > wi-fi Modo de Estación<br>";   }   temp += "Redes WiFi Disponibles:<table border=2 bgcolor = white ></tr></th><td>Cantidad </td><td>SSID </td><td>Seguridad </td><td>WiFi Fuerza </td>";   servidor de.sendContent(temp);   temp = "";   WiFi.scanDelete();   int n = WiFi.scanNetworks(false, false); //WiFi.scanNetworks(async, show_hidden)   si (n > 0) {     para (int i = 0; i < n; i++) {       temp += "</tr></th>";       Cadena de Nrb = Cadena(i);       temp += "<td>" + Nrb + "</td>";       temp += "<td>" + WiFi.SSID(i) + "</td>";       Nrb = GetEncryptionType(WiFi.encryptionType(i));       temp += "<td>" + Nrb + "</td>";       temp += "<td>" + Cadena de(WiFi.RSSI(i)) + "</td>";     }   } más {     temp += "</tr></th>";     temp += "<td>1 </td>";     temp += "<td>Sin WLAN encontrado</td>";     temp += "<td> --- </td>";     temp += "<td> --- </td>";   }   temp += "</table><table border=2 bgcolor = white ></tr></th><td>Conectarse a wi-fi SSID: </td><td><select name='WiFi_Network' >";   si (n > 0) {     para (int i = 0; i < n; i++) {       temp += "<option value='" + WiFi.SSID(i) + "'>" + WiFi.SSID(i) + "</option>";     }   } más {     temp += "<option value='No_WiFi_Network'>No WiFiNetwork encontrado !/opción>";   }   servidor de.sendContent(temp);   temp = "";   temp += "</select></td></tr></th></tr></th><td>Contraseña de wi-fi: </td><td>";   temp += "<input type='text' name='STAWLanPW' maxlength='40' size='40'>";   temp += "</td></tr></th><br></th></tr></table></table><table border=2 bgcolor = white width = 500 ><tr><th><br>";   servidor.sendContent(temp);   temp = "";   si (MyWiFiConfig.APSTA == verdadero)   {     temp += "<input type='radio' name='WiFiMode' value='2' checked> Punto de Acceso WiFi en el Modo <br/>";   } más   {     temp += "<input type='radio' name='WiFiMode' value='2' > Punto de Acceso WiFi en el Modo <br/>";   }   temp += "<table border=2 bgcolor = white ></tr></th> <td>Punto de Acceso WiFi Nombre: </td><td>";   servidor de.sendContent(temp);   temp = "";   si (MyWiFiConfig.APSTA == verdadero)   {     temp += "<input type='text' name='APPointName' maxlength='" + Cadena de(APSTANameLen - 1) + "' size='30' value='" + Cadena de(MyWiFiConfig.APSTAName) + "'></td>";   } más   {     temp += "<input type='text' name='APPointName' maxlength='" + Cadena de(APSTANameLen - 1) + "' size='30' ></td>";   }   servidor de.sendContent(temp);   temp = "";   si (MyWiFiConfig.APSTA == verdadero)   {     temp += "</tr></th><td>Contraseña de wi-fi: </td><td>";     temp += "<input type='password', nombre='APPW' maxlength='" + Cadena de(WiFiPwdLen - 1) + "' size='30' value='" + Cadena de(MyWiFiConfig.WiFiPwd) + "'> </td>";     temp += "</tr></th><td>Repita la Contraseña de WiFi: </td>";     temp += "<td><input type='password', nombre='APPWRepeat' maxlength='" + Cadena de(WiFiPwdLen - 1) + "' size='30' value='" + Cadena de(MyWiFiConfig.WiFiPwd) + "'> </td>";   } más   {     temp += "</tr></th><td>Contraseña de wi-fi: </td><td>";     temp += "<input type='password', nombre='APPW' maxlength='" + Cadena de(WiFiPwdLen - 1) + "' size='30'> </td>";     temp += "</tr></th><td>Repita la Contraseña de WiFi: </td>";     temp += "<td><input type='password', nombre='APPWRepeat' maxlength='" + Cadena de(WiFiPwdLen - 1) + "' size='30'> </td>";   }   temp += "</table>";   servidor de.sendContent(temp);   temp = "";   si (MyWiFiConfig.PwDReq)   {     temp += "<input type='checkbox' name='PasswordReq' checked> Contraseña de inicio de Sesión requerido. ";   } otra cosa   {     temp += "<input type='checkbox' name='PasswordReq' > Contraseña de inicio de Sesión requerido. ";   }   servidor.sendContent(temp);   temp = "";   si (MyWiFiConfig.CapPortal)   {     temp += "<input type='checkbox' name='CaptivePortal' checked> Activar Portal Cautivo";   } más   {     temp += "<input type='checkbox' name='CaptivePortal' > Activar Portal Cautivo";   }   servidor.sendContent(temp);   temp = "";   temp += "<br></tr></th></table><br> <button type='submit' name='La configuración de' value='1' style='height: 50px; width: 140px' de enfoque automático>Ajustar la Configuración WiFi</button>";   temp += "<button type='submit' name='Reiniciar' value='1' style='height: 50px; width: 200px' >Reboot System</button>";   servidor de.sendContent(temp);   temp = "";   temp += "<button type= "reset" name='acción' value='1' style='height: 50px; width: 100px' >Reset</button></form>";   temp += "<table border=2 bgcolor = white width = 500 cellpadding =5 ><caption><p><h3>Sytemlinks:</h2></p></caption><tr><th><br>";   servidor de.sendContent(temp);   temp = "";   temp += "<a href='/'>Página Principal</a><br><br></th></tr></table><br><br>";   //temp += "<footer><p>Programado y diseñado por: Tobias Kuch</p><p>Información de Contacto: <a href='mailto:tobias.kuch@googlemail.com'>tobias.kuch@googlemail.com</a>.</p></pie>";   temp += "</body></html>";   servidor de.sendContent(temp);   servidor de.cliente de().parada(); // Stop es necesario porque hemos enviado ningún contenido de longitud   temp = "";
}

#define SD_BUFFER_PIXELS 20

void loop()
{   si (SoftAccOK)   {     dnsServer.processNextRequest(); //DNS   }   //HTTP   server.handleClient();   rendimiento();
}

 

 

Ich wünsche viel Spaß beim testen des Portales Cautivos und bei der Implementierung en eigene Projekte.

Precipitador electrostático - 8266Projekte für fortgeschrittene

14 comentarios

MaKo

MaKo

Hallo ,
Danke , das Portal funktioniert nach Beseitigung der Compilerfehlermeldungen (fix Portzuweisungen erstellt! Ja ich weiß portabler Code schaut anders aus) Aber zunächst muß der Code ja erst mal übersetzt werden.
Bei mir erscheint das Portal nur auf einem alten Windows mobile! Bei anderen Mobiles (Android devices) kann ich nur die Netzwerkinfo Seite anschauen?? Habe dann auf dem WinGerät meine Home SSID und mein Passwrt eingegeben. Aber nach Netztrennenung und wieder anschalten ist wieder nur My_WlANDevice aktive!
Ich würde gerne meine 8-10 ESP Knoten die mit Mosquitto MQTT Brooker arbeiten und fix mit meinem Heim-Netzwerk verbunden sind mit dem Captive portal verknüpfen, weiss aber nicht wie ich das bewerkstelligen soll! (wenn denn die Auswahl erhalten bliebe) gibts da noch eine Anleitung ?
Bedanke mich schon mal im vorraus
Gruß Martin

ILIJA

ILIJA

Hello Tobias,
I see mistake in the loadCredentials():
if (String(MyWiFiConfig.ConfigValid) = String(“TK”)) —> it will not work correctly.
Shall be:
if (String(MyWiFiConfig.ConfigValid) == String(“TK”)) —> use “==” intead of “=”

Same for ESP32.

Regards
Ilija

Rudolf Schenke

Rudolf Schenke

Mit der von mit vermuteten Änderung (Vereinfachen des if-Ausdrucks) läuft es!!

Rudolf Schenke

Rudolf Schenke

Im Code muss ein Fehler sein!? Nach jedem Reset landet der ESP wieder im AP-Mode.
Die vermutete Fehlerquelle:
– in setup() oben: bool CInitFSSystem = false;
– in setup() weiter unten: if ((ConnectSuccess or CreateSoftAPSucc) and CInitFSSystem) Da die Variable “CInitFSSystem” nie auf “true” gesetzt wird, kommt das Programm auch nie weiter.

Th. Springer

Th. Springer

Hallo zusammen,

ohne diese Werte geht auch das Compilieren des Codes und auch die Funktion dazu auf einem ESP8266.
-——————————————————————————
static const uint8_t D0 = 16;
static const uint8_t D1 = 5;
static const uint8_t D2 = 4;
static const uint8_t D3 = 0;
static const uint8_t D4 = 2;
static const uint8_t D5 = 14;
static const uint8_t D6 = 12;
static const uint8_t D7 = 13;
static const uint8_t D8 = 15;
static const uint8_t D9 = 3;
static const uint8_t D10 = 1;
-———————————————————————————-
Im GitHub Portal ist das nicht drin !

mfg
Th. Springer

Alex

Alex

Danke für den Blogbeitrag!
Wenn man aber nicht alles selber machen will, gibt es die fertige Bibliothek “WifiManager” (MIT Lizenz) für den ESP8266 ;)

https://github.com/tzapu/WiFiManager

Rolf Schatten

Rolf Schatten

Super Idee, unter welcher Lizenz steht der Code?

Ralf Krämer

Ralf Krämer

Hallo,

hat das schon jemand mit einem esp32 umgesetzt?
Ich gehe mal davon aus, dass es die includes alle für esp32 gibt.

Gruß
Ralf

Jürgen Willnecker

Jürgen Willnecker

Schöne Idee, dieses grundlegende Problem als source code zur Verfügung zu stellen.

Ich würde mir bei den externen Spezialaufrufen einen erklärenden Kommentar wünschen.

Im code Hardwareanschlüsse (D0, D6) direkt anzusprechen, führt zu Fehlern beim Wechsel des Boards. Ein “no-go”.

Bei meinem Wemos D1 liegt die blaue BuildInLED auf D4. Bei einem ESP-01 mal so, mal anders (es gibt hier 2 verschiedene Versionen).
const int LED_blue1 = 2; // blaue LED (ESP-01S) – Board #1
const int LED_blue2 = 1; // blaue LED (ESP-01S) – Board #2

D0 erklärt sich jedoch über eine Definition im source code.
Aber D6? Muss da mit Reset gebrückt werden? Wozu ist ein LOW erforderlich?

Christian Zittier

Christian Zittier

Vorerst mal Danke jedoch hab ich aufgrund meiner Unwissenheit ein Problem mit dem Code.
Nach dem Flashvorgang (NodeMCU V3) sehe ich im Browser die Seite stelle wie beschrieben die WLan Einstellungen um er Übernimmt auch das Netzwerk und ist unter der neuen IP verfügbar aber nach einem Reset oder Stromausfall ist alles weg.
Eigentlich sollte der neue WLan Zugang im EEprom gespeichert werden macht es aber offensichtlich nicht? Bei einem Reboot von der Webseite aus bleiben die WLan Einstellungen erhalten

Hab auch mehrere Bord Einstellungen probiert jedoch ohne erfolg.
Würde mich freuen wenn mann mir auf die Sprünge hilft wollte auch ein fertiges funktionierendes Projekt mit meinen MQTT-Brocker integrieren (WLan Einstellungen aus dem Projekt entfernt und mit diesem Code ersetzt geht leider auch nicht irgendwie bin ich einfach zu Blöd. Mein Gedanke selbst wenn nach einem Neustart die WLan Einstellungen weg sind und ich nicht weiß warum, so müsste ja nach dem Anpassen der WLan Einstellungen das integrierte Projekt doch funktionieren?

l.g. Christian

Ilias

Ilias

Hallo Tobias,

vielen Dank, wirklich eine schöne Idee und optisch sehr ansprechend.

Daher habe es auch gleich auf einem “AZ-Delivery NodeMCU ESP8266-12E mit OLED Display” ausprobiert – leider mit mäßigem Erfolg:

Der AP-Mode funzt Wechsel in den Server-Mode funktioniert nur selten. Meistens wird wieder in den AP-Mode gewechselt. Beim Versuch, mit dem Handy (Adroid, Samsung S7 und S9) zuzugreifen eine Meldung dass es eine unseicher Verbindung sei und daher der Zugriff unterbunden wird (AP und Server-Mode). Wenn man die Daten für den AP-Mode ändern will, werden die Änderungen nicht im EEPROM gespeichert. Es ist bleiben immer die Default-Werte.

Leider sind die Meldungen auf der Seriellen Schnittstelle teilweise sehr kryptisch, was ein Debuggen erschwert.

Hat wer eine Idee, wie man das Programm verbessern kann, so dass es stabil läuft?
Zusatzfrage: Ich möchte die jeweilig IP-Adresse auf dem OLED ausgeben. Konnte aber weder die passenden stellen im Programm, noch den Funkitonsaufruf für die IP finden.

Grüße,
Ilias

Ulrich Klaas

Ulrich Klaas

Hallo,
das Portal funktioniert. Ich kann mit dem Handy zugreifen und die Zugangsdaten meines Routers eintragen. Wenn ich danach aber neu boote bleibt nach wie vor der Accesspoint
sichtbar und die NodeMCU verbindet sich nicht mit meinem Router.

Ich habe allerdings den Namen des Portals geändert. Das kann aber wohl nicht der Grund sein, oder ?

Ulrich Klaas

Ulrich Klaas

Was sollen den die Constdefinitionen von D0 – D10 ?
Ich kriege da Fehlermeldungen weil die natürlich schon definiert sind (NodeMCU).

Nehme ich die raus compiliert es.
Ulli

Hermann Schönbauer

Hermann Schönbauer

Super!!! Habe es bisher über eine starre “Notverbindung” zu einer fixen SSID gelöst. Aber so ist es wesentlich eleganter und überall einsetzbar.
Gratuliere
Hermann

Deja un comentario

Todos los comentarios son moderados antes de ser publicados