Farhan Ahmed
Farhan Ahmed

Reputation: 11

Can't connect ESP32 to MQTT

I have been trying to connect my ESP32 with HiveMQ MQTT broker url. It connects when I use free public MQTT broker like broker.hivemq.com, but when I use my url which I got after registering in HiveMQ, it doesn't connect. It returns error with code 2.

I have used this MQTT broker url with windows MQTT client app and it works fine but it doesn't work with ESP32.

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

// WiFi
const char *ssid = "********"; // Enter your WiFi name
const char *password = "********";  // Enter WiFi password

// MQTT Broker
const char *mqtt_broker = "591c2cacc87d4e248d106212ae6e0d4f.s2.eu.hivemq.cloud";
const char *topic = "esp32/test";
const char *mqtt_username = "*******";
const char *mqtt_password = "*******";
const int mqtt_port = 8883;

WiFiClient espClient;
PubSubClient client(espClient);

void setup() {
 // Set software serial baud to 115200;
 Serial.begin(115200);
 // connecting to a WiFi network
 WiFi.begin(ssid, password);
 while (WiFi.status() != WL_CONNECTED) {
     delay(500);
     Serial.println("Connecting to WiFi..");
 }
 Serial.println("Connected to the WiFi network");
 //connecting to a mqtt broker
 client.setServer(mqtt_broker, mqtt_port);
 client.setCallback(callback);
 while (!client.connected()) {
     String client_id = "esp32-client-";
     client_id += String(WiFi.macAddress());
     Serial.printf("The client %s connects to the public mqtt broker\n", client_id.c_str());
     if (client.connect(client_id.c_str(), mqtt_username, mqtt_password)) {
         Serial.println("Public emqx mqtt broker connected");
     } else {
         Serial.print("failed with state ");
         Serial.print(client.state());
         delay(2000);
     }
 }
 // publish and subscribe
 client.publish(topic, "Hi EMQ X I'm ESP32 ^^");
 client.subscribe(topic);
}

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

void loop() {
 client.loop();
}

Upvotes: 0

Views: 4054

Answers (2)

jobrien9
jobrien9

Reputation: 147

Using a combination of Farhan's example and a few other examples I found elsewhere, I was able to get this to work.

  1. First, open a terminal run the command from Johnny Boy's answer (This assumes you have openssl installed. If not, install it.

openssl s_client -connect YOUR_URL.hivemq.cloud:8883 -showcerts

  1. You'll get three certificates. They look like this

-----BEGIN CERTIFICATE----- MIIFYDCCBEigAwIBAgIQQAF3ITfU6UK47naqPGQKtzANBgkqhkiG9w0BAQsFADA/ MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT DkRTVCBSb290IENBIFgzMB4XDTIxMDEyMDE5MTQwM1oXDTI0MDkzMDE4MTQwM1ow ...Lots more characters that I'll omit for brevity... -----END CERTIFICATE-----

  1. The third certificate is the one you want. Copy this certificate out of your terminal (including the BEGIN and END CERTIFICATE parts). Paste the cert into your ESP32 code as a const char variable, such as:

const char *ROOT_CERT = "-----BEGIN CERTIFICATE-----\n"
"MIIFYDCCBEigAwIBAgIQQAF3ITfU6UK47naqPGQKtzANBgkqhkiG9w0BAQsFADA/\n"
"MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\n"
... etc..

  1. Using the WiFiClientSecure library mentioned in the comments, use the setCACert function to utilize your certificate. The rest of the code looks pretty close to what Farhan had. In my example, a few of the variables, including the ROOT_CERT variable from above, were defined in another file (WifiCredentials.h):

    #include <PubSubClient.h>
    #include <WiFi.h>
    #include <WiFiClient.h>
    #include <WiFiServer.h>
    #include <WiFiUdp.h>
    #include "WifiCredentials.h"
    #include <WiFiClientSecure.h>
    
    *********/
    Helpful  References: 
       * https://randomnerdtutorials.com/esp32-web-server-arduino-ide/
       * 
    *********/
    
    WiFiClientSecure wifiClient;
    PubSubClient mqttClient(wifiClient); 
    char *mqttServer = "YOUR_URL.hivemq.cloud";
    int mqttPort = 8883;
    const char *mqtt_password = "password_I_setup_at_hivemq";
    const char *mqtt_username = "username_I-setup_at_hivemq";
    
    void setup() {
      Serial.begin(9600);
    
      // Connect to Wi-Fi network
      Serial.print("Connecting to ");
      Serial.println(WifiSSID);
      WiFi.begin(WifiSSID, WifiPassword);
      while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.println("...Still Connecting");
      }
    
      Serial.println("");
      Serial.println("WiFi connected.");
    
    
      wifiClient.setCACert(ROOT_CERT);
    }
    
    void loop(){
      if (!mqttClient.connected()) {    
        mqttClient.setServer(mqttServer, mqttPort);
        // set the callback function
        mqttClient.setCallback(callback);
        Serial.println("Connecting to MQTT Broker...");
        while (!mqttClient.connected()) {
          Serial.println("Reconnecting to MQTT Broker..");
          String clientId = "ESP32Client-";
          clientId += String(random(0xffff), HEX);
    
          if (mqttClient.connect(clientId.c_str(), mqtt_username, mqtt_password)) {
             Serial.println("Connected to MQTT BRoker!.");
             // subscribe to topic
             mqttClient.subscribe("/transactions/device1");
             mqttClient.publish("/transactions/device1", "testing hello");
          } else {
              Serial.print("failed with state ");
              Serial.print(mqttClient.state());
              delay(2000);
          }
         }
       }
       mqttClient.loop();
    }
    
    void callback(char* topic, byte* payload, unsigned int length) {
      Serial.print("Callback - ");
      Serial.print("Message:");
      for (int i = 0; i < length; i++) {
        Serial.print((char)payload[i]);
      }
    }
    
  2. Connect a tool like MQTT Dash to your HiveMQ instance, open a serial monitor, and test your code.

Upvotes: 1

Johnny Boy
Johnny Boy

Reputation: 1

In the comments, @hcheung said:

When you use MQTT over TLS (port 8883), you need to use WiFiClientSecure.h and add the root CA of broker.hivemq.com to your sketch. Refer to WiFiClientSecure on how to do it.

You can get the root CA of your HiveMQ broker with the following OpenSSL method:

openssl s_client -connect hivemq-broker-host:8883 -showcerts

Change hivemq-broker-host with your MQTT host.

Upvotes: 0

Related Questions