ESP32 PubSubClient issues

Good evening,

Currently I am designing system for temperature measuring based on ESP32. I want to use PubSubClient library for maintaining connection with Cayenne cloud. Unfortunately, my attempts to connect with cayenne cloud were unsuccessful. Has anyone succesfully connected to the Cayenne cloud using PubSubClient and could give some advice how to achieve connection? There is no problem with connection to WiFi network. I also attach the code used for connecting to Cayenne.

#include <WiFi.h>
#include <Ethernet.h>
#include <PubSubClient.h>

const char* wifiname = "*************";
const char* wifipass = "*************"; 
const char* mqttserver = "*************";

const char* clientid = "***************";
const char* username = "***************";
const char* password = "***************";

WiFiClient espClient;
PubSubClient client(espClient);

void setup_wifi() 
{
  Serial.print("Establishing connection with: ");
  Serial.println(wifiname);
  Serial.println(wifipass);

  WiFi.begin(wifiname, wifipass);

  while(WiFi.status()!= WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}


void callback(char* topic, byte* payload, unsigned int length)
{
  char message_buffer[length];
  Serial.print("MQTT message on topic[");
  Serial.print(topic);
  Serial.print("]");
  for (int i = 0; i < length; i++)
  {
     message_buffer[i] = (char)payload[i];
     Serial.print((char)payload[i]);

  }
  message_buffer[length] = '\0';

}

void MQTTSetup()
{ 
  client.setServer(mqttserver, 1883);
  client.setCallback(callback);

  client.connect(clientid, username, password);
  Serial.println(client.connected());

  client.loop();

  while(!client.connected())
  {
    Serial.println("waiting...");
    delay(250);
    client.connect(clientid, username, password);
  }
}

void setup()
{
  Serial.begin(115200);
  setup_wifi();
  MQTTSetup();
}

void loop() 
{
}

You just need a client.loop(); in your main loop. Replace with this:

void loop() {
  client.loop();

  delay(100);
}
1 Like

@adam, @shramik_salgaonkar - thank you for your replies. Unfortunately, I am still not able to connect to Cayenne - according to the PubSubClient API documentation, the client is disconnected(client.state() value is -1). Link to the API documentation is here: https://pubsubclient.knolleary.net/api#state

What could be the cause of such strange behaviour? For test purposes, I decided to check connectivity to Cayenne by using Cayenne API library. In this case, I was able to connect without problem. I attach the code after modifications, unfortunately there is still no progress, when it comes to communication by using PubSubClient.

#include <WiFi.h>
#include <Ethernet.h>
#include <PubSubClient.h>

char wifiname[] = "************";
char wifipass[] = "************"; 
char mqttserver[] = "************";

char clientid[] = "**************";
char password[] = "**************";
char username[] = "**************";


WiFiClient espClient;
PubSubClient client(espClient);

void setup_wifi() 
{
   Serial.print("Establishing connection with: ");
   Serial.println(wifiname);
   Serial.println(wifipass);

   WiFi.begin(wifiname, wifipass);

 while(WiFi.status()!= WL_CONNECTED)
 {
    delay(500);
    Serial.print(".");
 }

   Serial.println("");
   Serial.println("WiFi connected");
   Serial.println("IP address: ");
   Serial.println(WiFi.localIP());
}


void callback(char* topic, byte* payload, unsigned int length)
{
  char message_buffer[length];
  Serial.print("MQTT message on topic[");
  Serial.print(topic);
  Serial.print("]");
  for (int i = 0; i < length; i++)
  {
    message_buffer[i] = (char)payload[i];
    Serial.print((char)payload[i]);

  }
  message_buffer[length] = '\0';

}

void MQTTSetup()
{ 
  client.setServer(mqttserver, 1883);
  client.setCallback(callback);

  client.connect(clientid, username, password);
  Serial.println(client.connected());

}

void setup()
{
   Serial.begin(115200);
   setup_wifi();
   MQTTSetup();
}

void loop() 
{
   client.loop();
   Serial.println(client.state());
   delay(1000);
}

Try this code:

#include <WiFi.h>
#include <Ethernet.h>
#include <PubSubClient.h>

const char* wifiname = "************";
const char* wifipass = "************"; 
const char* mqttserver = "************";

const char* clientid = "**************";
const char* password = "**************";
const char* username = "**************";


WiFiClient espClient;
PubSubClient client(espClient);

void setup_wifi() 
{
   Serial.print("Establishing connection with: ");
   Serial.println(wifiname);
   Serial.println(wifipass);

   WiFi.begin(wifiname, wifipass);

 while(WiFi.status()!= WL_CONNECTED)
 {
    delay(500);
    Serial.print(".");
 }

   Serial.println("");
   Serial.println("WiFi connected");
   Serial.println("IP address: ");
   Serial.println(WiFi.localIP());
}


void callback(char* topic, byte* payload, unsigned int length)
{
  char message_buffer[length];
  Serial.print("MQTT message on topic[");
  Serial.print(topic);
  Serial.print("]");
  for (int i = 0; i < length; i++)
  {
    message_buffer[i] = (char)payload[i];
    Serial.print((char)payload[i]);

  }
  message_buffer[length] = '\0';

}

void reconnect()
{ 
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    if (client.connect(clientid, username, password)) {
      Serial.println("connected");
      //client.subscribe("mqtt/topic");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      delay(5000);
    }
  }
}

void setup()
{
   Serial.begin(115200);
   client.setServer(mqttserver, 1883);
   setup_wifi();
}

void loop() 
{
  if (!client.connected()) {
    reconnect();
  }
   client.loop();
   Serial.println(client.state());
   delay(1000);
}

or this one:

// ---------- INLCUDE LIBRARIES ----------

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

// ---------- DEFINE CONSTANT VALUES ----------

#define MQTT_SERVER     "mqtt.mydevices.com"
#define MQTT_SERVERPORT 1883
#define MQTT_USERNAME   ""
#define MQTT_PASSWORD   ""
#define CLIENT_ID       ""

// Define "topic" linked to the Cayenne Dashboard Temperature Gauge (Cayenne Channel 10)
#define MQTT_TOPIC_TPROBE_INT   "v1/" MQTT_USERNAME "/things/" CLIENT_ID "/data/10"


// ---------- INITIALIZE INSTANCES ----------

WiFiClient    espClient;              // Creates a client instance for the PubSubClient
PubSubClient  client(espClient);


// ---------- DEFINE VARIABLES ----------

const   char* ssid        = ""; // WLAN-SSID (WiFi router)
const   char* password    = ""; // WLAN Password


// Define a datatype to store the mqtt message, up to 50 bytes.
char    msg[50];                 // 50 BYTES QUIZAS SEA MUCHO AL GAS, pero bueh


// -------------------- SETUP -------------------

void setup() {

  // Initialize serial monitor for debugging purposes.
  Serial.begin(9600);
  Serial.println("DEBUG: Entering setup ");

  // Attempt to connect to WiFi.
  WiFi.begin(ssid, password);
  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");                       // Faltaria agregar que muestre el ip si no es estatico
  Serial.println("WiFi connected");


  // Initialize Pins
  pinMode(BUILTIN_LED, OUTPUT);       // esp8266's built in led.
  digitalWrite(BUILTIN_LED, !LOW);    // This pin handles inverse logic, it's state is reversed.


  // Initialize MQTT PubSub Library
  client.setServer(MQTT_SERVER, MQTT_SERVERPORT);
  // Function called in case of an incomming mqtt message from Cayenne Dashboard
  // (In this case is the dashboard button to turn on/off the heater)
  client.setCallback(mqttCallback);

  Serial.println("DEBUG: Setup Done! ");

}


long    timeStampNow;
long    timeStampLastMsg = 0;

// -------------------- LOOOP -------------------

void loop() {

  Serial.println("DEBUG: Entering main loop ");

  // Check if the esp8266 is connected to the mqtt server.
  if (!client.connected()) {                            
    reconnect();                                        
  }

  // If connected, perform PubSubClient housekeeping function.
  client.loop();                                        

  // Publish temperature readings every 2 seconds (2000ms)
  timeStampNow = millis();
  if (timeStampNow - timeStampLastMsg > 2000) {    // Publish interval in milliseconds
    // Reset the counter
    timeStampLastMsg = timeStampNow;
    // Jump to the actual function to read and publish temperatures.
    dealWithTemperatures();
  }

  delay(10);
  Serial.println("DEBUG: Reached MAIN LOOP END --> Looping ");
}







// ------------------------------ OTHER FUNCTIONS

// Function that attempts to reconnect to the mqtt server.

void reconnect() {                                  
  // If esp8266 is disconnected from the mqtt server, try to reconnect.
  // (*** I still need to think what wil happen to the boiler if connection is lost ***)
  while (!client.connected()) {
    Serial.print("DEBUG: Attempting MQTT connection...");

    // Attempt to connect
    if (client.connect(CLIENT_ID, MQTT_USERNAME, MQTT_PASSWORD)) {
      Serial.println("connected");
      
      // Once connected, resubscribe to the Dashboard on/off button topic.
     // client.subscribe(MQTT_TOPIC_BTN_ONOFF);

    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
  Serial.println("DEBUG: Quiting reconnect loop ");
}




// Function to intercept MQTT messages

void mqttCallback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    // Show the received message "stream" in the serial monitor.
    Serial.print((char)payload[i]);
  }
  Serial.println();


  // The actual Cayenne mqtt message payload (Actuator Command) consists of:
  // a Sequence Identifier followed by the actual Value (0 = Off, 1 = On)
  // For example: "2otoExGxnMJz0Jn,0". We need the Value that is in "position" number 16.
  if ((char)payload[16] == '0') {

    // We received a 0, so turn built in led off.
    digitalWrite(BUILTIN_LED, !LOW);
    // Publish confirmation that the led was actually turned off, so it is reflected in the dashboard.
    client.publish("v1/" MQTT_USERNAME "/things/" CLIENT_ID "/data/5", "0");
  }

  if ((char)payload[16] == '1') {

    // We received a 1, so turn built in led on.
    digitalWrite(BUILTIN_LED, !HIGH);
    // Publish confirmation that the led was actually turned off, so it is reflected in the dashboard.
    client.publish("v1/" MQTT_USERNAME "/things/" CLIENT_ID "/data/5", "1");
  }

  //  Delay for debugging purposes. If a message arrives from Cayenne, the terminal feed pauses 5'.
  delay(5000);
  
}

float x;
// Function that handles temperature adquisition from sensors, and publishing to Cayenne Dashboard.

void dealWithTemperatures() {
  

  // Get the temperature value of sensor with hex address Probe01
  x = 22.00;

  // Construct the mqtt message following Cayenne's rules, according to the Docs..
  // Send Sensor data -> Topic: v1/username/things/clientID/data/channel  
  // (*** Still need to optimize the use of strings in this part!!! ***)
  String stringOne = "temp,c=";
  
  //using a float rounded to 2 decimal places.
  String stringTwo = String(x, 2);
  
  // Concatenate the two previous strings into mqtt_message.
  String mqtt_message =  String(stringOne + stringTwo);
  Serial.println(mqtt_message);


  // Convert the string into a Char Array
  mqtt_message.toCharArray(msg, 20);
  

  Serial.print("Publish message: ");
  Serial.println(msg);
  // Finally! Publish the temperature to Cayenne Dashboard, Channel 10.
  client.publish(MQTT_TOPIC_TPROBE_INT, msg);

  
}

Another thing you can try is telnet from a computer on the same LAN. Could be your network or ISP are blocking the MQTT connection to Cayenne.

telnet mqtt.mydevices.com 1883

@adam i guess he can connect to cayenne,

1 Like

Only other thing I can think of is if you reuse your clientID it will get disconnected. You have to generate a new clientID for each device.

1 Like