knolleary / pubsubclient

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

I always fail to connect. #138

Open THDEW opened 8 years ago

THDEW commented 8 years ago

I always fail to connect when I implement your basic example with my code. This will happen when I put put reconnect method in the void loop but when I tried to change the position to void setup(), it's work but not perfectly which mean when I put in different position in void setup(), somehow it make my program freeze. BTW, I put small delay before it will connect to and the code that I get is -2 which mean the connection fail. Do u have any suggestion?

THDEW commented 8 years ago

I got a little more question, if i set connection in Arduino and doing different task than publish or subscribe. Will it disconnect automatically?

knolleary commented 8 years ago

Hi, you'll have to provide a clearer description, with code, of what works and doesn't work for you. What hardware are you using?

The client will remain connected as long as you call the client.loop function regularly. Otherwise the server will disconnect the client due to inactivity.

shrobon commented 8 years ago

Problem Message : Attempting MQTT connection...failed, rc=-2 try again in 5 seconds

Hardware _: Arduino Uno + Ethernet Shield _Software : Arduino IDE (1.6.7) , PubSubClient 2.6.0

Code : (Modified the ip address to that of test.mosquitto.org )

include

include

include

// Update these with values suitable for your network. byte mac[] = { 0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED }; IPAddress ip(172, 16, 0, 100); IPAddress server(85,119,83,194); // test.mosquitto.org

void callback(char* topic, byte* payload, unsigned int length) { Serial.print("Message arrived ["); Serial.print(topic); Serial.print("] "); for (int i=0;i<length;i++) { Serial.print((char)payload[i]); } Serial.println(); }

EthernetClient ethClient; PubSubClient client(ethClient);

void reconnect() { // Loop until we're reconnected while (!client.connected()) { Serial.print("Attempting MQTT connection..."); // Attempt to connect if (client.connect("arduinoClientUNIQUE")) { Serial.println("connected"); // Once connected, publish an announcement... client.publish("outTopicUNIQUE","hello world"); // ... and resubscribe client.subscribe("inTopicUNIQUE"); } else { Serial.print("failed, rc="); Serial.print(client.state()); Serial.println(" try again in 5 seconds"); // Wait 5 seconds before retrying delay(5000); } } }

void setup() { Serial.begin(57600);

client.setServer(server, 1883); client.setCallback(callback);

Ethernet.begin(mac, ip); // Allow the hardware to sort itself out delay(1500); }

void loop() { if (!client.connected()) { reconnect(); } client.loop(); }

knolleary commented 8 years ago

@shrobon Have you tried verifying your basic setup using the File->Examples->Ethernet->WebClient example? Just to ensure the hardware and the network connection is all okay.

shrobon commented 8 years ago

@knolleary , Yes I have tried doing that . The WebClient works perfectly well .

shrobon commented 8 years ago

@knolleary . You can close the issue . There were a couple of problems from my end . You can include this in your readme since many stumble with this problem . Firstly , while using the WebClient , i was getting a DHCP address . Here in this sketch , i overlooked the IP address completely. Secondly i made the client name Unique . This solved the issue . Connects and publishes like a charm now ! Thanks

knolleary commented 8 years ago

@shrobon well, I can't close this issue as @THDEW raised it and we have no indication of whether they have resolved their issue. But I think you're quite right that hardcoded IP vs DHCP is definitely something I must remember to mention when this type of issue gets raised. Thanks!

panzho commented 8 years ago

hi there sorry for reviving this post but i have been with this problem for 2 weeks ! and here i read that there is a webclient example i try it but doesnt works for me :(

i add an screenshot to show you what happen, i am using an arduino ethernet on a DHCP network but when i try to use the webclient example always fail...

can someone help my with that ? or tell me where i can find some help ?

PD: sorry for my bad english LOOOTS OF THANKS FOR YOU POST GIVE ME HOPE !!

conexion failed state 2

vicatcu commented 8 years ago

@panzho it looks like your board isn't even getting an IP address, so you're problem probably has nothing to do with PubSubClient. Did you try just running this example sketch? Crawl before you walk, walk before you run :-)

panzho commented 8 years ago

@vicatcu yeah thanks for your answer i use that example and i remember that my network is not a dhcp network, i am on a static ip network ! (sorry about that :P ) now the example give me back the ip of my arduino in the monitor serie 9600 but i already have problems with my mqtt sketch `//https://www.baldengineer.com/mqtt-tutorial.html

include

include

include

include

LiquidCrystal lcd(9, 8, 6, 5, 3, 2);

byte mac[] = { 0x90, 0xA2, 0xDA, 0x0D, 0xDA, 0xA0 };

byte server[] = { 10,1,4,36 };

//byte ip[] = { 10, 2, 23, 163 };

IPAddress ip(10, 2, 23, 163); IPAddress myDns(10,1,1, 45); IPAddress gateway(10, 2, 23, 254); IPAddress subnet(255, 255, 255, 0);

EthernetClient ethClient;

//PubSubClient client(server , 1883 , callback ,ethClient);

void callback(char* topic, byte* payload, unsigned int length) {

Serial.print("Payload: ");

Serial.write(payload, length);

Serial.println();

//clear LCD screen

lcd.clear();

//set cursor position on the LCD at column 0, line 0 then display Office Temp

lcd.setCursor(0,0);

lcd.print("mqtt");

//set cursor position on the LCD at column 0, line 1

lcd.setCursor(0,1);

//write the payload to the LCD display

lcd.write(payload, length);

}

PubSubClient client(server, 1883, callback, ethClient);

void reconnect() { // Loop until we're reconnected while (!client.connected()) { Serial.print("intentando conexion MQTT..."); // Attempt to connect if (client.connect("ardu")) { Serial.println("conectado"); // ... and subscribe to topic client.subscribe("mqtt/2"); } else { Serial.print("failed, rc="); Serial.print(client.state()); Serial.println(" nuevo intento en 5 seg"); // Wait 5 seconds before retrying delay(5000); } } }

void setup(){ Serial.begin(9600); Ethernet.begin(mac, ip ,gateway, subnet); client.setClient(ethClient); client.setServer(server, 1883); client.setCallback(callback);

//Print Arduino IP address to serial for debugging

Serial.print("IP = ");

Serial.println(Ethernet.localIP());

lcd.begin(16, 2);

lcd.print("mqtt Siquei");

lcd.setCursor(0,1);

lcd.print(Ethernet.localIP());

if(4>3){ Serial.println("calando ifes"); } client.connect("ardu", "arduino", "arduino"); //client.connect("arduino", "arduino", "arduino"); if (client.connect("ardu", "arduino", "arduino")) {

client.publish("mqtt/2","LCD Display Online");

Serial.println("conexion exitosa");

client.subscribe("mqtt/2");

} if (client.connect("arduino")==false) {

client.publish("mqtt/2","LCD Display Online");

Serial.println("fallo la conexion");

client.subscribe("mqtt/2");

}

}

void loop() { if (!client.connected()) { reconnect(); } client.loop(); }

` this is my code, you can take it for your sketch if you want (i get it from many tutorials including this guy code :P ) what do you say about it ? where is wrong ?

ip works failed connect

vicatcu commented 8 years ago

@panzho if you monitor the traffic coming from your Arduino Ethernet (e.g. using WireShark or something) I bet things would become clear. I would guess wildly that the IP address of your server is wrong - double check it, and try reversing the octets in your sketch.

panzho commented 8 years ago

@vicatcu thanks for your patience i know my english is horrible i dont know how but i change lots of things on my network and my sketch code and now IS WORKING!

this little part of my life... its called happiness xD

pruebadeconexion

i think the problem was that i was trying to connect to a dhcp network but my network is a static one

the code for that is

byte mac[] = { 0x90, 0xA2, 0xDA, 0x0D, 0xDA, 0xA0 }; IPAddress ip(10, 2, 23, 163); IPAddress myDns(10,1,1, 45); IPAddress gateway(10, 2, 23, 254); IPAddress subnet(255, 255, 255, 0); IPAddress server(10, 1, 4, 36);

Ethernet.begin(mac, ip, myDns, gateway, subnet); this if for STATIC ip networks

byte mac[] = { 0x90, 0xA2, 0xDA, 0x0D, 0xDA, 0xA0 }; byte ip[]{10, 2, 23, 163};

ethernet.begin(mac,ip); this one is for DHCP networks ethernet.begin(mac); this one for dhcp networks too

amineBenguesmia commented 7 years ago

@panzho i have the same problem u had and i am running my broker on a raspberry pi how can i solve it i am very new to this so can u take it step by step

chenirl commented 7 years ago

Dont Use: byte server[] = { 10,1,4,36 };

USE: IPAddress server(10, 1, 4, 36);

IN: client.setServer(server, 1883);

Worked for me.

hotkeymuc commented 7 years ago

This seems to be a common problem when using ESP8266 + Mosquitto broker.

I also had a perfectly working set-up with multiple ESPs and they suddenly started showing the same "failed rc=-2" error (WifiClient can not connect to the broker) out of nowhere. Once this error starts showing, there is seemingly no way to recover. I even tried different MQTT libraries and ESP platforms.

The solution is very unexpected but simple:

Explicitly add a

WiFi.mode(WIFI_STA);

before

Wifi.connect(....);

I could not believe it myself. But it actually fixed the problem across ALL my MQT sensors. There simply seems to be an invalid state of the network stack that prevents PubSub's WifiClient to connect.

knolleary commented 7 years ago

@hotkeymuc interesting - good discovery thanks. Need to find somewhere to capture this as I'm sure it'll come up!

vanThijs commented 6 years ago

@knolleary Please add hotkeymuc's solution somewhere visible (in the (esp8266/32) examples perhaps?)! I ran into the same issue with the ESP32, and after hours of debugging found this thread. My problem was solved instantly.

new-developers commented 6 years ago

nice job, that solved my problem too.

I add the command
WiFi.mode(WIFI_STA);

just before
if (client.connect(..................)) {

and it did the job. Now, it is working like a charm !!!!!!

Thanks

apanasara commented 5 years ago
#include <ESP8266WiFi.h>
#include <PubSubClient.h>

// Update these with values suitable for your network.
#define WIFI_SSID "Home"
#define WIFI_PASS "testing1"
IPAddress server(198, 162, 43, 27);
String s = "";

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i=0;i<length;i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();
}

WiFiClient ethClient;
PubSubClient client(ethClient);

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
     WiFi.mode(WIFI_STA);//added here
    if (client.connect("NodeMCU")) {
      Serial.println("connected");
      // Once connected, publish an announcement...
      client.publish("test/topic","hello world");
      // ... and resubscribe
      client.subscribe("test/inTopic");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

void WiFi_Connect(){
 WiFi.mode(WIFI_STA); //added here
  WiFi.begin(WIFI_SSID, WIFI_PASS);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println(s+" connected with IP: "+WiFi.localIP());
}
void setup()
{

  Serial.begin(9600);
  delay(5000);
  Serial.println("Setup");
  Serial.println("Setserver "+server);
  client.setServer(server, 1883);
  Serial.println("Setcallback");
  client.setCallback(callback);

  WiFi_Connect();
  // Allow the hardware to sort itself out
  delay(1500);
}

void loop()
{
  Serial.println("Loop");

  if (!client.connected()) {
    Serial.println("Reconnect");
    reconnect();
  }
  client.loop();
}

Console response Setup  Setcallback ....... connected with IP: 1703520448 Loop Reconnect Attempting MQTT connection...failed, rc=-2 try again in 5 seconds Attempting MQTT connection...failed, rc=-2 try again in 5 seconds

still facing issue after adding WiFi.mode(WIFI_STA);

Bracketmounts commented 4 years ago

@knolleary I've just got involved with ESP and had the same issue with connecting to the MQTT server. I was using Mosquitto on the local machine. Cloud MQTT was working fine as was Mos testing server.

I thought I might have needed to somehow 'register' topics before I subcribed to them as I am new to all things IoT. I was trying AT Command Tester and bunch of other things trying to track the issue. I spent far too long trying to track down info for this without realizing I shouldn't be using "127.0.0.1" or "Localhost" on port 1883 but that I should be using the IP of the local machine.

I'd be willing wager a fizzy drink that there are more than a few people who receive the -2 error have the same issue.

const char* ssid = "********";                          //put your wifi ssid here
const char* password = "********";                         //put your wifi password here.
const char* mqtt_server = "192.168.0.1";         //const char* mqtt_server = "add local machine's IP Address here and not 127.0.0.1 or Localhost";
fazy310 commented 3 years ago

I am not able to connect to the mqtt server I have made in Window. localhost with the port 1883. The code is down below. No matter how man times I try. It doesn't connect with the broker.

include // Use this for WiFi instead of Ethernet.h

include

    // WiFi card example

char ssid[] = "Faizan_Qadir"; // your SSID char pass[] = "c8fabbe2"; // your SSID Password char server[] = "localhost"; WiFiClient client; PubSubClient mqttClient(client); // Use this for WiFi instead of EthernetClient void wifi() { delay(100); // Begin WiFi section // Serial.printf("\nConnecting to %s", ssid); WiFi.mode(WIFI_STA); WiFi.begin(ssid, pass); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }

  // print out info about the connection:
 Serial.println("\nConnected to network");
 Serial.println(ssid);
 Serial.print("My IP address is: ");
 Serial.println(WiFi.localIP());             

}

void reconnect() {

// Allow the hardware to sort itself out delay(1500); mqttClient.setServer(server, 1883);

if (mqttClient.connect("myClientID")) { // connection succeeded Serial.println("\nConnected Succeeded"); } else {

   Serial.println("\nFailed");
   mqttClient.state();
// connection failed
// mqttClient.state() will provide more information
// on why it failed.

}

} void setup() { Serial.begin(115200); wifi(); reconnect(); }

            void loop()
            {

mqttClient.loop(); } ![Uploading Capture.PNG…]()

beeboopx commented 2 years ago

nice job, that solved my problem too.

I add the command WiFi.mode(WIFI_STA);

just before if (client.connect(..................)) {

and it did the job. Now, it is working like a charm !!!!!!

Thanks

It's 2022 and this is still the fix. Thanks!

AlfaBravoX commented 2 years ago

same here today. only this works: nodemcu v3

WiFi.mode(WIFI_STA);//added here

Kingwizar commented 7 months ago

hello every one, i have the same problem but I don't know where to add it can comeone help?

#include <WiFiNINA.h>
#include <WiFiUdp.h>
#include <Wire.h>
#include <SparkFunLSM6DS3.h>

/*  You need to go into this file and change this line from:
      #define MQTT_MAX_PACKET_SIZE 128
    to:
      #define MQTT_MAX_PACKET_SIZE 2048
*/
#include <PubSubClient.h>

#include "./sha256.h"
#include "./base64.h"
#include "./parson.h"
#include "./morse_code.h"
#include "./utils.h"

#include "./configure.h"

//Create a instance of class LSM6DS3
LSM6DS3 onboardIMU(SPI_MODE, 30);

bool wifiConnected = false;
bool mqttConnected = false;

String iothubHost;
String deviceId;
String sharedAccessKey;

WiFiSSLClient wifiClient;
PubSubClient *mqtt_client = NULL;

int requestId = 0;
int twinRequestId = -1;

#define TELEMETRY_SEND_INTERVAL 5000  // telemetry data sent every 5 seconds
#define PROPERTY_SEND_INTERVAL  15000 // property data sent every 15 seconds
#define SENSOR_READ_INTERVAL  2500    // read sensors every 2.5 seconds

long lastTelemetryMillis = 0;
long lastPropertyMillis = 0;
long lastSensorReadMillis = 0;

// telemetry data values
enum xyz {X, Y, Z};
float tempValue = 0.0;
float gyroValue[3] = {0.0, 0.0, 0.0};
float accelValue[3] = {0.0, 0.0, 0.0};

// die property value
int dieNumberValue = 1;

// grab the current time from internet time service
unsigned long getNow()
{
    IPAddress address(129, 6, 15, 28); // time.nist.gov NTP server
    const int NTP_PACKET_SIZE = 48;
    byte packetBuffer[NTP_PACKET_SIZE];
    WiFiUDP Udp;
    Udp.begin(2390);

    memset(packetBuffer, 0, NTP_PACKET_SIZE);
    packetBuffer[0] = 0b11100011;     // LI, Version, Mode
    packetBuffer[1] = 0;              // Stratum, or type of clock
    packetBuffer[2] = 6;              // Polling Interval
    packetBuffer[3] = 0xEC;           // Peer Clock Precision
    packetBuffer[12]  = 49;
    packetBuffer[13]  = 0x4E;
    packetBuffer[14]  = 49;
    packetBuffer[15]  = 52;
    Udp.beginPacket(address, 123);
    Udp.write(packetBuffer, NTP_PACKET_SIZE);
    Udp.endPacket();

    // wait to see if a reply is available
    int waitCount = 0;
    while (waitCount < 20) {
        delay(500);
        waitCount++;
        if (Udp.parsePacket() ) {
            Udp.read(packetBuffer, NTP_PACKET_SIZE);
            unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
            unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
            unsigned long secsSince1900 = highWord << 16 | lowWord;

            Udp.stop();
            return (secsSince1900 - 2208988800UL);
        }
    }
    return 0;
}

// IoT Hub MQTT publish topics
static const char IOT_EVENT_TOPIC[] = "devices/{device_id}/messages/events/";
static const char IOT_TWIN_REPORTED_PROPERTY[] = "$iothub/twin/PATCH/properties/reported/?$rid={request_id}";
static const char IOT_TWIN_REQUEST_TWIN_TOPIC[] = "$iothub/twin/GET/?$rid={request_id}";
static const char IOT_DIRECT_METHOD_RESPONSE_TOPIC[] = "$iothub/methods/res/{status}/?$rid={request_id}";

// IoT Hub MQTT subscribe topics
static const char IOT_TWIN_RESULT_TOPIC[] = "$iothub/twin/res/#";
static const char IOT_TWIN_DESIRED_PATCH_TOPIC[] = "$iothub/twin/PATCH/properties/desired/#";
static const char IOT_C2D_TOPIC[] = "devices/{device_id}/messages/devicebound/#";
static const char IOT_DIRECT_MESSAGE_TOPIC[] = "$iothub/methods/POST/#";

// split the connection string into it's composite pieces
void splitConnectionString() {
    String connStr = (String)iotConnStr;
    int hostIndex = connStr.indexOf("HostName=");
    int deviceIdIndex = connStr.indexOf(F(";DeviceId="));
    int sharedAccessKeyIndex = connStr.indexOf(";SharedAccessKey=");
    iothubHost = connStr.substring(hostIndex + 9, deviceIdIndex);
    deviceId = connStr.substring(deviceIdIndex + 10, sharedAccessKeyIndex);
    sharedAccessKey = connStr.substring(sharedAccessKeyIndex + 17);
}

// acknowledge the receipt of a setting back to Azure IoT Central (makes the setting status turn green)
void acknowledgeSetting(const char* propertyKey, const char* propertyValue, int version) {
        // for IoT Central need to return acknowledgement
        const static char* responseTemplate = "{\"%s\":{\"value\":%s,\"statusCode\":%d,\"status\":\"%s\",\"desiredVersion\":%d}}";
        char payload[1024];
        sprintf(payload, responseTemplate, propertyKey, propertyValue, 200, "completed", version);
        Serial.println(payload);
        String topic = (String)IOT_TWIN_REPORTED_PROPERTY;
        char buff[20];
        topic.replace("{request_id}", itoa(requestId, buff, 10));
        mqtt_client->publish(topic.c_str(), payload);
        requestId++;
}

// process direct method requests
void handleDirectMethod(String topicStr, String payloadStr) {
    String msgId = topicStr.substring(topicStr.indexOf("$RID=") + 5);
    String methodName = topicStr.substring(topicStr.indexOf("$IOTHUB/METHODS/POST/") + 21, topicStr.indexOf("/?$"));
    Serial_printf("Direct method call:\n\tMethod Name: %s\n\tParameters: %s\n", methodName.c_str(), payloadStr.c_str());
    if (strcmp(methodName.c_str(), "ECHO") == 0) {
        // acknowledge receipt of the command
        String response_topic = (String)IOT_DIRECT_METHOD_RESPONSE_TOPIC;
        char buff[20];
        response_topic.replace("{request_id}", msgId);
        response_topic.replace("{status}", "200");  //OK
        mqtt_client->publish(response_topic.c_str(), "");

        // output the message as morse code
        JSON_Value *root_value = json_parse_string(payloadStr.c_str());
        JSON_Object *root_obj = json_value_get_object(root_value);
        const char* msg = json_object_get_string(root_obj, "displayedValue");
        morse_encodeAndFlash(msg);
        json_value_free(root_value);
    }
}

// process Cloud to Device (C2D) requests
void handleCloud2DeviceMessage(String topicStr, String payloadStr) {
    Serial_printf("Twin property change:\n\tPayload: %s\n", payloadStr.c_str());
}

// process twin property (settings in IoT Central language) changes
void handleTwinPropertyChange(String topicStr, String payloadStr) {
    // read the property values sent using JSON parser
    JSON_Value *root_value = json_parse_string(payloadStr.c_str());
    JSON_Object *root_obj = json_value_get_object(root_value);
    const char* propertyKey = json_object_get_name(root_obj, 0);
    double propertyValue;
    double version;
    if (strcmp(propertyKey, "fanSpeed") == 0) {
        JSON_Object* valObj = json_object_get_object(root_obj, propertyKey);
        propertyValue = json_object_get_number(valObj, "value");
        version = json_object_get_number(root_obj, "$version");
        char propertyValueStr[8];
        itoa(propertyValue, propertyValueStr, 10);
        Serial_printf("Fan Speed setting change received with value: %s\n", propertyValueStr);
        acknowledgeSetting(propertyKey, propertyValueStr, version);
    }
    json_value_free(root_value);
}

// callback for MQTT subscriptions
void callback(char* topic, byte* payload, unsigned int length) {
    String topicStr = (String)topic;
    topicStr.toUpperCase();
    payload[length] = '\0';
    String payloadStr = (String)((char*)payload);

    if (topicStr.startsWith("$IOTHUB/METHODS/POST/")) { // direct method callback
        handleDirectMethod(topicStr, payloadStr);
    } else if (topicStr.indexOf("/MESSAGES/DEVICEBOUND/") > -1) { // cloud to device message
        handleCloud2DeviceMessage(topicStr, payloadStr);
    } else if (topicStr.startsWith("$IOTHUB/TWIN/PATCH/PROPERTIES/DESIRED")) {  // digital twin desired property change
        handleTwinPropertyChange(topicStr, payloadStr);
    } else if (topicStr.startsWith("$IOTHUB/TWIN/RES")) { // digital twin response
        int result = atoi(topicStr.substring(topicStr.indexOf("/RES/") + 5, topicStr.indexOf("/?$")).c_str());
        int msgId = atoi(topicStr.substring(topicStr.indexOf("$RID=") + 5, topicStr.indexOf("$VERSION=") - 1).c_str());
        if (msgId == twinRequestId) {
            // twin request processing
            twinRequestId = -1;
            // output limited to 512 bytes so this output may be truncated
            Serial_printf("Current state of device twin:\n%s", payloadStr.c_str());
            if (length > 512)
                Serial.println(" ...");
            else
                Serial.println();
        } else {
            if (result >= 200 && result < 300) {
                Serial_printf("--> IoT Hub acknowledges successful receipt of twin property: %d\n", msgId);
            } else {
                Serial_printf("--> IoT Hub could not process twin property: %d, error: %d\n", msgId, result);
            }
        }
    } else { // unknown message
        Serial_printf("Unknown message arrived [%s]\nPayload contains: %s", topic, payloadStr.c_str());
    }
}

// connect to Azure IoT Hub via MQTT
void connectMQTT(String deviceId, String username, String password) {
    mqtt_client->disconnect();

    Serial.println("Starting IoT Hub connection");
    int retry = 0;
    while(retry < 10 && !mqtt_client->connected()) {     
        if (mqtt_client->connect(deviceId.c_str(), username.c_str(), password.c_str())) {
                Serial.println("===> mqtt connected");
                mqttConnected = true;
        } else {
            Serial.print("---> mqtt failed, rc=");
            Serial.println(mqtt_client->state());
            delay(2000);
            retry++;
        }
    }
}

// create an IoT Hub SAS token for authentication
String createIotHubSASToken(char *key, String url, long expire){
    url.toLowerCase();
    String stringToSign = url + "\n" + String(expire);
    int keyLength = strlen(key);

    int decodedKeyLength = base64_dec_len(key, keyLength);
    char decodedKey[decodedKeyLength];

    base64_decode(decodedKey, key, keyLength);

    Sha256 *sha256 = new Sha256();
    sha256->initHmac((const uint8_t*)decodedKey, (size_t)decodedKeyLength);
    sha256->print(stringToSign);
    char* sign = (char*) sha256->resultHmac();
    int encodedSignLen = base64_enc_len(HASH_LENGTH);
    char encodedSign[encodedSignLen];
    base64_encode(encodedSign, sign, HASH_LENGTH);
    delete(sha256);

    return "SharedAccessSignature sr=" + url + "&sig=" + urlEncode((const char*)encodedSign) + "&se=" + String(expire);
}

// reads the value from the onboard LSM6DS3 sensor
void readSensors() {
    // random die roll
    dieNumberValue = random(1, 7);

    // read LSM6DS3 sensor values
    tempValue = onboardIMU.readTempC();
    accelValue[X] = onboardIMU.readRawAccelX();
    accelValue[Y] = onboardIMU.readRawAccelY();
    accelValue[Z] = onboardIMU.readRawAccelZ();
    gyroValue[X] = onboardIMU.readRawGyroX();
    gyroValue[Y] = onboardIMU.readRawGyroY();
    gyroValue[Z] = onboardIMU.readRawGyroZ();
}

// arduino setup function called once at device startup
void setup()
{
    Serial.begin(115200);

    if( onboardIMU.begin() != 0 ) {
        Serial.println("Error initializing the on device IMU");
    }

    // attempt to connect to Wifi network:
    Serial.print("WiFi Firmware version is ");
    Serial.println(WiFi.firmwareVersion());
    int status = WL_IDLE_STATUS;
    Serial_printf("Attempting to connect to Wi-Fi SSID: %s ", wifi_ssid);

    status = WiFi.begin(wifi_ssid, wifi_password);
    while ( status != WL_CONNECTED) {
        Serial.print(".");
        delay(1000);
    }
    Serial.println();

    splitConnectionString();

    // create SAS token and user name for connecting to MQTT broker
    String url = iothubHost + urlEncode(String("/devices/" + deviceId).c_str());
    char *devKey = (char *)sharedAccessKey.c_str();
    long expire = getNow() + 864000;
    String sasToken = createIotHubSASToken(devKey, url, expire);
    String username = iothubHost + "/" + deviceId + "/api-version=2016-11-14";

    // connect to the IoT Hub MQTT broker
    wifiClient.connect(iothubHost.c_str(), 8883);
    mqtt_client = new PubSubClient(iothubHost.c_str(), 8883, wifiClient);
    connectMQTT(deviceId, username, sasToken);
    mqtt_client->setCallback(callback);

    // // add subscriptions
    mqtt_client->subscribe(IOT_TWIN_RESULT_TOPIC);  // twin results
    mqtt_client->subscribe(IOT_TWIN_DESIRED_PATCH_TOPIC);  // twin desired properties
    String c2dMessageTopic = IOT_C2D_TOPIC;
    c2dMessageTopic.replace("{device_id}", deviceId);
    mqtt_client->subscribe(c2dMessageTopic.c_str());  // cloud to device messages
    mqtt_client->subscribe(IOT_DIRECT_MESSAGE_TOPIC); // direct messages

    // request full digital twin update
    String topic = (String)IOT_TWIN_REQUEST_TWIN_TOPIC;
    char buff[20];
    topic.replace("{request_id}", itoa(requestId, buff, 10));
    twinRequestId = requestId;
    requestId++;
    mqtt_client->publish(topic.c_str(), "");

    // initialize timers
    lastTelemetryMillis = millis();
    lastPropertyMillis = millis();
}

// arduino message loop - do not do anything in here that will block the loop
void loop()
{
    if (mqtt_client->connected()) {
        // give the MQTT handler time to do it's thing
        mqtt_client->loop();

        // read the sensor values
        if (millis() - lastSensorReadMillis > SENSOR_READ_INTERVAL) {
            readSensors();
            lastSensorReadMillis = millis();
        }

        // send telemetry values every 5 seconds
        if (millis() - lastTelemetryMillis > TELEMETRY_SEND_INTERVAL) {
            Serial.println("Sending telemetry ...");
            String topic = (String)IOT_EVENT_TOPIC;
            topic.replace("{device_id}", deviceId);
            //char buff[10];
            String payload = "{\"temp\": {temp}, \"accelerometerX\": {accelerometerX}, \"accelerometerY\": {accelerometerY}, \"accelerometerZ\": {accelerometerZ}, \"gyroscopeX\": {gyroscopeX}, \"gyroscopeY\": {gyroscopeY}, \"gyroscopeZ\": {gyroscopeZ}}";
            payload.replace("{temp}", String(tempValue));
            payload.replace("{accelerometerX}", String(accelValue[X]));
            payload.replace("{accelerometerY}", String(accelValue[Y]));
            payload.replace("{accelerometerZ}", String(accelValue[Z]));
            payload.replace("{gyroscopeX}", String(gyroValue[X]));
            payload.replace("{gyroscopeY}", String(gyroValue[Y]));
            payload.replace("{gyroscopeZ}", String(gyroValue[Z]));
            Serial_printf("\t%s\n", payload.c_str());
            mqtt_client->publish(topic.c_str(), payload.c_str());

            lastTelemetryMillis = millis();
        }

        // send a property update every 15 seconds
        if (millis() - lastPropertyMillis > PROPERTY_SEND_INTERVAL) {
            Serial.println("Sending digital twin property ...");

            String topic = (String)IOT_TWIN_REPORTED_PROPERTY;
            char buff[20];
            topic.replace("{request_id}", itoa(requestId, buff, 10));
            String payload = "{\"dieNumber\": {dieNumberValue}}";
            payload.replace("{dieNumberValue}", itoa(dieNumberValue, buff, 10));

            mqtt_client->publish(topic.c_str(), payload.c_str());
            requestId++;

            lastPropertyMillis = millis();
        }
    }
}
Chandramouli-at commented 4 months ago

This seems to be a common problem when using ESP8266 + Mosquitto broker.

I also had a perfectly working set-up with multiple ESPs and they suddenly started showing the same "failed rc=-2" error (WifiClient can not connect to the broker) out of nowhere. Once this error starts showing, there is seemingly no way to recover. I even tried different MQTT libraries and ESP platforms.

The solution is very unexpected but simple:

Explicitly add a

WiFi.mode(WIFI_STA);

before

Wifi.connect(....);

I could not believe it myself. But it actually fixed the problem across ALL my MQT sensors. There simply seems to be an invalid state of the network stack that prevents PubSub's WifiClient to connect.

Hi,

In my code, I added the line Wifi.mode(WIFI_STA);

But Same error persists. My MQTT server is actively running on port 1883. And Also I connected to the wifi.

This is my code:

#include <ESP8266WiFi.h>
#include <PubSubClient.h>

const char* ssid = "test";
const char* password = "test123";

// MQTT broker credentials (set to NULL if not required)
const char* MQTT_username = "root";
const char* MQTT_password = "toor";

const char* mqtt_server = "192.168.1.106";

WiFiClient espClient;
PubSubClient client(espClient);

long now = millis();
long lastMeasure = 0;

void setup_wifi() {
  delay(10);
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("WiFi connected - ESP IP address: ");
  Serial.println(WiFi.localIP());
}

void callback(String topic, byte* message, unsigned int length) {
  Serial.print("Message arrived on topic: ");
  Serial.print(topic);
  Serial.print(". Message: ");
  String messageTemp;

  for (int i = 0; i < length; i++) {
    Serial.print((char)message[i]);
    messageTemp += (char)message[i];
  }
  Serial.println();

  if (topic == "esp32/output") {
    Serial.print("Changing LED to ");
    if (messageTemp == "on") {
      digitalWrite(LED_BUILTIN, HIGH);
      Serial.print("On");
    } else if (messageTemp == "off") {
      digitalWrite(LED_BUILTIN, LOW);
      Serial.print("Off");
    }
  }
  Serial.println();
}

void reconnect() {
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");

    WiFi.mode(WIFI_STA);
    if (client.connect("ESP8266Client", MQTT_username, MQTT_password)) {
      Serial.println("connected");
      // Subscribe or resubscribe to a topic
      client.subscribe("esp32/output");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

long randomNumber;

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  WiFi.mode(WIFI_STA);

  Serial.begin(9600);
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
  randomSeed(analogRead(0));
}

void loop() {
  if (!client.connected()) {
    reconnect();
  }
  if (!client.loop()) {
    WiFi.mode(WIFI_STA);
    client.connect("ESP8266Client", MQTT_username, MQTT_password);
  }

  now = millis();
  if (now - lastMeasure > 30000) {
    lastMeasure = now;

    randomNumber = random(100);
    client.publish("esp32/random", String(randomNumber).c_str());
    Serial.println("Random Number");
    Serial.print(randomNumber);
  }
}

Kindly help me resolve this issue. Thanks in advance!