Aun sigo sin entender algunos pasos, que probablemente o lo mas seguro es que algo no este haciendo como corresponde.
les dejo el codigo y explico brevemente parte de la logica :
hay dos archivos para guardar credenciales de red, uno para AP y otro para STA. Si estos archivos existen, se pasa lo almacenado a las variables ssid y pswd, segun corresponda.
para el modo STA, inicialmente las const char* ssid y pswd estan vacias, los datos almacenados contienen las credenciales.
La funciona que carga los datos, no veo que tena problemas, la funciona que inicia el modo STA, tampoco veo que tenga mayores problemas.
ahora, al ver esto por el monitor, se puede apreciar que las const char reciben correctamente los datos, estos son presentados en el terminar y finalmente se pasan al begin, pero es ahi donde por algun motivo , la const se comporta extraño y despues al visualizarla nuevamente se ve "distinto" por decir algo.
MONITOR
SPIFFS OK!
Credenciales encontradas [003]:
Modo STA autoseleccionado
Variables desde la funcion setupSTAMode()
SSID WF : MARIA PAZ 2.4
PSWD WF : RM0300CM
[ 13796][E][WiFiSTA.cpp:232] begin(): SSID too long or missing!
Mode: STA
Channel: 1
SSID (0):
Passphrase (0):
BSSID set: 0
Conetando a red wifi ¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥ÍÍ... ..
---- Se cerró el puerto de serie /dev/ttyACM0 ----
main.cpp
#include <Arduino.h>
#include <SPIFFS.h>
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <ArduinoJson.h>
#include "funciones.h"
void setup() {
pinMode(RGB_LED,OUTPUT);
RGBLed(0);
Serial.begin(115200);
delay(5000);
int ntiempo = 0;
while(!SPIFFS.begin(true) && ntiempo < 20){
Serial.print(".");
delay(1000);
ntiempo++;
}
if (!SPIFFS.begin(true)) {
Serial.println("An error has occurred while mounting SPIFFS");
return;
}else{
Serial.println("SPIFFS OK!");
}
loadWiFiCredentials();
if (isAPMode) {
loadAPCredentials();
RGBLed(2);
setupAPMode();
} else {
RGBLed(5);
setupSTAMode();
}
WebServerIni();
// Guardar el tiempo de inicio
startTime = millis();
}
void loop() {
// El bucle principal puede permanecer vacío ya que no hay tareas periódicas necesarias
chkTimeBootAP();
if(Serial.read()=='1'){ESP.restart();};
if(Serial.read()=='8'){DelCredencials(8);};
if(Serial.read()=='9'){DelCredencials(9);};
}
funciones.h
#define RGB_LED 48
bool isAPMode = true;
// Constantes y variables globales
const char* ssidAP = "CAMCARESP32";
const char* passwordAP = "ESP32S3CAM";
const char* ssidSTA = ""; // To be loaded from SPIFFS
const char* passwordSTA = ""; // To be loaded from SPIFFS
unsigned long startTime;
const unsigned long timeout = 120000; // 2 minutos en milisegundos
AsyncWebServer server(80);
String scanNetworks() {
String wifiList = "";
int n = WiFi.scanNetworks();
for (int i = 0; i < n; ++i) {
wifiList += "<button type=\"button\" class=\"list-group-item list-group-item-action\" value=\"" + WiFi.SSID(i) + "\" onclick=\"clickbtn()\">" + WiFi.SSID(i) + " (" + WiFi.RSSI(i) + " dBm)</button>";
}
return wifiList;
}
void RGBLed(int numColor){
/*
0 = Blanco
1 = Rojo
2 = Azul
3 = Verde
4 = Amarillo
*/
int r = 0;
int g = 0;
int b = 0;
switch (numColor){
case 0:
r=255;g=255;b=255;
break;
case 1:
r=255;g=3;b=3;
break;
case 2:
r=0;g=0;b=255;
break;
case 3:
r=0;g=255;b=0;
break;
case 4:
r=200;g=255;b=3;
break;
case 5:
r=240;g=10;b=255;
break;
case 6:
r=10;g=255;b=100;
break;
default:
r=255;g=255;b=255;
break;
}
digitalWrite(RGB_LED,LOW);
neopixelWrite(RGB_LED,r,g,b);
digitalWrite(RGB_LED,HIGH);
}
String insertValues(String html) {
html.replace("{{cpuFreq}}", String(ESP.getCpuFreqMHz()));
html.replace("{{flashSize}}", String(ESP.getFlashChipSize() / (1024 * 1024)));
html.replace("{{ramSize}}", String(ESP.getFreeHeap() / 1024));
html.replace("{{networkMode}}", String(WiFi.getMode() == WIFI_STA ? "WIFI_STA" : "WIFI_AP"));
if(WiFi.getMode() == WIFI_STA){
html.replace("{{ssid}}", String(WiFi.SSID()));
html.replace("{{ipAddress}}", WiFi.localIP().toString());
html.replace("{{subnetMask}}", WiFi.subnetMask().toString());
html.replace("{{gateway}}", WiFi.gatewayIP().toString());
}else{
html.replace("{{ssid}}", String(WiFi.SSID()));
html.replace("{{ipAddress}}", WiFi.softAPIP().toString());
html.replace("{{subnetMask}}", String(WiFi.softAPSubnetCIDR()));
html.replace("{{gateway}}", WiFi.softAPIP().toString());
}
html.replace("{{btStatus}}", "Activo"); // Supongamos que está activo
html.replace("{{btMac}}", "AA:BB:CC:DD:EE:FF"); // Reemplazar con la MAC real si es necesario
html.replace("{{sdkVersion}}", String(ESP.getSdkVersion()));
html.replace("{{uptime}}", String(millis() / (1000 * 60)));
html.replace("{{cpuTemp}}", String(temperatureRead()));
return html;
}
String insertValuesAP(String html) {
html.replace("{{valueSSID}}", String(ssidAP));
html.replace("{{valuePSWD}}", String(passwordAP));
html.replace("{{valueIP}}", String(WiFi.softAPIP().toString()));
return html;
}
void setupAPMode() {
RGBLed(0);
Serial.println("Iniciando modo AP...");
delay(1000);
WiFi.mode(WIFI_AP);
WiFi.setTxPower(WIFI_POWER_8_5dBm);
WiFi.softAP(ssidAP,passwordAP,random(2,13) );
delay(1000);
IPAddress IP = WiFi.softAPIP();
Serial.print("AP IP Address: ");
Serial.println(IP);
Serial.print("SSID AP : ");Serial.println(String(ssidAP));
Serial.print("PSWD AP : ");Serial.println(String(passwordAP));
isAPMode = true;
RGBLed(3);
}
void setupSTAMode() {
Serial.println("Variables desde la funcion setupSTAMode()");
Serial.print("SSID WF : ");Serial.println(ssidSTA);
Serial.print("PSWD WF : ");Serial.println(passwordSTA);
int nseg = 0;
int nchannel = 1;
WiFi.mode(WIFI_STA);
WiFi.setTxPower(WIFI_POWER_8_5dBm);
WiFi.channel(nchannel);
WiFi.begin(ssidSTA,passwordSTA);
delay(2000);
Serial.println();
WiFi.printDiag(Serial);
Serial.println();
delay(1000);
Serial.print("Conetando a red wifi " + String(&ssidSTA[0]) + "... ");
while (WiFi.status() != WL_CONNECTED && nchannel <= 14) {
delay(1000);
Serial.print(".");
nseg++;
if(nseg==10){
Serial.println();
nchannel++;
WiFi.channel(nchannel);
WiFi.reconnect();
Serial.println();
WiFi.printDiag(Serial);
nseg=0;
Serial.println();
}
}
if(WiFi.status() == WL_CONNECTED){
Serial.println(WiFi.localIP());
isAPMode = false;
RGBLed(6);
}else{
Serial.println("No se pudo conectar a la red WIFI almacenada");
isAPMode = true;
RGBLed(1);
}
}
void loadWiFiCredentials() {
File root = SPIFFS.open("/");
File WFJson;
bool lFile = false;
String NombreFile = "";
File file = root.openNextFile();
while (file) {
if (!file.isDirectory()) {
if(String(file.name())=="wifi_credentials.json"){
lFile = true;
NombreFile = file.name();
WFJson = SPIFFS.open("/" + NombreFile, "r");
break;
}
}
file = root.openNextFile();
}
delay(3000);
if (!lFile) {
Serial.println("No se encontraron credenciales WiFi guardadas.");
RGBLed(1);
delay(3000);
return;
}else{
size_t size = WFJson.size();
std::unique_ptr<char[]> buf(new char[size]);
file.readBytes(buf.get(), size);
JsonDocument doc;
deserializeJson(doc, buf.get());
Serial.println("Credenciales encontradas [003]:");
ssidSTA = doc["ssid"].as<const char*>();
passwordSTA = doc["password"].as<const char*>();
doc.clear();
//Serial.println("Variables desde la funcion loadWiFiCredentials()");
//Serial.print("SSID WF : ");Serial.println(ssidSTA);Serial.print("PSWD WF : ");Serial.println(passwordSTA);
RGBLed(2);
delay(5000);
if(ssidSTA != nullptr && ssidSTA[0] != '\0' && passwordSTA != nullptr && passwordSTA[0] != '\0'){
isAPMode=false;
Serial.println("Modo STA autoseleccionado");
}else{
Serial.println("Credenciales corruptas!!![002]");
SPIFFS.remove(NombreFile);
Serial.println("Credenciales ELIMINADAS[006]");
RGBLed(6);
isAPMode = true;
}
WFJson.close();
}
}
void loadAPCredentials() {
File root = SPIFFS.open("/");
File APJson;
bool lFile = false;
String NombreFile = "";
File file = root.openNextFile();
while (file) {
if (!file.isDirectory()) {
if(String(file.name())=="ap_credentials.json"){
lFile = true;
NombreFile = file.name();
APJson = SPIFFS.open("/" + NombreFile, "r");
break;
}
}
file = root.openNextFile();
}
if (!lFile) {
Serial.println("No se encontraron credenciales AP guardadas.");
RGBLed(1);
return;
}else{
if(isAPMode){
Serial.println("credenciales AP encontradas.[008]");
size_t size = APJson.size();
std::unique_ptr<char[]> buf(new char[size]);
file.readBytes(buf.get(), size);
JsonDocument doc;
deserializeJson(doc, buf.get());
String auxssid = doc["ssid"].as<const char*>();
String auxpswd = doc["password"].as<const char*>();
doc.clear();
auxssid.trim();
auxpswd.trim();
ssidAP = auxssid.c_str();
passwordAP = auxpswd.c_str();
Serial.print("SSID AP : ");Serial.println(String(ssidAP));
Serial.print("PSWD AP : ");Serial.println(String(passwordAP));
APJson.close();
}
}
}
void saveWiFiCredentials(const String& ssid, const String& password) {
JsonDocument doc;
doc["ssid"] = ssid;
doc["password"] = password;
File file = SPIFFS.open("/wifi_credentials.json", "w");
serializeJson(doc, file);
file.close();
isAPMode = false;
doc.clear();
}
void saveAPCredentials(const String& ssid, const String& password) {
JsonDocument doc;
doc["ssid"] = ssid;
doc["password"] = password;
File file = SPIFFS.open("/ap_credentials.json", "w");
serializeJson(doc, file);
file.close();
doc.clear();
}
void listSPIFFSFiles() {
// Comprobar si SPIFFS está montado correctamente
if (!SPIFFS.begin()) {
Serial.println("No se pudo montar SPIFFS");
return;
}
// Abre el directorio raíz
File root = SPIFFS.open("/");
if (!root) {
Serial.println("Fallo al abrir el directorio raíz");
return;
}
// Comprueba si es un directorio
if (!root.isDirectory()) {
Serial.println("No es un directorio");
return;
}
// Abre el directorio
File file = root.openNextFile();
while (file) {
if (file.isDirectory()) {
Serial.print("Directorio: ");
Serial.println(file.name());
} else {
Serial.print("Archivo: ");
Serial.print(file.name());
Serial.print(" Tamaño: ");
Serial.println(file.size());
}
file = root.openNextFile();
}
// Cerrar el directorio y finalizar SPIFFS
file.close();
//SPIFFS.end();
}
void DelCredencials(int Credencials){
File root = SPIFFS.open("/");
String NombreFile = "";
File file = root.openNextFile();
bool fEncontrado = false;
switch (Credencials)
{
case 8:
NombreFile = "ap_credentials.json";
break;
case 9:
NombreFile = "wifi_credentials.json";
break;
default:
NombreFile = ".";
break;
}
while (file) {
if (!file.isDirectory()) {
if(String(file.name())==NombreFile){
SPIFFS.remove("/" + NombreFile);
Serial.print("Archivo ");
Serial.print(NombreFile);Serial.println(" Eliminado!");
fEncontrado = true;
break;
}
}
file = root.openNextFile();
}
if(!fEncontrado){
Serial.println();Serial.println("Archivo de credenciales no encontrado");
}
}
void WebServerIni(){
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
String htmlContent;
File file = SPIFFS.open("/index.html", "r");
if (file) {
htmlContent = file.readString();
file.close();
}
if(isAPMode){
// Reemplaza los marcadores de posición con los valores reales
htmlContent.replace("{SSID_AP}", WiFi.softAPSSID());
htmlContent.replace("{IP_AP}", WiFi.softAPIP().toString());
htmlContent.replace("{AP_PSWD}", String(passwordAP));
}else{
if (WiFi.status() == WL_CONNECTED) {
htmlContent.replace("{SSID_AP}", String(WiFi.SSID()));
htmlContent.replace("{IP_AP}", WiFi.localIP().toString());
} else {
htmlContent.replace("{SSID_AP}", "No conectado");
htmlContent.replace("{IP_AP}", "N/A");
}
}
// Envía el contenido modificado al cliente
request->send(200,"text/html",htmlContent);
});
server.on("/wifi_sta", HTTP_GET, [](AsyncWebServerRequest *request){
String htmlContent;
File file = SPIFFS.open("/wifi_sta.html", "r");
if (file) {
htmlContent = file.readString();
file.close();
}
// Reemplaza {{WIFI_LIST}} con la lista de redes WiFi escaneadas
htmlContent.replace("{{WIFI_LIST}}", scanNetworks());
request->send(200, "text/html",htmlContent );
});
server.on("/save_wifi", HTTP_POST, [](AsyncWebServerRequest *request){
String ssid;
String password;
if (request->hasParam("lstSSID", true)) {
ssid = request->getParam("lstSSID", true)->value();
}
if (request->hasParam("inputPassword2", true)) {
password = request->getParam("inputPassword2", true)->value();
}
// Guarda las credenciales WiFi
if (ssid.length() > 0 && password.length() > 0) {
saveWiFiCredentials(ssid, password);
delay(5000);
request->send(200, "text/plain", "Credenciales guardadas. Reinicia el ESP32.[000]");
delay(10000);
ESP.restart();
}else{
request->send(200, "text/plain", "Credenciales corruptas! ERROR[001]");
delay(10000);
}
});
server.on("/setup_ap", HTTP_GET, [](AsyncWebServerRequest *request){
String htmlContent;
File file = SPIFFS.open("/setup_ap.html", "r");
if (file) {
htmlContent = file.readString();
file.close();
}
// Insertar los valores dinámicos en el HTML
htmlContent = insertValuesAP(htmlContent);
request->send(200, "text/html",htmlContent );
});
server.on("/save_ap", HTTP_POST, [](AsyncWebServerRequest *request){
String ssid;
String password;
if (request->hasParam("ssidAP", true)) {
ssid = request->getParam("ssidAP", true)->value();
}
if (request->hasParam("pswdAP", true)) {
password = request->getParam("pswdAP", true)->value();
}
// Guarda las credenciales WiFi
if (ssid.length() > 0 && password.length() > 0) {
saveAPCredentials(ssid, password);
delay(5000);
request->send(200, "text/plain", "Credenciales guardadas. Reinicia el ESP32.[000]");
delay(10000);
ESP.restart();
}else{
request->send(200, "text/plain", "Credenciales corruptas! ERROR[001]");
delay(10000);
}
});
server.on("/estado_ap", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SPIFFS, "/estado_ap.html", "text/html");
});
server.on("/del_credencials", HTTP_GET, [](AsyncWebServerRequest *request){
DelCredencials(8);
DelCredencials(9);
request->send(200, "text/plain", "Accion ejecutada!");
delay(2000);
request->send(SPIFFS, "/", "text/html");
});
server.on("/elimina_credenciales", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SPIFFS, "/elimina_credenciales.html", "text/html");
});
server.on("/info_esp32", HTTP_GET, [](AsyncWebServerRequest *request){
String htmlContent;
File file = SPIFFS.open("/info_esp32.html", "r");
if (file) {
htmlContent = file.readString();
file.close();
}
htmlContent = insertValues(htmlContent);
request->send(200, "text/html",htmlContent );
});
server.on("/jquery-3.2.1.slim.min.js", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SPIFFS, "/jquery-3.2.1.slim.min.js", "application/javascript");
});
server.on("/popper.min.js", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SPIFFS, "/popper.min.js", "application/javascript");
});
server.on("/bootstrap.min.js", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SPIFFS, "/bootstrap.min.js", "application/javascript");
});
server.on("/bootstrap.min.js.map", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SPIFFS, "/bootstrap.min.js.map", "application/javascript");
});
server.on("/bootstrap.min.css", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SPIFFS, "/bootstrap.min.css", "text/css");
});
server.on("/bootstrap.min.css.map", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SPIFFS, "/bootstrap.min.css.map", "text/css");
});
server.on("/banneresp32camcar.png", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SPIFFS, "/banneresp32camcar.png", "image/png");
});
server.on("/favicon.ico", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SPIFFS, "/favicon.ico", "image/x-icon");
});
server.begin();
}
void chkTimeBootAP(){
Esta linea, le ha impreso de diferentes formas y el resultado es el mismo que se ve en el monitor.
Serial.print("Conetando a red wifi " + String(&ssidSTA[0]) + "... ");
Saludos.