My code keeps saying "mqtt disconnect, error 5"


#1

I am able to run the example code just fine. I am trying to create a device that can broadcast an AP, take in data, store it in EEPROM, and then reboot and connect to Cayenne using that data.
Here is my code:

    #include <LSM9DS1_Registers.h>
#include <LSM9DS1_Types.h>
#include <Wire.h>
#include <SPI.h>
#include <SparkFunLSM9DS1.h>
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <EEPROM.h>
#include <SimpleTimer.h>
#include <ESP8266WiFiMulti.h>


#define CAYENNE_DEBUG
#define CAYENNE_PRINT Serial
#include <CayenneMQTTESP8266.h>

#define EEPROM_BLOCK 32 //32 bytes per chunk of storage

#define LSM9DS1_M  0x1E // Would be 0x1C if SDO_M is LOW
#define LSM9DS1_AG  0x6B // Would be 0x6A if SDO_AG is LOW

#define PRINT_CALCULATED //Print calculated IMU values
#define PRINT_SPEED 50 // 50 ms between prints
#define DECLINATION -8.58 // Declination (degrees) in Boulder, CO.

ESP8266WiFiMulti WiFiMulti;
LSM9DS1 imu; //Construct imu object
SimpleTimer timer; //Construct timer object

void send_data(){ //Send data to Cayenne
  Cayenne.virtualWrite(0,5);
  delay(500);
	//readIMU();
    //printGyro();  // Print "G: gx, gy, gz"
    /*printAccel(); // Print "A: ax, ay, az"
    if((abs(imu.calcAccel(imu.ax)) > 1.60) || (abs(imu.calcAccel(imu.ay)) > 1.60) || (abs(imu.calcAccel(imu.az)) > 1.60)){
      Serial.println("Over");
	  Cayenne.celsiusWrite(3, 2);
      delay(500);
    }
    else{
      delay(500);
    }*/
	
}

const char *ssid = "Falling"; //Local AP SSID
const char *password = "Detector"; //Local AP password

ESP8266WebServer server(80); //Construct server object

//Initialize variables
String ssidEEPROM; //stored as chars in EEPROM from 9 through 9+EEPROM_BLOCK
String passwordEEPROM;
String Cusername;
String Cpassword;
String CclientID;

bool need_credentials;

//See if a local AP is needed
bool check_EEPROM(){
	uint8_t cred_val = EEPROM.read(8);
	Serial.println("\nneed credentials?: ");
	
	if(cred_val==0){
		return true;
    Serial.print("yes\n");
	}
	else{
  Serial.print("no\n");
		return false;
	}
}

//Read EEPROM for SSID
String read_essid(){
	String EEP_ssid;
	for(int i=0; i<EEPROM_BLOCK;i++){
  if(EEPROM.read(i+9) != 0){
			EEP_ssid += char(EEPROM.read(i+9));
     Serial.print(EEPROM.read(i+9));
  }
		}
	return EEP_ssid;
}

//Read EEPROM for wifi password
String read_epass(){
	String EEP_pass;
	for(int i=0; i<EEPROM_BLOCK;i++){
  if(EEPROM.read(i+41) != 0){
		EEP_pass += char(EEPROM.read(i+41));
	}
	}
	return EEP_pass;
}

//Cayenne credentials
//Cayenne credentials are stored in 48 byte chunks
String read_username(){
	String EEP_user;
	for(int i=0; i<48;i++){
  if(EEPROM.read(i+73) != 0){
			EEP_user += char(EEPROM.read(i+73));
		}
	}
	return EEP_user;
}

String read_password(){
	String EEP_password;
	for(int i=0; i<48;i++){
  if(EEPROM.read(i+121) != 0){
			EEP_password += char(EEPROM.read(i+121));
		}
	}
	return EEP_password;
}

String read_clientID(){
	String EEP_clientID;
	for(int i=0; i<48;i++){
  if(EEPROM.read(i+169) != 0){
			EEP_clientID += char(EEPROM.read(i+169));
		}
	}
	return EEP_clientID;
}

unsigned long lastPrint = 0; // Keep track of print time for IMU

//What to do when a client accesses the local webpage
void handleRoot(){
	String msg;
	//Write data to EEPROM if there
	if (server.hasArg("SSID") && server.hasArg("PASSWORD")){
     String qsid = server.arg("SSID");
     String qpass = server.arg("PASSWORD");
     String quser = server.arg("USERNAME");
     String qCpass = server.arg("CPASS");
     String qid = server.arg("ID");
      for(int i=0;i<252;i++){
        EEPROM.write(i,0);
      }
      EEPROM.write(8,1); //Change the need_credential value to 1, making it not need a local AP
	  //Write SSID, wifi password, and Cayenne credentials to EEPROM
		for(int i=0;i<qsid.length();i++){
			EEPROM.write(9+i, qsid[i]);
		}
		for(int i=0;i<qpass.length();i++){
			EEPROM.write(41+i, qpass[i]);
		}
		for(int i=0;i<quser.length();i++){
			EEPROM.write(73+i, quser[i]);
		}
		for(int i=0;i<qCpass.length();i++){
			EEPROM.write(121+i, qCpass[i]);
		}
		for(int i=0;i<qid.length();i++){
			EEPROM.write(169+i, qid[i]);
		}
		
   EEPROM.commit(); //Save changes
   ESP.reset(); //Restart the device
      return;
    }
	//HTML to serve when page is accessed
	String content = "<html><body><form action='/' method='POST'>To add your credentials, please use : Falling/Detector<br>";
  content += "SSID name:<input type='text' name='SSID' placeholder='SSID'><br>";
  content += "Password:<input type='password' name='PASSWORD' placeholder='password'><br>";
  content += "Cayenne username:<input type='text' name='USERNAME' placeholder='username'><br>";
  content += "Cayenne password:<input type='password' name='CPASS' placeholder='Cayenne password'><br>";
  content += "Cayenne client ID:<input type='text' name='ID' placeholder='Cayenne ID'><br>";
  content += "<input type='submit' name='SUBMIT' value='Submit'></form>" + msg + "<br>";
  content += "</body></html>";
  //Send the page to the client
  server.send(200, "text/html", content);
}

void initLocalAP(){ //Initialize the local access point
  Serial.println("Initializing Local AP!");
	WiFi.softAP(ssid, password);
	IPAddress myIP = WiFi.softAPIP();
	Serial.println(myIP); //IP address will always be 192.168.4.1
	server.on("/", handleRoot);
	server.begin();
}

void setup() {
	EEPROM.begin(512); //Begin EEPROM with 512 bytes of memory
	Serial.begin(115200); //Begin Serial with a baud rate of 115200
	need_credentials = check_EEPROM(); //get the boolean value for address 8
	if(need_credentials){ //If you need to start the AP, start it
		initLocalAP();
	}
	else{ //if not, do what's below
	//Read values from EEPROM and pass to variables
		ssidEEPROM = read_essid();
		passwordEEPROM = read_epass();
		Cusername = read_username();
		Cpassword = read_password();
		CclientID = read_clientID();
		//Print the read values
		printCredentials();

	//Convert Strings to char arrays
    char ssid[32];
    char pass[32];
    char user[48];
    char Cpass[48];
    char cID[48];
    ssidEEPROM.toCharArray(ssid, 32);
    passwordEEPROM.toCharArray(pass, 32);
    Cusername.toCharArray(user, 48);
    Cpassword.toCharArray(Cpass, 48);
    CclientID.toCharArray(cID, 48);
    
	Cayenne.begin(user, Cpass, cID, ssid, pass); //Start the Cayenne service
	WiFi.mode(WIFI_STA);
	imu.settings.device.commInterface = IMU_MODE_I2C;
	imu.settings.device.mAddress = LSM9DS1_M;
	imu.settings.device.agAddress = LSM9DS1_AG;
  // The above lines will only take effect AFTER calling
  // imu.begin(), which verifies communication with the IMU
  // and turns it on.
  if (!imu.begin())
  {
    Serial.println("Failed to communicate with LSM9DS1.");
    Serial.println("Double-check wiring.");
    Serial.println("Default settings in this sketch will " \
                  "work for an out of the box LSM9DS1 " \
                  "Breakout, but may need to be modified " \
                  "if the board jumpers are.");
    while (1)
      ;
  }
  timer.setInterval(500L, send_data); //check every 500 milliseconds
	}
}

void loop() {
   if(need_credentials){
   server.handleClient();
  }
else{
Cayenne.loop();
timer.run();
if(Serial.available()>0){ //If 'r' is sent then it resets the data in EEPROM
			char c = Serial.read();
			if(c=='r'){
				EEPROM.write(8,0);
				EEPROM.commit();
				ESP.reset();
			}
		}
}

void readIMU(){
  Serial.println("looped");
 if ( imu.gyroAvailable() )
  {
    // To read from the gyroscope,  first call the
    // readGyro() function. When it exits, it'll update the
    // gx, gy, and gz variables with the most current data.
    imu.readGyro();
  }
  if ( imu.accelAvailable() )
  {
    // To read from the accelerometer, first call the
    // readAccel() function. When it exits, it'll update the
    // ax, ay, and az variables with the most current data.
    imu.readAccel();
  }
  if ( imu.magAvailable() )
  {
    // To read from the magnetometer, first call the
    // readMag() function. When it exits, it'll update the
    // mx, my, and mz variables with the most current data.
    imu.readMag();
  }
}


//Default function for processing actuator commands from the Cayenne Dashboard.
//You can also use functions for specific channels, e.g CAYENNE_IN(1) for channel 1 commands.
CAYENNE_IN_DEFAULT()
{
	CAYENNE_LOG("CAYENNE_IN_DEFAULT(%u) - %s, %s", request.channel, getValue.getId(), getValue.asString());
	//Process message here. If there is an error set an error message using getValue.setError(), e.g getValue.setError("Error message");
}

void printCredentials(){
	Serial.print("SSID: ");
		Serial.print(ssidEEPROM);
		Serial.print(", Wifi Password: ");
		Serial.println(passwordEEPROM);
		Serial.print("Cayenne username: ");
		Serial.println(Cusername);
		Serial.print(". Cayenne password: ");
		Serial.println(Cpassword);
		Serial.print(". Cayenne clientID: ");
		Serial.println(CclientID);
}

void printAccel()
{  
  // Now we can use the ax, ay, and az variables as we please.
  // Either print them as raw ADC values, or calculated in g's.
  Serial.print("A: ");
#ifdef PRINT_CALCULATED
  // If you want to print calculated values, you can use the
  // calcAccel helper function to convert a raw ADC value to
  // g's. Give the function the value that you want to convert.
  Serial.print(imu.calcAccel(imu.ax), 2);
  Serial.print(", ");
  Serial.print(imu.calcAccel(imu.ay), 2);
  Serial.print(", ");
  Serial.print(imu.calcAccel(imu.az), 2);
  Serial.println(" g");
#elif defined PRINT_RAW 
  Serial.print(imu.ax);
  Serial.print(", ");
  Serial.print(imu.ay);
  Serial.print(", ");
  Serial.println(imu.az);
#endif

}

#2

Welcome to the Cayenne community, @gatoninja236. Hello from down the street in Denver :smile:

Is the specific message more like “Disconnected with result code 5” ? If so, code 5 means ‘not authorized’ so the first thing I’d check is that the MQTT Username/Password/Client ID in your code are matching those in the Cayenne dashboard entry, and that there wasn’t a typo or extra character somewhere in there, and that you don’t have another client with the same 3 credentials connected to Cayenne at the same time.


#3

Yeah, I checked. I can upload other sketches and they work just fine with the credentials I specified. I’m wondering why it’s only this sketch that won’t work. The other sketch I used was the example sketch for the Cayenne ESP8266 library. And sometimes the error code is error 2.


#4

Hi again,

We did discover a MQTT connectivity issue yesterday that was resolved on our server side. I’m not sure if it related to what you were seeing here, but it would be worth re-testing since it caused 2 of my Arduinos to display the same ‘result code 5’ error message. In the case of one it was necessary for me to re-upload the code to it to get a clean connection, so I’d advise that as well.

If you’re still seeing the issue, I’d be interested if you also see it with this example client that we provide – just to simplify the problem and see if anything in your specific code changes the behavior – and if you have this issue with even the basic example code. You’ll need to plug some MQTT Username/Password/Client ID credentials into it to connect, of course.