Duda Arduino ESP8266 MCU con WifiManager + WifiClientSecure + MQTT

Buenas!

He configurado mi arduino con wifiManager para crear el portal y que cada usuario identifique y se conecte a su propia wifi. Una vez se obtiene en el SaveConfigCallback del wifiManager y compruebo que efectivamente hay conexión, inicio la conexión con MQTT con mi servidor mosquitto, el cual esta configurado y funcionando con SSL.

El problema o duda que no consigo entender es el siguiente:
La primera vez que configuro el Wifi en el dispositivo desde el portal de WifiManager (o le introduzco el comando WifiManager.resetSettings() para que elimine lo que guarda en memoria y simular que es la primera vez que entra) y se intenta conectar desde ahí al MQTT, me da fallo la conexión MQTT y no entra en ninguna de sus reconexiones.

Pero (aqui es donde me pierdo) si le quito el comando WifiManager.resetSettings(), la primera vez que entra me falla como comentaba anteriormente, pero si vuelvo a iniciar el arduino ya carga perfectamente la conexion MQTT (solo falla la primera vez, todas las demás veces se conecta).

Entiendo que no es problema de configuración con el MQTT, porque accedo al broker desde varios sitios con la misma configuración y no hay problema (incluyendo el propio arduino siempre y cuando no sea la primera vez que se conecta desde WiFiManager) e incluso si en lugar de utilizar WifiManager me conecto directo al Wifi por la libreria WiFi del esp8266 no me da ese error de conexión de MQTT.

No he introducido código, porque no se si se debe a un bug de la primera vez que configura WifiManager la conexión y la usa para MQTT o algo así, si necesitais cualquier fragmento pedírmelo sin problemas.

Alguien se le ocurre que poder hacer esa primera vez con la conexión entre WifiManager y MQTT?

Gracias de antemano!!

Y el código?
Nunca leíste las normas del foro? Si tu sabes la solución del problema entonces lo podrás resolver por tu cuenta pero para que nosotros te demos una mano, tenemos que ver TODO el problema. Código y tu posible enfoque de donde esta la causa.
Yo te aseguro que reset borra todo y OBLIGA a que en la siguiente oportunidad debes SI O SI, volver a encontrar la WIFI con la que quieres operar. Si no la pide es porque muy posiblemente tengas de tu desarrollo previo los valores hardcodeados y los esta tomando.

Por eso ver el código nos permite dar un buen diagnóstico.

Como no has adjuntado el código como para poder verificarlo, pregunto: ¿Estás seguro que se ha establecido la conexión wifi cuando intentas conectarte a mqtt?

Gracias por vuestra respuesta, os adjunto el código relacionado a esa parte que expliqué.

En cuanto a tu pregunta sobre la conexión wifi estoy seguro que se lleva a cabo ya que entra en el callback de saveWifiCallback() del propio WifiManager y a través de ese callback es cuando compruebo la conexion wifi, ajusto la hora del reloj y ya comprueba la conexion con el MQTT y la establece.

#include <WiFiManager.h>
#include <WiFiClientSecure.h>
#include <PubSubClient.h>

WiFiManager wm;

// Clientes WiFi y MQTT
static WiFiClientSecure wificlient;
static PubSubClient mqttclient(wificlient);

// X.509 parsed CA & Client Certs
X509List caCertX509(caCert);
X509List clientCertX509(clientCert);
PrivateKey clienteKeyX509(clientKey);

bool wifiActivado = false;
bool mqttConectado = false;

void saveWifiCallback(){
  Serial.println("CALLBACK WIFI");
  if(!mqttConectado){
    inicia_wifi();
  } else {
    Serial.println("Ya se encuentra conectado a wifi y mqtt");
  }
}

void setup() {
  WiFi.mode(WIFI_STA);
  Serial.begin(115200);
  
  // Utilizo este resetSettings para que borre los datos de la conexión, 
// y forzar que simule como si el arduino se configure por primera vez, 
//de manera que tenga que volver a configurar el usuario la conexion 
// con su wifi.

// Aqui es donde tengo el problema, ya que si le quito el resetSettings() 
// y cargo el programa, la primera vez que configure el wifi va a fallar 
// la conexion MQTT, pero simplemente volviendo a encender 
// el arduino sin cargar programa ni modificando nada, coge los datos de la conexion del wifi 
// guardado en el por WifiManager y con el mismo autoReconnect
// se establece la conexion perfectamente MQTT.

   wm.resetSettings();
  wm.setConfigPortalBlocking(false);
  wm.setWiFiAutoReconnect(true);
  wm.setDebugOutput(true);
  wm.setSaveConfigCallback(saveWifiCallback);
  bool res;

  res = wm.autoConnect("WifiManagerPortal", "87654321");
  if(!res) {
        Serial.println("Failed to connect");
        wifiActivado = false;
  }  else {
    // Aqui vuelvo a llamar a la funcion que uso para el callback ya que
   //  practicamente lo que hace es comprobar la conexion y lo envia 
   // a la función de inicia_wifi()
    saveWifiCallback();
  }
}

void loop() {
  wm.process();
  mqttclient.loop();
  yield();

  if(wifiActivado){
    //Revisa estado de Wifi o reintenta conexión  
    if (WiFi.status() != WL_CONNECTED){
      inicia_wifi();
    }else{
      if (!mqttConectado){
        Serial.println("NO SE TIENE MQTT CONECTADO Y SE VUELVE A CONECTAR");
        mqttclient.disconnect();
        inicia_mqtt(); // reintento
      }
    }
  } 
} 

void inicia_wifi(){
    //int intentos = 5;
    //int cuenta = 0;
    while (WiFi.status() != WL_CONNECTED)//&& (cuenta < intentos) 
    {
      Serial.println("CONECTANDO WIFI... ");
      //cuenta = cuenta+1;
      delay(1000);
      Serial.print("."); 
    }

    if(WiFi.status() == WL_CONNECTED){
      timeClient.begin();
      delay ( 1000 );
      if (timeClient.update()){
        Serial.println ( "Adjust local clock" );
        unsigned long epoch = timeClient.getEpochTime();
        setTime(epoch);
      }else{
        Serial.println ( "NTP Update not WORK!!" );
      }
      Serial.println("WIFI conectado con exito! ");
      inicia_mqtt();
    } else {
      Serial.println("Sin conexion wifi");
    }
  }

void inicia_mqtt() {
  int intentos = 5;
  int cuenta = 0;

  wifiActivado = true;
  // Configura cliente TLS
  // añade CA cert en los sitios de confianza
  wificlient.setTrustAnchors(&caCertX509);
  // Habilita self-signed cert
  wificlient.allowSelfSignedCerts(); 
  // añade fingerprint para validar conexión
  wificlient.setFingerprint(mqttCertFingerprint); 
  // le envia el certif icado de cliente (lo solicita el servidor)
  wificlient.setClientRSACert(&clientCertX509, &clienteKeyX509);
  
  mqttclient.setServer(MQTT_IP, MQTT_puerto);

  // Create a random client ID
    String clientId = "ESP8266Client-";
    clientId += String(random(0xffff), HEX);

    mqttclient.connect(clientId.c_str());
    mqttclient.setBufferSize(512);
    mqttclient.setCallback(callback);

    Serial.print(" MQTT Conectando a ");
    Serial.println(MQTT_IP);

  while (!mqttclient.connected()&&(cuenta<=intentos)){
    cuenta = cuenta + 1;
    delay(1000);
    Serial.print(".");
  }
  Serial.println("");

  if(mqttclient.connected()){
    Serial.println("Mqtt Conectado con exito!");
    Serial.println(mqttclient.state());  
    mqttConectado = true;
  } else {
    Serial.print("failed, rc=");
    Serial.print(mqttclient.state());
    Serial.println("Sin conexion con Mqtt");
    mqttConectado = false;
    Serial.println("EL MQTT CONECTADO ES FALSE Y DEBE ENTRAR OTRA VEZ");
  }
}

Os dejo los logs para que podais entender visualmente un poco mejor el flujo:

** Primera vez que se carga el programa en arduino o con el uso del wm.resetsettings() para formar esa primera conexión que es la que da fallo: **

*wm: ID_MQTT 
AUTO RECONNECTED O CALLBACK WIFI
Adjust local clock
WIFI conectado con exito! 
 MQTT Conectando a ID_MQTT 
......
failed, rc=-2Sin conexion con Mqtt
EL MQTT CONECTADO ES FALSE Y DEBE ENTRAR OTRA VEZ
NO SE TIENE MQTT CONECTADO Y SE VUELVE A CONECTAR
 MQTT Conectando  a ID_MQTT
......
failed, rc=-2Sin conexion con Mqtt
EL MQTT CONECTADO ES FALSE Y DEBE ENTRAR OTRA VEZ
NO SE TIENE MQTT CONECTADO Y SE VUELVE A CONECTAR
 MQTT Conectando  a ID_MQTT
......
failed, rc=-2Sin conexion con Mqtt
EL MQTT CONECTADO ES FALSE Y DEBE ENTRAR OTRA VEZ
NO SE TIENE MQTT CONECTADO Y SE VUELVE A CONECTAR

// Así en bucle ya que no consigue conectar

Esto genera los siguientes logs en mi servidor mosquitto:

1712640217: New connection from IP_ARDUINO:54809 on port 8883.
1712640223: OpenSSL Error[0]: error:0A000126:SSL routines::unexpected eof while reading
1712640223: Client <unknown> disconnected: protocol error.
1712640223: New connection from IP_ARDUINO:55978 on port 8883.
1712640229: OpenSSL Error[0]: error:0A000126:SSL routines::unexpected eof while reading
1712640229: Client <unknown> disconnected: protocol error.

Los siguientes logs son para la situación que os indicaba, se comenta en el código el resetSettings() para que guarde la conexión. La primera vez que entra y se configura pasa lo mismo que lo comentado arriba (mismos logs ya que sigue siendo la primera vez que entra y se configura), pero aqui simplemente ya no se borran esos datos y REINICIO el arduino para que coja los datos ya guardados anteriormente de WifiManager:

*wm:v2.0.17  D:2
*wm:AutoConnect 
*wm:Connecting to SAVED AP: MI_RED_WIFI
*wm:connectTimeout not set, ESP waitForConnectResult... 
*wm:AutoConnect: SUCCESS 
*wm:STA IP Address: 192.168.X.X

Adjust local clock
WIFI conectado con exito! 
 MQTT Conectando a 192.168.X.X

Mqtt Conectado con exito!

Y en los logs de mi servidor mosquitto se puede ver que funcionó todo correcto:

1712641764: New connection from 192.168.X.X:61741 on port 8883.
1712641772: New client connected from 192.168.X.X:61741 as ESP8266Client-3f8b (p2, c1, k15, u'cliente').
1712641772: No will message specified.
1712641772: Sending CONNACK to ESP8266Client-3f8b (0, 0)
1712641772: Received SUBSCRIBE from ESP8266Client-3f8b
1712641787: Received PINGREQ from ESP8266Client-3f8b
1712641787: Sending PINGRESP to ESP8266Client-3f8b
1712641802: Received PINGREQ from ESP8266Client-3f8b
1712641802: Sending PINGRESP to ESP8266Client-3f8b

Es lo que os comentaba, solo falla la primera vez que se configura (ya sea la primera carga del programa o siempre y cuando que obligue con el resetSettings() a configurar de nuevo esa conexión), todas las demás veces que se vuelva a cargar o se reinicie con esa conexión Wifi cargada, no hay ningun problema y funciona todo perfectamente.

Gracias de antemano!

De todas las soluciones y explicaciones que encontré en distintos foros, creo que la única que podrías probar es mover la línea

WiFiManager wm;

justo debajo de

#include <WiFiManager.h>

No se si realmente cambie en algo pero con probar...

Tienes la linea que resetea toda tu configuración. Debes comentarla!!!
La primera vez es para poner los registros de WiFIManager a 0 pero luego vuelves a compilar con esa linea comentada y ahi comienzas a usar debidamente tu código.

Y ademas tienes las cosas confundidas.
Esto

res = wm.autoConnect("WifiManagerPortal", "87654321");

Genera un AP para que te conectes a tu ESP8266 pero nunca te vas a conectar a la WIFI de tu casa o lugar donde deba funcionar.

Eso es lo que buscas no?

Lo probé pero no hubo suerte :sweat_smile:.

Estuve haciendo pruebas con respecto a la conexión Wifi, cambiando parametros, guardandolos en FS y conectandome mediante Wifi.begin(), etc. pero creo que no es por la conexión wifi en si (ya que con el autoconect de wifimanager o por el wifi.begin siempre acaba conectando a la primera, el problema es que la conexión MQTT a la primera es la que falla), si no que a la hora de arrancar o la configuración del WifiClientSecure junto con el MQTT no se que se dejará pero esa primera vez no lo hace bien.

De hecho te dejo un pequeño log mostrando como daría igual como se intente conectar a wifi ya que haciendo esos cambios que te comentaba e incluso quitando la conexión wifi y volviendola a crear en cada intento se hace con éxito:

SE CONECTA CON CLIENTE -> ESP8266Client-e92e
 MQTT Conectando a 192.168.X.X
......
failed, rc=-2Sin conexion con Mqtt
EL MQTT CONECTADO ES FALSE Y DEBE ENTRAR OTRA VEZ
WIFI SSID -> MyWifiSSID
WIFI PASS -> MyWifiPass.
CONECTANDO WIFI... 
.CONECTANDO WIFI... 
.CONECTANDO WIFI... 
.CONECTANDO WIFI... 
WIFI conectado con exito! 
SE CONECTA CON CLIENTE -> ESP8266Client-9612
 MQTT Conectando a 192.168.x.x
......
failed, rc=-2Sin conexion con Mqtt
EL MQTT CONECTADO ES FALSE Y DEBE ENTRAR OTRA VEZ
WIFI SSID -> MyWifiSSID
WIFI PASS -> MyWifiPass
CONECTANDO WIFI... 
.CONECTANDO WIFI... 
.CONECTANDO WIFI... 
.CONECTANDO WIFI... 
WIFI conectado con exito! 
SE CONECTA CON CLIENTE -> ESP8266Client-b2d7
 MQTT Conectando a 192.168.X.X
......
failed, rc=-2Sin conexion con Mqtt
EL MQTT CONECTADO ES FALSE Y DEBE ENTRAR OTRA VEZ
NO SE TIENE MQTT CONECTADO Y SE VUELVE A CONECTAR

También tengo la idea de algo de esa primera configuración en WifiClientSecure o MQTT porque si que es verdad que en los logs de mosquitto, para esa primera vez que intenta conectarse y se queda en bucle al fallar la conexión MQTT, se dan los siguientes logs:

1712723113: New connection from 192.168.1.62:51167 on port 8883.
1712723119: OpenSSL Error[0]: error:0A000126:SSL routines::unexpected eof while reading
1712723119: Client <unknown> disconnected: protocol error.

Parece que no crea bien esa conexión ya que el cliente con el que envio los intentos de conexión es 'ESP8266Client-XXXX', de hecho una vez reinicio el arduino como os comentaba, parece que si crea esa conexión bien a partir de los datos que ya tiene guardados porque si logra conectarse al MQTT y los logs si son razonables

1712721739: New client connected from 192.168.X.X:52736 as ESP8266Client-2808 (p2, c1, k15, u'cliente').
1712721739: No will message specified.
1712721739: Sending CONNACK to ESP8266Client-2808 (0, 0)
1712721739: Received SUBSCRIBE from ESP8266Client-2808
1712721739: Sending SUBACK to ESP8266Client-2808
1712721755: Received PINGREQ from ESP8266Client-2808
1712721755: Sending PINGRESP to ESP8266Client-2808
1712721770: Received PINGREQ from ESP8266Client-2808

Sí, como te comente la uso para simular que es un 'arduino nuevo', sin configuraciones de ningun tipo. Esa linea una vez lo ejecuto, vuelvo a cargar el programa con esa linea comentada (por eso sé que las siguientes veces si establece bien las conexiones con MQTT y solo falla la primera) y ya, a partir de ahí, empiezo a configurar el wifi como os comente, pero dejandola o sin dejar simularía que es la primera vez que se entra en el arduino para configurar el wifi y la conexion MQTT y en esa primera iteracion es donde falla.

Lo que mencionas del autoConnect crea un ap para que puedas configurarle el Wifi a tu Arduino sin necesidad de hardcodearle los parametros del wifi (ya que cada persona tiene su wifi y con esto lo que se hace es que cada usuario se configure su wifi con el arduino), es más, hasta el log del WifiManager te indica que se conecta a un AP (en este caso mi router) y me muestra la información y la conexión exitosa a el, a parte que despues el WiFi.status() es connected.

*wm:16 networks found
*wm:Connecting to NEW AP: MiRouterSSID
*wm:Connect to new AP [SUCCESS] 
*wm:Got IP Address: 
*wm: MiRouterIP

De hecho si te fijas en los primeros logs que os envie se conecta perfectamente y tiene el Wifi en todo momento funcionando indicando los parametros del wifi al que esta conectado.

Te dejo unos logs del flujo siguiente, para que veas el problema más claro:
inicio arduino sin configuración --> se configura/establece conexión wifi --> intento de MQTT (con fallo en bucle porque es la primera vez de esas conexiones) --> presionar boton RST arduino para volver a cargar el programa --> autoreconexion del wifi --> conexión exitosa MQTT

*wm:16 networks found
*wm:Connecting to NEW AP: WIFISSID
*wm:connectTimeout not set, ESP waitForConnectResult... 
*wm:Connect to new AP [SUCCESS] 
*wm:Got IP Address: 
*wm:192.168.X.X 
AUTO RECONNECTED O CALLBACK WIFI
WIFI SSID -> MyWifiSSID
WIFI PASS -> MyWifiPass
CONECTANDO WIFI... 
.CONECTANDO WIFI... 
.CONECTANDO WIFI... 
.CONECTANDO WIFI... 
.Adjust local clock
WIFI conectado con exito! 
SE CONECTA CON CLIENTE -> ESP8266Client-1dec
 MQTT Conectando a 192.168.X.X
......
failed, rc=-2Sin conexion con Mqtt
EL MQTT CONECTADO ES FALSE Y DEBE ENTRAR OTRA VEZ
WIFI SSID -> MyWifiSSID
WIFI PASS -> MyWifiPass
CONECTANDO WIFI... 
.CONECTANDO WIFI... 
.CONECTANDO WIFI... 
.CONECTANDO WIFI... 

// La siguiente linea es el log al haber pulsado el boton rst de arduino
.sllܾ��c�n�$�p�|����r��B��NN�dNN���cp��cd`{dp�N��$��bn�|����c�|�o�l��l`�e

*wm:v2.0.17  D:2
*wm:AutoConnect 
*wm:Connecting to SAVED AP: WIFISSID
*wm:connectTimeout not set, ESP waitForConnectResult... 
*wm:AutoConnect: SUCCESS 
*wm:STA IP Address: 192.168.X.X
AUTO RECONNECTED O CALLBACK WIFI
WIFI SSID -> MyWifiSSID
WIFI PASS -> MyWifiPass
CONECTANDO WIFI... 
.CONECTANDO WIFI... 
.CONECTANDO WIFI... 
.CONECTANDO WIFI... 
.Adjust local clock
WIFI conectado con exito! 
SE CONECTA CON CLIENTE -> ESP8266Client-c331
 MQTT Conectando a 192.168.X.X

Mqtt Conectado con exito!

Como le he comentado a @MaximoEsfuerzo, lo unico que se me ocurre es que algo no va bien en esa primera configuración con WifiClientSecure y MQTT que es donde crea la conexion con el MQTT, pero insisto, solo esa primera vez, porque una vez se reinicia el arduino la conexión con el MQTT funciona a la primera.

Esto requiere un yield()
intena no usar delay() o tendras problemas.

Esto no es suficiente

void loop() {
  wm.process();
  mqttclient.loop();
  yield();

porque luego de 3 intentes ves que se cuelga
Asi que agrega un yield() y reduce el delay() en los reintentos mqtt.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.