knolleary / pubsubclient

A client library for the Arduino Ethernet Shield that provides support for MQTT.
http://pubsubclient.knolleary.net/
MIT License
3.83k stars 1.47k forks source link

MQTT Client stuck at `mqttClient.connect("id", "user", "pass")`. No runtime error, no error code, no timeout. #992

Open Nuddel69 opened 1 year ago

Nuddel69 commented 1 year ago

The client seems to freeze when executing mqttClient.connect(). I find it strange considering how it manages a few complete transmissions before this happens. I'm using GSM - I make sure the arduino is connected before each transmission by reconnecting and checking whether there's a valid IP-address present. This doesn't seem to be a common issue so I figured I'd try my luck here. Here's the mqtt function:

  if (!mqttClient.connected()) {
    Serial.print("MQTT - Attempting to connect to MQTT broker: ");
    Serial.println(broker);

    if (!mqttClient.connect("id", "user", "pass")) {
      Serial.print("MQTT - connection failed! Error code = ");
      Serial.println(mqttClient.state());
    } else {
      Serial.println("MQTT - connected");
      send_to_mqtt();
      Serial.println("MQTT - message sent.");
      mqttClient.disconnect();  // disconnects mqtt
      gsmClient.stop();   // disconnects network
      isClientConnected = false;
      Serial.println("MQTT - mqttClient and gsmClient disconnected.");
    }
  } else {
    Serial.println("MQTT - already connected");
  }

There's a reconnect function executed before each MQTT transmission looking like this:

  checkNetwork();
  Serial.println("Reconnecting GSM...");
  GSM.getNetwork()->disconnect();
  delay(500);
  Serial.println(GSM.localIP());
  int thresh = 3;
  while(GSM.localIP() == IPAddress(0,0,0,0) && thresh > 0)
  {
    Serial.println("No Ip - Connecting...");

    switch(GSM.getNetwork()->connect())
    {
      case 0:  //NSAPI_ERROR_OK
      Serial.println("Connection established.");
      break;

      case -3020:    //NSAPI_ERROR_BUSY
      Serial.println("Asynchronous operation cannot be started. ");
      break;

      case -3015:    //NSAPI_ERROR_IS_CONNECTED
      Serial.println("Already connected.");
      break;

      default:
      Serial.println("Connection failed");
      break;
    }
    delay(1000);
    thresh--;
  } 
  if (!thresh)
  {
    Serial.println("Failed to establish GSM connection.");
    physReset(RESETpin);
  }
  else
  {
    Serial.print("GSM connected at IP adress: ");
    Serial.println(GSM.localIP());
  }

Here's a screenshot of the output:

bilde

After looking through the source code I'm guessing this is the part where I'm getting stuck (in boolean PubSubClient::connect(const char *id, const char *user, const char *pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage, boolean cleanSession)), but I can't seem to figure a way to solve it

            while (!_client->available()) {
                unsigned long t = millis();
                if (t-lastInActivity >= ((int32_t) this->socketTimeout*1000UL)) {
                    _state = MQTT_CONNECTION_TIMEOUT;
                    _client->stop();
                    return false;
                }
            }

Edit:

I tried rewriting the function to use a unique pointer instead to ensure a fresh client, but the problem persists First declaring the object: std::unique_ptr<PubSubClient> mqttClient; And defining the function:

  mqttClient.reset(new PubSubClient);
  mqttClient->setClient(gsmClient);
  mqttClient->setServer(broker, port);
  if (!mqttClient->connected()) {
    Serial.print("MQTT - Attempting to connect to MQTT broker: ");
    Serial.println(broker);

    if (!mqttClient->connect("id", "user", "pass")) {
      Serial.print("MQTT - connection failed! Error code = ");
      Serial.println(mqttClient->state());
    } else {
      Serial.println("MQTT - connected");
      send_to_mqtt();
      Serial.println("MQTT - message sent.");
      mqttClient->disconnect();  // disconnects mqtt
      gsmClient.stop();   // disconnects network
      isClientConnected = false;
      Serial.println("MQTT - mqttClient->and gsmClient disconnected.");
    }
  } else {
    Serial.println("MQTT - already connected");
  }

Edit 2:

After some further testing I seem to have located the part causing issues. I placed print statements before and after each function call in the connect() method, and the only part where it seems to struggle is here:

write(MQTTCONNECT,this->buffer,length-MQTT_MAX_HEADER_SIZE);

Is it possible to add some sort of either timeout or complete reset of the buffer before executing this command?

alanmasu commented 1 year ago

Hi, I'm in a similar situation, when I try to connect an MQTT broker over internet (eg. test.mosquitto.org) or in my LAN (Raspberry Pi) and there isn't any internet or network connection (I haven't possibility to check it before) calling PubSubClient::connect(const char* ) the ESP32 hangs in that row

Gen1usBruh commented 1 year ago

I believe this may help: https://github.com/knolleary/pubsubclient/issues/403#issuecomment-1432869562 I answered thinking this is my problem, but I found your issue.

Link does not work by clicking, copy and paste it.