Problem with setting "client.setCallback(callback)"

Hello.

This is my first post here, so I will take this opportunity to say hello to everyone.

I’m trying to control a relay connected to the ESP32 dev board using MQTT trigger.

I modified this example to work for my needs: Link

Unfortunately there is a problem with my board and it only reconnect to the WIFI every other time. Apparently this is a known issue and as there is not fix yet I decide to use a workaround which I found here: Link

Now the fun begins.
Both codes work separately, but how to make them work together?

As the ESP32 is a dual core board I found this code, which allows to assign task to the core:

Code

I tried to merge all 3 together, but i’m getting “‘callback’ was not declared in this scope” error.

My code:

#include <WiFi.h>
#include <PubSubClient.h>
#include <Wire.h>
const char* ssid = "XXX";
const char* password = "XXX";
// Add your MQTT Broker IP address
const char* mqtt_server = "XXX";
WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
char msg[50];
int value = 0;
// relay Pin
const int relayPin = 4;
TaskHandle_t Task1;
TaskHandle_t Task2;


void setup() {
  Serial.begin(115200);
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
  pinMode(relayPin, OUTPUT);

  //create a task that will be executed in the myWiFiTask() function, with priority 1 and executed on core 0
  xTaskCreatePinnedToCore(
                    myWiFiTask,   /* Task function. */
                    "Task1",     /* name of task. */
                    10000,       /* Stack size of task */
                    NULL,        /* parameter of the task */
                    1,           /* priority of the task */
                    &Task1,      /* Task handle to keep track of created task */
                    0);          /* pin task to core 0 */                  
  delay(500); 

  //create a task that will be executed in the MQTT() function, with priority 1 and executed on core 1
  xTaskCreatePinnedToCore(
                    mqtt,   /* Task function. */
                    "Task2",     /* name of task. */
                    10000,       /* Stack size of task */
                    NULL,        /* parameter of the task */
                    1,           /* priority of the task */
                    &Task2,      /* Task handle to keep track of created task */
                    1);          /* pin task to core 1 */
    delay(500); 
}

//myWiFiTask:
bool myWiFiFirstConnect = true;

void myWiFiTask(void *pvParameters) {
  wl_status_t state;

  while (true) {
    state = WiFi.status();
    if (state != WL_CONNECTED) {  // We have no connection
      if (state == WL_NO_SHIELD) {  // WiFi.begin wasn't called yet
        Serial.println("Connecting WiFi");

        WiFi.mode(WIFI_STA);
        WiFi.begin(ssid, password);

      } else if (state == WL_CONNECT_FAILED) {  // WiFi.begin has failed (AUTH_FAIL)
        Serial.println("Disconnecting WiFi");

        WiFi.disconnect(true);

      } else if (state == WL_DISCONNECTED) {  // WiFi.disconnect was done or Router.WiFi got out of range
        if (!myWiFiFirstConnect) {  // Report only once
          myWiFiFirstConnect = true;

          Serial.println("WiFi disconnected");
        }
      }

      vTaskDelay (250); // Check again in about 250ms

    } else { // We have connection
      if (myWiFiFirstConnect) {  // Report only once
        myWiFiFirstConnect = false;

        Serial.print("Connected to ");
        Serial.println(ssid);
        Serial.print("IP address: ");
        Serial.println(WiFi.localIP());
        Serial.println("");
      }

      vTaskDelay (5000); // Check again in about 5s
    }
  }
}
void loop() {
}


//MQTT

void mqtt( void * pvParameters ){
void callback(char* 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();

  // Feel free to add more if statements to control more GPIOs with MQTT

  // If a message is received on the topic esp32/output, you check if the message is either "on" or "off".
  // Changes the output state according to the message
  if (String(topic) == "esp32/output") {
    Serial.print("Changing output to ");
    if(messageTemp == "on"){        
      Serial.println("Relay ON");
      digitalWrite(relayPin, LOW);    //pins on board seams to be working in "reverse"
    }
    else if(messageTemp == "off"){    
      Serial.println("Relay OFF");
      digitalWrite(relayPin, HIGH);   //pins on board seams to be working in "reverse"
    }
  }
}

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    if (client.connect("ESP8266Client")) {
      Serial.println("connected");
      // Subscribe
      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);
    }
  }
}
void loop() {
  if (!client.connected()) {
    reconnect();
  }
  client.loop();

  long now = millis();
  }

}

void loop() {
  
}

I think the problem is that “client.setCallback(callback);” cannot find “callback” function in my code as it is within another function. I’m new to the Arduino, and I cannot find any information online about how to solve this.

Please help me with fixing my sketch.

Add the prototype for your callback function before setup()

void callback(char* topic, byte* message, unsigned int length);
void setup()
{
   ...
}

Hello

Thank you for your help.

I understand that I have to define my client.setCallback(callback) function in the global scope.
How to recall it inside the other function?

This is my new code:

#include <WiFi.h>
#include <PubSubClient.h>
#include <Wire.h>
const char* ssid = "XXX";
const char* password = "XXX";
// Add your MQTT Broker IP address
const char* mqtt_server = "XXX";
WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
char msg[50];
int value = 0;
// relay Pin
const int relayPin = 4;
TaskHandle_t Task1;
TaskHandle_t Task2;
void callback(char* topic, byte* message, unsigned int length);

void setup() {
  Serial.begin(115200);
  client.setServer(mqtt_server, 1883);
  pinMode(relayPin, OUTPUT);
  client.setCallback(callback);
  //create a task that will be executed in the myWiFiTask() function, with priority 1 and executed on core 0
  xTaskCreatePinnedToCore(
                    myWiFiTask,   /* Task function. */
                    "Task1",     /* name of task. */
                    10000,       /* Stack size of task */
                    NULL,        /* parameter of the task */
                    1,           /* priority of the task */
                    &Task1,      /* Task handle to keep track of created task */
                    0);          /* pin task to core 0 */                  
  delay(500); 

  //create a task that will be executed in the MQTT() function, with priority 1 and executed on core 1
  xTaskCreatePinnedToCore(
                    MQTT,   /* Task function. */
                    "Task2",     /* name of task. */
                    10000,       /* Stack size of task */
                    NULL,        /* parameter of the task */
                    1,           /* priority of the task */
                    &Task2,      /* Task handle to keep track of created task */
                    1);          /* pin task to core 1 */
    delay(500); 
}

//myWiFiTask:
bool myWiFiFirstConnect = true;

void myWiFiTask(void *pvParameters) {
  wl_status_t state;

  while (true) {
    state = WiFi.status();
    if (state != WL_CONNECTED) {  // We have no connection
      if (state == WL_NO_SHIELD) {  // WiFi.begin wasn't called yet
        Serial.println("Connecting WiFi");

        WiFi.mode(WIFI_STA);
        WiFi.begin(ssid, password);

      } else if (state == WL_CONNECT_FAILED) {  // WiFi.begin has failed (AUTH_FAIL)
        Serial.println("Disconnecting WiFi");

        WiFi.disconnect(true);

      } else if (state == WL_DISCONNECTED) {  // WiFi.disconnect was done or Router.WiFi got out of range
        if (!myWiFiFirstConnect) {  // Report only once
          myWiFiFirstConnect = true;

          Serial.println("WiFi disconnected");
        }
      }

      vTaskDelay (250); // Check again in about 250ms

    } else { // We have connection
      if (myWiFiFirstConnect) {  // Report only once
        myWiFiFirstConnect = false;

        Serial.print("Connected to ");
        Serial.println(ssid);
        Serial.print("IP address: ");
        Serial.println(WiFi.localIP());
        Serial.println("");
      }

      vTaskDelay (5000); // Check again in about 5s
    }
  }
}
void loop() {
}


//MQTT
void MQTT( void * pvParameters ){
  //What to put here to make it work?//
  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();

  // Feel free to add more if statements to control more GPIOs with MQTT

  // If a message is received on the topic esp32/output, you check if the message is either "on" or "off".
  // Changes the output state according to the message
  if (String(topic) == "esp32/output") {
    Serial.print("Changing output to ");
    if(messageTemp == "on"){        
      Serial.println("Relay ON");
      digitalWrite(relayPin, LOW);    //pins on board seams to be working in "reverse"
    }
    else if(messageTemp == "off"){    
      Serial.println("Relay OFF");
      digitalWrite(relayPin, HIGH);   //pins on board seams to be working in "reverse"
    }
  }
}

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    if (client.connect("ESP8266Client")) {
      Serial.println("connected");
      // Subscribe
      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);
    }
  }
}
void loop() {
  if (!client.connected()) {
    reconnect();
  }
  client.loop();

  long now = millis();
  }

}

void loop() {
  
}

Search for line : //What to put here to make it work?// this is where I don’t know what to do.
No matter what I try I cannot make it work.
When is use void callback I get error “variable or field ‘callback’ declared void” when I use :: operator I get expected ‘;’ before ‘{’ token

Why do you have 3 loop() functions in your code?

You have THREE functions named 'loop' and no definition of the function named 'callback'. You have a declaration saying how you would call such a function if it existed but you have no definition of what the function does.