Subscribe to MQTT Topic ESP32

Hi peeps,

i have the following setup:
First:
ESP32 (D1 Mini NodeMCU WiFi Modul) with an Potentiometer. If i turn the Poti, a variable changes between 0-100 and gets published via MQTT to a Broker on the Topic "remoteServo/PotiValue". That is running on my Homeassistant server.It is working fine, if i turn the Poti, the value changes.

Here a picture of my Homeassistant Server, if i listen to this topic:
grafik

Second:
A second ESP32 with which i want to receive the value published on the Topic "remoteServo/PotiValue". I tried it witht he following Code, but i do not get the value that i publish with the first ESP. I looked at about a dozen diffenent examples online, but it seems like there is a thinking error. Can someone tell me what i did wrong?

#include "OTA.h"
#include <credentials.h>
#include <WiFi.h>
#include <PubSubClient.h>

String clientId = "ESP32-Nr1";

#define inTopic "remoteServo/PotiValue"


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++) {
    String message = message + (char) payload[i];  // convert *byte to string
    Serial.print(message);
  }
  Serial.println();
}

WiFiClient espClient;
PubSubClient client(myMQTTSERVER, 1883, callback, espClient);

long lastMsg;

void setup() {
  delay(100);
  Serial.begin(115200);
  while (!Serial);

  // We start by connecting to a WiFi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(mySSID);

  WiFi.begin(mySSID, myPASSWORD);

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

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

  client.setServer(myMQTTSERVER, 1883);
  client.subscribe(inTopic);
  client.setCallback(callback);

}

void loop() {

  ArduinoOTA.handle();
  if (!client.connected()) {
    reconnect();
  }
  
  long now = millis();
  if (now - lastMsg > 5000) {
    Serial.println("Send new Data");
    lastMsg = now;
    delay(1000);
  
  }
  
}

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Create a random client ID
    clientId += String(random(0xffff), HEX);
    // Attempt to connect
    if (client.connect(clientId.c_str(), mqtt_user, mqtt_password)) {
      Serial.println("connected");
      client.subscribe(inTopic);
      Serial.println("Subscribed to topic: inTopic");

    } else {
      Serial.print("failed, rc=");
      Serial.println(client.state());
      delay(5000);
    }
  }
}

Hi!

What's the output on serial monitor for this second device when the message is published?

What's the client ID used for the first device?

Best regards.

Here is some code that I use to run client.loop(). If client.loop() is not run then receiving a publication will not happen.

/*
  Important to not set vTaskDelay/vTaskDelayUntil to less then 10. Errors begin to develop with the MQTT and network connection.
  makes the initial wifi/mqtt connection and works to keeps those connections open.
*/
void MQTTkeepalive( void *pvParameters )
{
  sema_MQTT_KeepAlive   = xSemaphoreCreateBinary();
  xSemaphoreGive( sema_MQTT_KeepAlive ); // found keep alive can mess with a publish, stop keep alive during publish
  MQTTclient.setKeepAlive( 90 ); // setting keep alive to 90 seconds makes for a very reliable connection, must be set before the 1st connection is made.
  TickType_t xLastWakeTime = xTaskGetTickCount();
  const TickType_t xFrequency = 250; //delay for ms
  for (;;)
  {
    //check for a is-connected and if the WiFi 'thinks' its connected, found checking on both is more realible than just a single check
    if ( (wifiClient.connected()) && (WiFi.status() == WL_CONNECTED) )
    {
      xSemaphoreTake( sema_MQTT_KeepAlive, portMAX_DELAY ); // whiles MQTTlient.loop() is running no other mqtt operations should be in process
      MQTTclient.loop();
      xSemaphoreGive( sema_MQTT_KeepAlive );
    }
    else {
      log_i( "MQTT keep alive found MQTT status % s WiFi status % s", String(wifiClient.connected()), String(WiFi.status()) );
      if ( !(wifiClient.connected()) || !(WiFi.status() == WL_CONNECTED) )
      {
        connectToWiFi();
      }
      connectToMQTT();
    }
    //log_i( " high watermark % d",  uxTaskGetStackHighWaterMark( NULL ) );
    xLastWakeTime = xTaskGetTickCount();
    vTaskDelayUntil( &xLastWakeTime, xFrequency );
  }
  vTaskDelete ( NULL );
}

First Question:

On the Serial Monitor i only get:

Send new Data
Send new Data
Send new Data

So it seems like, it never reaches the "void callback" function. If i subsribe via client.subscribe(inTopic); , shouldnt this function be called if i a new value is published? Or do i have to call the callback function manually? Could it have something to do with the "Retain:false" flag of the published value?

Second Question:

The clientId for the ESP32 who publishes the Data is:

String clientId = "ESP32-Nr4";

So publish ESP32 has ESP32-Nr4, the subscribe ESP32 has ESP32-Nr1

Try this on your second device:

void loop() 
{
  ArduinoOTA.handle();

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

  client.loop();
}

About retained message check this blog.

The function assumes a proper WiFi connection. If WiFi is not connected will the client ever connect to the MQTT Broker?

If WiFi is not connected during the setup the process will stop in this while loop.

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

If the connection is lost after the setup the process will stay in this condition:

else {
      Serial.print("failed, rc=");
      Serial.println(client.state());
      delay(5000);
    }

I'll fix that. But since i get the "Send new Data" message on the output the connection seems to work.

If i use client.loop(); as it was suggested, i get the "Brownout detected" message. Thats also true for different ESP32's

This piece of code doesn't have anything related to MQTT. It's just a leftover.

long now = millis();
  if (now - lastMsg > 5000) {
    Serial.println("Send new Data");
    lastMsg = now;
    delay(1000);
  }

Brownout error means there's no enough power for ESP32.

that would have been useful info in post#1.

Power is the issue.

post a schematic.

post an image of your project.

That is only the case if i use the client.loop();, which i did not do in the beginnng.

There is also no schematic. The 2nd Esp32 that should receive the data of the 1st ESP32 is only plugged in into the PC. Changing the PC port or switching to an external supply does not help. Changing the Esp32 does not help.

The function client.loop is not optional. Check the documentation.

https://pubsubclient.knolleary.net/api#loop

That would have been useful information to have had in post#1.

Try replace the USB cable.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.