Captive Portal Blog: Ein Fileserver für den ESP32 Teil 3 - AZ-Delivery

Hola y bienvenido

 a una nueva parte de la serie del portal ESP Captive. En hoy  Blog estamos ampliando nuestro portal cautivo con una primera aplicación: como un servidor de archivos! Los archivos con un tamaño máximo de SPIFFS interno se pueden cargar a través del portal web, pero también se pueden volver a descargar. Para controlar convenientemente esta función, estamos creando nuestro menú principal uno másen (sub) punto de: Insertamos el punto "Filemanger" como un enlace en los enlaces del sistema y construimos una subpágina con las funciones de archivo más importantes que necesita dicho servidor de archivos. La página principal de nuestro servidor de archivos se ve así:

Vemos el nuevo punto "Filemanager". Bajo este punto, ahora estamos construyendo un nuevo sitio web que contiene todos los puntos importantes para la gestión de archivos:

Antes de que podamos usar el sistema de archivos SPIFFS a través de nuestro servidor web para almacenar nuestro primer archivo, debemos formatearlo. También está el enlace "Formatear sistema de archivos SPIFFS", que, después de hacer clic, formatea el sistema de archivos SPIFFS para el primer uso. Así que primero hacemos clic en él y esperamos que el sistema de archivos se formatee internamente. El primer archivo se puede guardar. Usamos los botones de arriba para almacenar / crear archivos.

Por un lado, este sería un botón con el que se puede seleccionar un archivo del almacenamiento local en el disco duro y también un botón con el que este archivo seleccionado se puede cargar en nuestro ESP.

Este archivo aparece luego de una recarga automática de la página en la parte superior en "Archivos disponibles en SPIFFS". Allí se puede descargar nuevamente, pero también se puede eliminar si ya no es necesario. Nada más es necesario para un sistema de almacenamiento de archivos. La memoria es suficiente para varios archivos pequeños o imágenes.

El código para el portal cautivo para el ESP32, complementado por la funcionalidad del servidor de archivos, es:

[

#include <WiFi.h>
#include <WiFiClient.h> 
#include <Servidor web.h>
#include <ESPmDNS.h>
#include <SPIFFS.h>
#include <Servidor DNS.h>
#include <EEPROM.h>

#definir GPIO_OUT_W1TS_REG (DR_REG_GPIO_BASE + 0x0008)
#definir GPIO_OUT_W1TC_REG (DR_REG_GPIO_BASE + 0x000c)

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

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" "   };

/ * nombre de host para mDNS. Debería funcionar al menos en Windows. Prueba http://esp8266.local */
const char *ESPHostname = "ESP32";

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

// Conmmon Paramenters
bool SoftAccOK  = falso;

// servidor web
Servidor web servidor(80);

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

sin firmar largo currentMillis = 0;
sin firmar largo startMillis;

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

Archivo fsUploadFile;              // un objeto File para almacenar temporalmente el archivo recibido
WiFiEEPromData MyWiFiConfig;
Cadena getContentType(Cadena nombre de archivo); // convierte la extensión del archivo al tipo MIME
bool handleFileRead(Cadena camino);       // envía el archivo correcto al cliente (si existe)
nulo handleFileUpload();                // cargar un nuevo archivo a SPIFFS
Cadena temp ="";


nulo configuración() 
{   REG_WRITE(GPIO_OUT_W1TS_REG, BIT(GPIO_NUM_16));     // Conjunto de corrección de errores de meditación Guru   retrasar(1);   REG_WRITE(GPIO_OUT_W1TC_REG, POCO(GPIO_NUM_16));     // Solución de error de meditación Guru claro   bool ConnectSuccess = falso;   bool CreateSoftAPSucc  = falso;   bool CInitFSSystem  = falso;   bool CInitHTTPServer  = falso;   byte Len;    De serie.empezar(9600);    mientras (!De serie) {     ; // espera a que se conecte el puerto serie. Necesario para USB nativo   }   De serie.println(F("Interfaz serie inicializada a 9600 baudios".));    Wifi.setAutoReconnect (falso);   Wifi.persistente(falso);   Wifi.desconectar();    Wifi.setHostname(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   {       De serie.println(F("Credenciales válidas encontradas".));         Si (MyWiFiConfig.APSTA == cierto)  // Modo AP       {          De serie.println(F("Modo de punto de acceso seleccionado".));          Len = Strlen(MyWiFiConfig.APSTAName);         MyWiFiConfig.APSTAName[Len+1] = '\0';          Len = Strlen(MyWiFiConfig.WiFiPwd);         MyWiFiConfig.WiFiPwd[Len+1] = '\0';           CreateSoftAPSucc = CreateWifiSoftAP();       } más       {         De serie.println(F("Modo de estación seleccionado".));                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(F("NO se encontraron credenciales válidas".));       SetDefaultWiFiConfig ();      CreateSoftAPSucc = CreateWifiSoftAP();       guardar credenciales();      retrasar(500);        }   // Inicializar sistema de archivos   CInitFSSystem = InitalizeFileSystem();    Si (!(CInitFSSystem)) {De serie.println(F("¡Sistema de archivos no inicializado!")); }    Si ((ConnectSuccess o CreateSoftAPSucc))     {                De serie.impresión (F("Dirección IP: "));       Si (CreateSoftAPSucc) { De serie.println(Wifi.softAPIP());}          Si (ConnectSuccess) { De serie.println(Wifi.localIP());}       InitalizeHTTPServer();          }     más     {       De serie.setDebugOutput(cierto); // Salida de depuración para WLAN en la interfaz en serie.       De serie.println(F("Error: no se puede conectar a la WLAN. Establezca la configuración POR DEFECTO".));       SetDefaultWiFiConfig();       CreateSoftAPSucc = CreateWifiSoftAP();       InitalizeHTTPServer();         SetDefaultWiFiConfig();       guardar credenciales();        } 
}

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);   servidor.en("/ sistema de archivos", HTTP_GET,handleDisplayFS);   servidor.en("/subir", HTTP_POST, []() {   servidor.enviar(200, "Texto sin formato", "");   }, handleFileUpload);    // if (MyWiFiConfig.CapPortal) {server.on ("/ generate_204", handleRoot); } // Portal cautivo de Android. Quizás no sea necesario. Puede ser manejado por el controlador notFound.   // if (MyWiFiConfig.CapPortal) {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   // if (MyWiFiConfig.CapPortal) {server.on ("/ fwlink", handleRoot); } // portal cautivo de Microsoft. Quizás no sea necesario. Puede ser manejado por el controlador notFound.   servidor.en("/ generate_204", manejarRoot);  // Portal cautivo de Android. Quizás no sea necesario. Puede ser manejado por el controlador notFound.   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   servidor.en("/ fwlink", manejarRoot);   // 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 InitalizeFileSystem() {   bool initok = falso;   initok = SPIFFS.empezar();   retrasar(200);   Si (!(initok))   {     De serie.println(F("Formatear SPIFFS"));     SPIFFS.formato();     initok = SPIFFS.empezar();   }   regreso initok;
}

booleano CreateWifiSoftAP() 
{   Wifi.desconectar();   De serie.impresión(F("Inicializar SoftAP"));   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(2000); // Sin demora he visto la dirección IP en blanco   Wifi.softAPConfig(apIP, apIP, netMsk);   Si (SoftAccOK)   {   / * Configurar el servidor DNS redirigiendo todos los dominios a la apIP * /     servidor DNS.setErrorReplyCode(DNSReplyCode::No hay error);   servidor DNS.comienzo(DNS_PORT, "*", apIP);   De serie.println(F("exitoso."));   // Serial.setDebugOutput (true); // Salida de depuración para WLAN en la interfaz en serie.   } más   {   De serie.println(F("Error de AP suave".));   De serie.println(MyWiFiConfig.APSTAName);   De serie.println(MyWiFiConfig.WiFiPwd);   }   regreso SoftAccOK;
}


byte ConnectWifiAP() 
{   De serie.println(F("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.   retrasar(500);     Wifi.empezar(MyWiFiConfig.APSTAName, MyWiFiConfig.WiFiPwd);   connRes  = Wifi.waitForConnectResult();   mientras (( connRes == 0 ) y (yo != 10))  // if connRes == 0 "IDLE_STATUS - cambiar Statius"     {        connRes  = Wifi.waitForConnectResult();       retrasar(2000);       yo++;       De serie.impresión(F("."));       // declaración (s)     }   mientras (( connRes == 1 ) y (yo != 10))  // if connRes == 1 NO_SSID_AVAILin - SSID no puede ser alcanzado     {        connRes  = Wifi.waitForConnectResult();       retrasar(2000);       yo++;       De serie.impresión(F("."));       // declaración (s)     }     Si (connRes == 3 ) {                          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(F("Error: MDNS"));                                 } más { MDNS.addService("http", "tcp", 80); }                      }   mientras (( connRes == 4 ) y (yo != 10))  // if connRes == 4 Contraseña incorrecta. A veces sucede esto con la PCD correcta     {        Wifi.empezar(MyWiFiConfig.APSTAName, MyWiFiConfig.WiFiPwd);        connRes = Wifi.waitForConnectResult();       retrasar(3000);       yo++;       De serie.impresión(F("."));                      }   Si (connRes == 4 ) {                           De serie.println(F("STA Pwd Err"));                                              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);
De serie.println("");
regreso connRes;
}


#definir SD_BUFFER_PIXELS 20


vacío handleFileUpload() {                                  // Dateien vom Rechnenknecht oder Klingelkasten ins SPIFFS schreiben    Si (servidor.uri() != "/subir") regreso;    HTTPUpload& subir = servidor.subir();    Si (subir.estado == UPLOAD_FILE_START) {      Cuerda nombre del archivo = subir.nombre del archivo;      Si (subir.nombre del archivo.longitud() > 30) {       subir.nombre del archivo = subir.nombre del archivo.subcadena(subir.nombre del archivo.longitud() - 30, subir.nombre del archivo.longitud());  // Dateinamen auf 30 Zeichen kürzen     }      De serie.println("Nombre de FileUpload:" + subir.nombre del archivo);        Si (!nombre del archivo.comienza con("/")) nombre del archivo = "/" + nombre del archivo;      // fsUploadFile = SPIFFS.open (nombre de archivo, "w");       fsUploadFile = SPIFFS.abierto("/" + servidor.urlDecode(subir.nombre del archivo), "w");      nombre del archivo = Cuerda();    } más Si (subir.estado == UPLOAD_FILE_WRITE) {    // Serial.print ("handleFileUpload Data:"); Serial.println (upload.currentSize);      Si (fsUploadFile)        fsUploadFile.escribir(subir.buf, subir.tamaño actual);    } más Si (subir.estado == UPLOAD_FILE_END) {      Si (fsUploadFile)        fsUploadFile.cerca();      // Serial.print ("handleFileUpload Size:"); Serial.println (upload.totalSize);    server.sendContent(Header);      handleDisplayFS();    }
 }



Vacío handleDisplayFS() {                     Sistema de archivos HTML   Página: /filesystem   Temp ="";   Encabezado HTML     Servidor.sendHeader("Control de caché", "no-cache, no-store, must-revalidate");   Servidor.sendHeader("Pragma", "Sin caché");   Servidor.sendHeader("Caduca", "-1");   Servidor.setContentLength(CONTENT_LENGTH_UNKNOWN);   Contenido HTML   Servidor.Enviar ( 200, "texto/html", Temp );    Temp += "<! DOCTYPE HTML><html lang-'de'><head><meta charset''UTF-8'><meta name'contenido de la ventana gráfica''width'device-width, escala inicial>'>";   Servidor.sendContent(Temp);   Temp = "";   Temp += "<tipo de estilo'texto/css'><!-- DIV.container á min-height: 10em; pantalla: celda de tabla; vertical-align: medio .button á height:35px; width:90px; font-size:16px-";   Servidor.sendContent(Temp);   Temp = "";   Temp += "cuerpo -color de fondo: powderblue; </style><head><title>File System Manager</title></head>";   Temp += "<h2>Sistema de archivos Flash de interfaz periférica serial</h2><cuerpo><izquierda>";   Servidor.sendContent(Temp);   Temp = "";   Si (Servidor.Args() > 0) Parámetro wurden ubergeben     {       Si (Servidor.hasArg("eliminar"))           {               Cadena Ftodel = Servidor.Arg("eliminar");           Si (SPIFFS.Existe(Ftodel))               {               SPIFFS.eliminar(Ftodel);                 Temp += "Archivo" + Ftodel + " eliminado correctamente.";             } Más             {               Temp += "Archivo" + Ftodel + " no se puede eliminar.";             }           Servidor.sendContent(Temp);           Temp = "";         }       Si (Servidor.hasArg("formato") Y Servidor.Arg("en"))           {              SPIFFS.Formato();            Temp += "Sistema de archivos SPI formateado correctamente.";            Servidor.sendContent(Temp);            Temp = "";         } server.client().stop(); Stop es necesario porque no enviamos ninguna longitud de contenido        }     Temp += "<borde de la tabla 2 bgcolor - anchura blanca á 400 ><td><h4>Estado actual de SPIFFS: </h4>";     Temp += formatBytes(SPIFFS.usedBytes() * 1.05) + " de " + formatBytes(SPIFFS.totalBytes()) + " utilizado. <br>";   Temp += formatBytes((SPIFFS.totalBytes() - (SPIFFS.usedBytes() * 1.05)))+ " gratis. <br>";   Temp += "</td></table><br>";   Servidor.sendContent(Temp);   Temp = "";   Compruebe los parámetros del sitio    Temp += "<borde de la tabla 2 bgcolor - anchura blanca á 400><tr><th><br>";   Temp += "<h4>Archivos disponibles en SPIFFS:</h4><frontera de tabla-2 bgcolor -blanco ></tr></th><td>Nombre de archivo</td><td>Tamaño</td><td>Acción </td></tr></th>";   Servidor.sendContent(Temp);   Temp = "";   Archivo Raíz = SPIFFS.Abierto("/");   Archivo Archivo = Raíz.openNextFile();    Mientras (Archivo)   {      Temp += "<td> <a title-"Descargar" href"" + Cadena(Archivo.Nombre()) + "Descarga de " + Cadena(Archivo.Nombre()) + "\">" + Cadena(Archivo.Nombre()) + "</a> <br></th>";      Temp += "<td>"+ formatBytes(Archivo.Tamaño())+ "</td>";      Temp += "<td><a href ?filesystem?delete? + Cadena(Archivo.Nombre()) + "> Eliminar </a></td>";      Temp += "</tr></th>";         Archivo = Raíz.openNextFile();    }   Temp += "</tr></th>";   Temp += "</td></tr></th><br></th></tr></table></table><br>";   Temp += "<borde de la tabla 2 bgcolor - anchura blanca á 400 ><td><h4>Upload</h4>";     Temp += "<etiqueta> Elegir archivo: </etiqueta>";   Temp += "<método de formulario 'POST' acción '/upload' enctype ''multipart/form-data' style''height:35px;' ><tipo de entrada''nombre'archivo''subir' estilo'altura:35px; Tamaño de fuente:13px;' requerido> ?;   Temp += " </table><br>";   Servidor.sendContent(Temp);   Temp = "";   Temp += "<td><a href ?filesystem?format-on> Formatear el sistema de archivos SPIFFS. (Toma hasta 30 segundos) </a></td>";   Temp += "<frontera de la tabla-2 bgcolor -anchura blanca- 500 cellpadding n.o 5 ><subtitulado><p><h3>Enlaces del sistema:</h2></p></caption><tr><th><br>";   Temp += " <a href''/'>Página principal</a><br><br></th></tr></table><br><br>";   Servidor.sendContent(Temp);   Temp = "";   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></footer></body></html>";     server.send ( 200, "", temp );   Servidor.sendContent(Temp);   Servidor.Cliente().Parada(); Stop es necesario porque no enviamos ninguna longitud de contenido   Temp = "";
 }

/** Cargar credenciales WLAN de EEPROM */

Bool loadCredentials() 
{
 Bool RetValue;
 Eeprom.Comenzar(512);
 Eeprom.Obtener(0, MyWiFiConfig);
 Eeprom.Final();
 Si (Cadena(MyWiFiConfig.ConfigValid) = Cadena("Tk"))    {     RetValue = Verdad;   } Más   {     RetValue = Falso; Configuración WLAN no encontrada.   }   devolución RetValue;
}


/** Almacene las credenciales WLAN en EEPROM */

Bool saveCredentials() 
{
Bool RetValue;
Comprobar errores lógicos
RetValue = Verdad;
Si  (MyWiFiConfig.APSTA == Verdad ) Modo AP   {    Si (MyWiFiConfig.PwDReq Y (Sizeof(Cadena(MyWiFiConfig.WiFiPwd)) < 8))     {           RetValue = Falso;  Config no válido     }    Si (Sizeof(Cadena(MyWiFiConfig.APSTAName)) < 1)     {       RetValue = Falso;  Config no válido     }   } 
Si (RetValue)   {   Eeprom.Comenzar(512);   Para (Int  = 0 ;  < Sizeof(MyWiFiConfig) ; ++)       {       Eeprom.Escribir(, 0);      }   strncpy( MyWiFiConfig.ConfigValid , "Tk", Sizeof(MyWiFiConfig.ConfigValid) );   Eeprom.Poner(0, MyWiFiConfig);   Eeprom.Cometer();   Eeprom.Final();   }   devolución RetValue;
}


Vacío SetDefaultWiFiConfig()
{    Byte Len;    MyWiFiConfig.APSTA = Verdad;    MyWiFiConfig.PwDReq = Verdad;  PW por defecto requerido    MyWiFiConfig.CapPortal = Verdad;    strncpy( MyWiFiConfig.APSTAName, "ESP_Config", Sizeof(MyWiFiConfig.APSTAName) );    Len = Strlen(MyWiFiConfig.APSTAName);    MyWiFiConfig.APSTAName[Len+1] = '\0';       strncpy( MyWiFiConfig.WiFiPwd, "12345678", Sizeof(MyWiFiConfig.WiFiPwd) );    Len = Strlen(MyWiFiConfig.WiFiPwd);    MyWiFiConfig.WiFiPwd[Len+1] = '\0';      strncpy( MyWiFiConfig.ConfigValid, "Tk", Sizeof(MyWiFiConfig.ConfigValid) );    Len = Strlen(MyWiFiConfig.ConfigValid);    MyWiFiConfig.ConfigValid[Len+1] = '\0';     Serial.println(F("Restablecer credenciales WiFi.")); 
}



Vacío handleRoot() {
Página principal:
 Temp = "";
 Byte PicCount = 0;
 Byte ServArgs = 0;   Encabezado HTML   Servidor.sendHeader("Control de caché", "no-cache, no-store, must-revalidate");   Servidor.sendHeader("Pragma", "Sin caché");   Servidor.sendHeader("Caduca", "-1");   Servidor.setContentLength(CONTENT_LENGTH_UNKNOWN);
Contenido HTML   Servidor.Enviar ( 200, "texto/html", Temp );   Speichersparen - Schon mal dem Cleint senden   Temp = "";   Temp += "<! DOCTYPE HTML><html lang-'de'><head><meta charset''UTF-8'><meta name'contenido de la ventana gráfica''width'device-width, escala inicial>'>";   Servidor.sendContent(Temp);   Temp = "";   Temp += "<tipo de estilo'texto/css'><!-- DIV.container á min-height: 10em; pantalla: celda de tabla; vertical-align: medio .button á height:35px; width:90px; font-size:16px-";   Servidor.sendContent(Temp);   Temp = "";   Temp += "cuerpo -color de fondo: powderblue; </estilo>";   Temp += "<head><title>Hauptseite</title></head>";   Temp += "<h2>Hauptseite</h2>";   Temp += "<cuerpo>";   Servidor.sendContent(Temp);   Temp = ""; 
Procesamiento de solicitud de usuario   Temp = "";    Temp += "<frontera de la tabla 2 bgcolor - anchura blanca - 500 relleno de celda s 5 ><subtitulado><p><h3>Enlaces del sistema:</h2></p></caption>";   Temp += "<tr><th><br>";   Temp += "<a href''/wifi'>WIFI Einstellungen</a><br><br>";   Temp += "<a href'/filesystem'>Filemanager</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></footer>";   Temp += "</body></html>";   Servidor.sendContent(Temp);   Temp = "";   Servidor.Cliente().Parada(); Stop es necesario porque no enviamos ninguna longitud de contenido
}



Vacío handleNotFound() {      Si (cautivoPortal())        { Si el portal caprichoso redirigir en lugar de mostrar la página de error.         devolución;       }     Si (!handleFileRead(Servidor.Uri()))      {     Temp = "";      Encabezado HTML     Servidor.sendHeader("Control de caché", "no-cache, no-store, must-revalidate");     Servidor.sendHeader("Pragma", "Sin caché");     Servidor.sendHeader("Caduca", "-1");     Servidor.setContentLength(CONTENT_LENGTH_UNKNOWN);     Contenido HTML     Temp += "<! DOCTYPE HTML><html lang-'de'><head><meta charset''UTF-8'><meta name'contenido de la ventana gráfica''width'device-width, escala inicial>'>";     Temp += "<tipo de estilo'texto/css'><!-- DIV.container á min-height: 10em; pantalla: celda de tabla; vertical-align: medio .button á height:35px; width:90px; font-size:16px-";     Temp += "cuerpo -color de fondo: powderblue; </estilo>";     Temp += "<head><title>Archivo no encontrado</title></head>";     Temp += "<h2> 404 Archivo no encontrado</h2><br>";     Temp += "<h4>Información de depuración:</h4><br>";     Temp += "<cuerpo>";     Temp += "URI: ";     Temp += Servidor.Uri();     Temp += "-nMétodo: ";     Temp+= ( Servidor.Método() == HTTP_GET ) ? "Get" : "POST";     Temp += "<br>Argumentos: ";     Temp += Servidor.Args();     Temp += "N";       Para ( uint8_t  = 0;  < Servidor.Args(); ++ ) {         Temp += " " + Servidor.argName (  ) + ": " + Servidor.Arg (  ) + "N";         }     Temp += "<br>Server Hostheader: "+ Servidor.hostHeader();     Para ( uint8_t  = 0;  < Servidor.Encabezados(); ++ ) {         Temp += " " + Servidor.headerName (  ) + ": " + Servidor.Rúbrica (  ) + "<br>";         }       Temp += "</table></form><br><br><table border-2 bgcolor - blanco width á 500 cellpadding ?5 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> lt;caption><p><h2>Es posible que desee buscar:</h2></p></caption>";     Temp += "<tr><th>";     Temp += "<a href'/'>Página principal</a><br>";     Temp += "<a href''/wifi'>Configuración de WIFI</a><br>";     Temp += "<a href'/filesystem'>Filemanager</a><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></footer>";     Temp += "</body></html>";     Servidor.Enviar ( 404, "", Temp );     Servidor.Cliente().Parada(); Stop es necesario porque no enviamos ninguna longitud de contenido     Temp = "";     }
}




/** Redirija al portal cautivo si recibimos una solicitud para otro dominio. Devuelve true en ese caso para que el controlador de página no intente controlar la solicitud de nuevo. */
Booleana cautivoPortal() {   Si (!Sipi(Servidor.hostHeader()) && Servidor.hostHeader() != (Cadena(ESPHostname)+".local")) {     Serial.println("Solicitud redirigida al portal cautivo");       Servidor.sendHeader("Ubicación", Cadena("http://") + toStringIp(Servidor.Cliente().localIP()), Verdad);     Servidor.Enviar ( 302, "Texto/sin formato", ""); El contenido vacío inhibe el encabezado content-length, por lo que tenemos que cerrar el socket nosotros mismos.     Servidor.Cliente().Parada(); Stop es necesario porque no enviamos ninguna longitud de contenido     devolución Verdad;   }   devolución Falso;
}
 


/** Controlador de página de configuración Wifi */
Vacío handleWifi() 
 {   Página: /wifi   Byte ;   Byte Len ;   Temp = "";   Compruebe los parámetros del sitio         Si (Servidor.hasArg("Reiniciar") )  Sistema de reinicio         {          Temp = "Reiniciar el sistema en 5 segundos..";          Servidor.Enviar ( 200, "texto/html", Temp );          Retraso(5000);          Servidor.Cliente().Parada();                Wifi.Desconecte();          Retraso(1000);              }       Si (Servidor.hasArg("WiFiMode") Y (Servidor.Arg("WiFiMode") == "1")  )  Modo estación STA Conéctese a otra estación WIFI          {         startMillis = Millis(); Restablecer contador de tiempo para evitar el funcionamiento del modo inactivo         Conéctese a STATION existente         Si ( Sizeof(Servidor.Arg("WiFi_Network")) > 0  )           {             Serial.println("Modo STA");             MyWiFiConfig.APSTA = Falso; Punto de acceso o modo de estación - modo de estación falso             Temp = "";                       Para (  = 0;  < APSTANameLen;++) { MyWiFiConfig.APSTAName[] =  0; }             Temp = Servidor.Arg("WiFi_Network");             Len =  Temp.Longitud();             Para (  = 0;  < Len;++)              {                    MyWiFiConfig.APSTAName[] =  Temp[];                           }             Temp = "";             Para (  = 0;  < WiFiPwdLen;++)  { MyWiFiConfig.WiFiPwd[] =  0; }                       Temp = Servidor.Arg("STAWLanPW");             Len =  Temp.Longitud();                                  Para (  = 0;  < Len;++)                 {                  Si (Temp[] > 32) Steuerzeichen raus                   {                    MyWiFiConfig.WiFiPwd[] =  Temp[];                     }                 }             Temp = "WiFi Connect to AP: -";              Temp += MyWiFiConfig.APSTAName;             Temp += "-<br>WiFi PW: -";              Temp += MyWiFiConfig.WiFiPwd;             Temp += "-<br>";                       Temp += "Conectarse al modo STA en 2 segundos. <br>";             Servidor.Enviar ( 200, "texto/html", Temp );              Servidor.sendContent(Temp);             Retraso(2000);             Servidor.Cliente().Parada();              Servidor.Parada();             Temp = "";             Wifi.Desconecte();             Wifi.softAPdisconnect(Verdad);             Retraso(500);            ConnectWifiAP            Bool SaveOk = saveCredentials();                        = ConnectWifiAP();             Retraso(700);             Si ( != 3) 4: WL_CONNECT_FAILED - La contraseña es incorrecta 1: WL_NO_SSID_AVAILin - El SSID configurado no se puede alcanzar               {                  Serial.Impresión(F("No se puede conectar a la red especificada. Razón: "));                  Serial.println();                  Servidor.Cliente().Parada();                  Retraso(100);                               Wifi.setAutoReconnect (Falso);                  Retraso(100);                       Wifi.Desconecte();                               Retraso(1000);                  SetDefaultWiFiConfig();                  CreateWifiSoftAP();                  devolución;                } Más               {                  Configuración segura                  Bool SaveOk = saveCredentials();                  InitalizeHTTPServer();                  devolución;               }           }        }                 Si (Servidor.hasArg("WiFiMode") Y (Servidor.Arg("WiFiMode") == "2")  )  Cambiar el modo AP         {         startMillis = Millis(); Restablecer contador de tiempo para evitar el funcionamiento del modo inactivo         Configurar punto de acceso         Temp = Servidor.Arg("APPointName");               Len =  Temp.Longitud();         Temp =Servidor.Arg("APPW");         Si (Servidor.hasArg("PasswordReq"))             {                      =  Temp.Longitud();             } Más {  = 8; }                  Si (  ( Len > 1 ) Y (Servidor.Arg("APPW") == Servidor.Arg("APPWRepeat")) Y (  > 7)          )           {             Temp = "";             Serial.println(F("APMode"));             MyWiFiConfig.APSTA = Verdad; Punto de acceso o modo de sación - modo AP verdadero                                     Si (Servidor.hasArg("CaptivePortal"))             {               MyWiFiConfig.CapPortal = Verdad ; CaptivePortal encendido en el modo AP             } Más { MyWiFiConfig.CapPortal = Falso ; }                          Si (Servidor.hasArg("PasswordReq"))             {               MyWiFiConfig.PwDReq = Verdad ; Contraseña requerida en el modo AP             } Más { MyWiFiConfig.PwDReq = Falso ; }             Para (  = 0;  < APSTANameLen;++) { MyWiFiConfig.APSTAName[] =  0; }             Temp = Servidor.Arg("APPointName");             Len =  Temp.Longitud();             Para (  = 0;  < Len;++) { MyWiFiConfig.APSTAName[] =  Temp[]; }             MyWiFiConfig.APSTAName[Len+1] = '\0';               Temp = "";             Para (  = 0;  < WiFiPwdLen;++)  {  MyWiFiConfig.WiFiPwd[] =  0; }                       Temp = Servidor.Arg("APPW");             Len =  Temp.Longitud();                                  Para (  = 0;  < Len;++)  { MyWiFiConfig.WiFiPwd[] =  Temp[];  }             MyWiFiConfig.WiFiPwd[Len+1] = '\0';               Temp = "";                      Si (saveCredentials()) Guardar AP ConfigCongfig                 {                         Temp = "Daten des AP Modes erfolgreich gespeichert. Reinicie notwendig.";               } Más  { Temp = "Daten des AP Modes fehlerhaft.";  }           } Más Si (Servidor.Arg("APPW") != Servidor.Arg("APPWRepeat"))                 {                   Temp = "";                   Temp = "WLAN Passwort nicht gleich. Abgebrochen.";                 } Más                 {                               Temp = "";                   Temp = "WLAN Passwort oder AP Nombre zu kurz. Abgebrochen.";                 }                                        }      Encabezado HTML   Servidor.sendHeader("Control de caché", "no-cache, no-store, must-revalidate");   Servidor.sendHeader("Pragma", "Sin caché");   Servidor.sendHeader("Caduca", "-1");   Servidor.setContentLength(CONTENT_LENGTH_UNKNOWN);
Contenido HTML   Temp += "<! DOCTYPE HTML><html lang-'de'><head><meta charset''UTF-8'><meta name'contenido de la ventana gráfica''width'device-width, escala inicial>'>";   Servidor.Enviar ( 200, "texto/html", Temp );    Temp = "";    Temp += "<tipo de estilo'texto/css'><!-- DIV.container á min-height: 10em; pantalla: celda de tabla; vertical-align: medio .button á height:35px; width:90px; font-size:16px-";   Temp += "cuerpo -color de fondo: powderblue; </style><head><title>Smartes Tuerschild - WiFi Settings</title></head>";   Servidor.sendContent(Temp);   Temp = "";   Temp += "<h2>WiFi Einstellungen</h2><body><left>";   Temp += "<borde de la tabla 2 bgcolor - anchura blanca 500 ><td><h4>Configuración actual de WiFi: </h4>";   Si (Servidor.Cliente().localIP() == apIP) {      Temp += "Modo : Punto de Acceso Suave (AP)<br>";      Temp += "SSID : " + Cadena (MyWiFiConfig.APSTAName) + "<br><br>";   } Más {      Temp += "Modo : Estación (STA) <br>";      Temp += "SSID : "+ Cadena (MyWiFiConfig.APSTAName) + "<br>";      Temp += "BSSID : " + Wifi.BSSIDstr()+ "<br><br>";   }   Temp += "</td></table><br>";   Servidor.sendContent(Temp);   Temp = "";   Temp += "<forma acción '/wifi' método ''post'>";   Temp += "<borde de la tabla 2 bgcolor - anchura blanca á 500><tr><th><br>";   Si (MyWiFiConfig.APSTA == 1)     {       Temp += "<tipo de entrada 'radio' valor ''1' nombre ''WiFiMode' > Modo de estación WiFi<br>";     } Más     {       Temp += "<tipo de entrada 'radio' valor ''1' nombre 'WiFiMode' marcado > Modo de estación WiFi<br>";     }   Temp += "Redes WiFi disponibles:<frontera de tabla-2 bgcolor - blanco ></tr></th><td>Número </td><td>SSID </td><td>Cifrado </td><td>Fuerza WiFi </td>";   Servidor.sendContent(Temp);   Temp = "";   Wifi.scanDelete();   Int N = Wifi.scanNetworks(Falso, Falso); WiFi.scanNetworks(async, show_hidden)   Si (N > 0) {     Para (Int  = 0;  < N; ++) {     Temp += "</tr></th>";     Cadena Nrb = Cadena();     Temp += "<td>" + Nrb + "</td>";     Temp += "<td>" + Wifi.Ssid() +"</td>";         Nrb = GetEncryptionType(Wifi.encryptionType());     Temp += "<td>"+ Nrb + "</td>";     Temp += "<td>" + Cadena(Wifi.Rssi()) + "</td>";        }   } Más {     Temp += "</tr></th>";     Temp += "<td>1 </td>";     Temp += "<td>No se ha encontrado ninguna RED inalámbrica (WLAN)</td>";     Temp += "<td> --- </td>";     Temp += "<td> --- </td>";   }   Temp += "</table><table border-2 bgcolor á blanco ></tr></th><td>Connect to WiFi SSID: </td><td><select name>'WiFi_Network' >";
Si (N > 0) {     Para (Int  = 0;  < N; ++) {     Temp += "<valor de opción'" + Wifi.Ssid() +"'>" + Wifi.Ssid() +"</opción>";           }   } Más {     Temp += "<valor de opción''No_WiFi_Network'>No se ha encontrado WiFiNetwork !/option>";   }   Servidor.sendContent(Temp);   Temp = "";   Temp += "</select></td></tr></th></tr></th><td>WiFi Password: </td><td>";   Temp += "<tipo de entrada 'nombre de texto' nombre 'STAWLanPW' maxlength '40' tamaño ''40'>";    Temp += "</td></tr></th><br></th></tr></table></table><table border-2 bgcolor á anchura blanca á 500 ><tr><th>>"&;   Servidor.sendContent(Temp);   Temp = "";   Si (MyWiFiConfig.APSTA == Verdad)     {       Temp += "<tipo de entrada 'nombre de radio' valor ''2' marcado> Modo de punto de acceso WiFi <br>";     } Más     {       Temp += "<tipo de entrada 'nombre de radio' valor ''2' > Modo de punto de acceso WiFi <br>";     }   Temp += "<frontera de la tabla 2 bgcolor á blanco ></tr></th> <td>Nombre del punto de acceso WiFi: </td><td>";     Servidor.sendContent(Temp);   Temp = "";               Si (MyWiFiConfig.APSTA == Verdad)     {       Temp += "<tipo de entrada 'nombre de texto' nombre 'APPointName' maxlength '"+Cadena(APSTANameLen-1)+"' tamaño '30' valor '" + Cadena(MyWiFiConfig.APSTAName) + "'></td>";     } Más     {       Temp += "<tipo de entrada 'nombre de texto' nombre 'APPointName' maxlength '"+Cadena(APSTANameLen-1)+"' tamaño '30' ></td>";     }   Servidor.sendContent(Temp);   Temp = "";          Si (MyWiFiConfig.APSTA == Verdad)     {       Temp += "</tr></th><td>Contraseña WiFi: </td><td>";       Temp += "<tipo de entrada 'contraseña' nombre ''APPW' maxlength'"+Cadena(WiFiPwdLen-1)+"' tamaño '30' valor '" + Cadena(MyWiFiConfig.WiFiPwd) + "'> </td>";       Temp += "</tr></th><td>Repetir contraseña WiFi: </td>";       Temp += "<td><tipo de entrada''contraseña' nombre ''APPWRepeat' maxlength'"+Cadena(WiFiPwdLen-1)+"' tamaño '30' valor '" + Cadena(MyWiFiConfig.WiFiPwd) + "'> </td>";     } Más     {       Temp += "</tr></th><td>Contraseña WiFi: </td><td>";       Temp += "<tipo de entrada 'contraseña' nombre ''APPW' maxlength'"+Cadena(WiFiPwdLen-1)+"' tamaño '30'> </td>";       Temp += "</tr></th><td>Repetir contraseña WiFi: </td>";       Temp += "<td><tipo de entrada''contraseña' nombre ''APPWRepeat' maxlength'"+Cadena(WiFiPwdLen-1)+"' tamaño '30'> </td>";     }       Temp += "</tabla>";   Servidor.sendContent(Temp);   Temp = "";         Si (MyWiFiConfig.PwDReq)     {       Temp += "<tipo de entrada 'checkbox' name''PasswordReq' activado> Contraseña para el inicio de sesión requerido. ";      } Más     {       Temp += "<tipo de entrada 'checkbox' name''PasswordReq' > Contraseña para el inicio de sesión requerido. ";      }   Servidor.sendContent(Temp);   Temp = "";     Si (MyWiFiConfig.CapPortal)     {       Temp += "<tipo de entrada 'checkbox' name''CaptivePortal' marcado> Activar portal cautivo";      } Más     {       Temp += "<tipo de entrada 'checkbox' name''CaptivePortal' > Activar portal cautivo";      }   Servidor.sendContent(Temp);   Temp = "";     Temp += "<br></tr></th></table><br> <button type>'submit' name''Settings' value''1' style''height: 50px; ancho: 140px' autofocus>Establecer ajustes WiFi</button>";   Temp += "<tipo de botón 'Enviar' nombre ''Reboot' valor ''1' estilo 'altura: 50px; ancho: 200px' >Reiniciar sistema</botón>";   Servidor.sendContent(Temp);   Temp = "";   Temp += "<tipo de botón 'reset' name ''acción' valor ''1' estilo 'altura: 50px; ancho: 100px' >Reset</button></form>";   Temp += "<frontera de la tabla-2 bgcolor -anchura blanca- 500 cellpadding n.o 5 ><subtitulado><p><h3>Enlaces del sistema:</h2></p></caption><tr><th><br>";   Servidor.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><</footer>";   Temp += "</body></html>";     Servidor.sendContent(Temp);   Servidor.Cliente().Parada(); Stop es necesario porque no enviamos ninguna longitud de contenido   Temp = "";
}


Vacío handleUploadSave() 
{   Cadena FileData ;     Temp = "";   server.send(200);   Serial.println("FileUpload");   Serial.println(server.args());               Para (Byte  = 0;  < Servidor.Args(); ++)    {     Temp += "Arg" + (Cadena) + " –> ";   Incluir el valor de iteración actual     Temp += Servidor.argName() + ": ";     Obtener el nombre del parámetro     Temp += Servidor.Arg() + "N";              Obtener el valor del parámetro   }    server.send(200, "text/plain", temp);       Respuesta a la solicitud HTTP   FileData = Servidor.Arg("Fecha");    Servidor.sendHeader("Ubicación", "sistema de archivos", Verdad);   Servidor.sendHeader("Control de caché", "no-cache, no-store, must-revalidate");   Servidor.sendHeader("Pragma", "Sin caché");   Servidor.sendHeader("Caduca", "-1");   Servidor.Enviar ( 302, "Texto/sin formato", "");  El contenido vacío inhibe el encabezado content-length, por lo que tenemos que cerrar el socket nosotros mismos.   Servidor.Cliente().Parada(); Stop es necesario porque no enviamos ninguna longitud de contenido  
}


/** ¿Es esto una IP? */
Booleana Sipi(Cadena Str) {   Para (Int  = 0;  < Str.Longitud(); ++) {     Int C = Str.charAt();     Si (C != '.' && (C < '0' || C > '9')) {       devolución Falso;     }   }   devolución Verdad;
}

Cadena GetEncryptionType(Byte thisType) {   Cadena Salida = "";    leer el tipo de cifrado e imprimir el nombre:    Interruptor (thisType) {      Caso 5:        Salida = "WEP";        devolución Salida;        Romper;      Caso 2:        Salida = "WPA";        devolución Salida;        Romper;      Caso 4:        Salida = "WPA2";        devolución Salida;        Romper;      Caso 7:        Salida = "Ninguno";        devolución Salida;        Romper;      Caso 8:        Salida = "Automático";        devolución Salida;       Romper;    }
}

/** ¿IP a cadena? */
Cadena toStringIp(Ipaddress Ip) {   Cadena res = "";   Para (Int  = 0;  < 3; ++) {     res += Cadena((Ip >> (8 * )) & 0xFF) + ".";   }   res += Cadena(((Ip >> 8 * 3)) & 0xFF);   devolución res;
}

Cadena formatBytes(Size_t Bytes) {            lesbare Anzeige der Speichergr-en    Si (Bytes < 1024) {      devolución Cadena(Bytes) + "Byte";    } Más Si (Bytes < (1024 * 1024)) {      devolución Cadena(Bytes / 1024.0) + " KB";    } Más Si (Bytes < (1024 * 1024 * 1024)) {      devolución Cadena(Bytes / 1024.0 / 1024.0) + "MB";    }
 }

Cadena getContentType(Cadena Nombre) { convertir la extensión de archivo al tipo MIME   Si (Nombre.endsWith(".htm")) devolución "texto/html";   Más Si (Nombre.endsWith(".css")) devolución "text/css";   Más Si (Nombre.endsWith(".js")) devolución "aplicación/javascript";   Más Si (Nombre.endsWith(".ico")) devolución "imagen/x-icono";   Más Si (Nombre.endsWith(".gz")) devolución "aplicación/x-gzip";   Más Si (Nombre.endsWith(".bmp")) devolución "imagen/bmp";   Más Si (Nombre.endsWith(".tif")) devolución "imagen/tiff";   Más Si (Nombre.endsWith(".pbm")) devolución "imagen/x-portátil-mapa de bits";   Más Si (Nombre.endsWith(".jpg")) devolución "imagen/jpeg";   Más Si (Nombre.endsWith(".gif")) devolución "imagen/gif";   Más Si (Nombre.endsWith(".png")) devolución "imagen/png";   Más Si (Nombre.endsWith(".svg")) devolución "image/svg+xml";   Más Si (Nombre.endsWith(".html")) devolución "texto/html";   Más Si (Nombre.endsWith(".wav")) devolución "audio/x-wav";   Más Si (Nombre.endsWith(".zip")) devolución "aplicación/zip";   Más Si (Nombre.endsWith(".rgb")) devolución "imagen/x-rg";
 Lista completa en https://wiki.selfhtml.org/wiki/MIME-Type/Ibersicht   devolución "Texto/sin formato";
}

Bool handleFileRead(Cadena Camino) { enviar el archivo correcto al cliente (si existe)
Serial.println("handleFileRead: " + path);   Si (Camino.endsWith("/")) Camino += "index.html";          Si se solicita una carpeta, envíe el archivo de índice   Cadena Contenttype = getContentType(Camino);             Obtener el tipo MIME   Cadena pathWithGz = Camino + ".gz";   Si (SPIFFS.Existe(pathWithGz) || SPIFFS.Existe(Camino)) { Si el archivo existe, ya sea como un archivo comprimido o normal     Si (SPIFFS.Existe(pathWithGz))                         Si hay una versión comprimida disponible       Camino += ".gz";                                         Utilice el verion comprimido     Archivo Archivo = SPIFFS.Abierto(Camino, "R");                    Abra el archivo     Size_t Enviado = Servidor.streamFile(Archivo, Contenttype);    Envíalo al cliente     Archivo.Cerca();                                          Cierre el archivo de nuevo     devolución Verdad;   }   devolución Falso;
}

Vacío Bucle() 
 {     Si (SoftAccOK)   {     dnsServer.processNextRequest(); Dns   }   HTTP   Servidor.handleClient();     }

]

 

Le deseo un montón de diversión con el servidor de archivos en el ESP32. En la siguiente parte veremos cómo generar imágenes BMP almacenadas en el servidor de archivos en pantallas LED Matrix.

¡Hasta la próxima!

Esp-8266Projekte für fortgeschrittene

5 comentarios

Eberhard

Eberhard

Hallo
heute war ich auf das Captive portal für den ESP8266 gestoßen. Gleich gemacht – und es funktioniert prächtig. Danke für diese Anweisungen.
Nun will ich auch nen Fileserver auf den EWP8266 installieren – das geht aber leider nicht mit dieser Anweisung hier.
Frage: wie kann ich zum Captive portal auf dem ESP8266 einen Fileserver installieren?
Danke im Voraus
Hardy

Tobias

Tobias

Hallo Sven,
Tausche bitte die Zeile
if (String(MyWiFiConfig.ConfigValid) = String(“TK”)) durch if (String(MyWiFiConfig.ConfigValid) == String(“TK”)) aus. Dann sollte es funktionieren. Leider konnte ich den Fehler erst in Teil 4 der Reihe korrigieren..
Gruß

Peter Pitzeier

Peter Pitzeier

Die consts

static const byte WiFiPwdLen = 25;
static const byte APSTANameLen = 20;

sind u.U. nicht ausreichend. Ein WiFi password darf bis zu 63, der Name eines APs max. 32 Zeichen lang sein.

Sven

Sven

Also, kompilieren hat ohne Probleme funktioniert, auch das Hochladen. Aber, der Name ESP32 erscheint auf dem Handy nicht, nur ESP_?? und mit dem Passwort kann man sich nicht verbinden. Habe den Namen geändert, hat aber auch nicht geklappt. Ich finde die Idee sehr gut, nur wie klappt es trotzdem? Ich habe auch schon andere Handys probiert, ohne Erfolg. Wäre dankbar für eine Hilfe.

Peter Pitzeier

Peter Pitzeier

Wie in den Teilen 1 und 2 steht in bool loadCredentials()

if (String(MyWiFiConfig.ConfigValid) = String(“TK”))

Das kann doch wohl nicht richtig sein, oder? Wenn kein Vergleich mittels ‘==’ , sondern eine Zuweisung ‘=’ erfolgt, wird das ‘if’ immer wahr und damit sinnlos sein.

Deja un comentario

Todos los comentarios son moderados antes de ser publicados