PubSubClient "no matching function call" errors

src\main.cpp:31:45: error: ‘callback’ was not declared in this scope
PubSubClient client(mqtt_server, mqtt_port, callback, wifiClient);

The callback function was not pre-declared. It needs it’s prototype written above the usage of it. It seems that this was originally a .ino sketch but the conversion to cpp wasn’t one properly in this case.

So, writing

void callback(char* topic, byte* payload, unsigned int length);

above the PubSubClient client line solves that.

It then says

src\main.cpp:33:65: error: no matching function for call to ‘PubSubClient::PubSubClient(String&, uint16_t&, void (&)(char*, byte*, unsigned int), WiFiClient&)’
PubSubClient client(mqtt_server, mqtt_port, callback, wifiClient);

So you’re trying to call a constructor with the argument types

  • String&
  • uint16_t&,
  • void (&)(char*, byte*, unsigned int),
  • WiFiClient&

So let’s see what constructors with what types are available an which are not.

First, you can see that there are no constructors which take a String or a String& (reference) – either pure strings (char*) or IPAddress objects or pointers to the individual bytes of the IP (source).

Thus we rewrite the lines

String mqtt_server = "mqtt.mydomain";
...
PubSubClient client(mqtt_server, mqtt_port, callback, wifiClient);

to

#define MQTT_SERVER "mqtt.mydomain"
..
PubSubClient client(MQTT_SERVER , mqtt_port, callback, wifiClient);

Next up the same thing with the code

  if (client.connect(clientId.c_str(),mqtt_user,mqtt_password)) {

thatcomplains

src/main.cpp:213:30: error: no matching function for call to ‘PubSubClient::connect(String&)’
if (client.connect(clientId)) {
.pio/libdeps/esp12e/PubSubClient/src/PubSubClient.h:145:12: note: boolean PubSubClient::connect(const char*)
boolean connect(const char* id);

So you’re again trying to call a function that accepts a C-string char* with a String object – the call to c_str() on the object is missing (or efine it as a pure string in the first place).

I’m not sure about this line since I don’t have the definition of mqtt_user and mqtt_password

  if (client.connect(clientId.c_str(),mqtt_user,mqtt_password)) {

but if these are String variables, then they also need c_str().

And finally

src\main.cpp:203:37: error: no matching function for call to ‘PubSubClient::publish(String&, String&)’
if (client.publish(topic, Jstate)) {
^
src\main.cpp:203:37: note: candidates are:
In file included from src\main.cpp:7:0:
C:\Users\Max.platformio\lib\PubSubClient\src/PubSubClient.h:151:12: note: boolean PubSubClient::publish(const char*, const char*)
boolean publish(const char* topic, const char* payload);

You’re attempgin to call client.publish() with two String objects as argument, but it’s only accepting C-strings. Adding c_str() conversion calls solves that again.

Nitpick: You write in your code

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

but the for(int i = .. is wrong when length is unsigned. i should be an unsigned int, too.

So your whole fixed code (while removing the reference to SSID_access.h and substituting the guesse content) looks like

#include <Arduino.h>
#include <DNSServer.h>
#include <ESP8266WiFi.h>
#include <ESPAsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <AsyncElegantOTA.h>
#include <PubSubClient.h>
//#include <SSID_access.h>
//assume content like 
String mqtt_user = "unknown";
String mqtt_password = "unknown2";
#define MY_SSID "my ssid"
#define SSID_PSW "my_ssid_password"

#define LED 2
#define updated 20210217

String topic = "jlight";
#define MQTT_SERVER "mqtt.mydomain"
uint16_t mqtt_port = 51883;
String Jstate = "off";
String clientId = "ESP"; // IP address added later

int latest = micros();
// reconnect every 5 seconds
long lastReconnectAttempt = 0;
// auto publish every hour
long publishDelay = 3600000;
long lastPublish = -publishDelay;
long publish = 0;

DNSServer dnsServer;
AsyncWebServer server(80);

void callback(char* topic, byte* payload, unsigned int length);

WiFiClient wifiClient;
PubSubClient client(MQTT_SERVER, mqtt_port, callback, wifiClient);
//PubSubClient client(mqtt_server, mqtt_port, wifiClient);
//PubSubClient client(wifiClient);
 
boolean reconnect() {
  Serial.print("Attempting MQTT connection from ");
  Serial.print(WiFi.localIP());
  Serial.print(" as ");
  clientId = "ESP";
  clientId += WiFi.localIP().toString();
  Serial.println(clientId);

  // Attempt to connect
  if (client.connect(clientId.c_str(),mqtt_user.c_str(),mqtt_password.c_str())) {
    Serial.println("connected");
    
    // Once connected, publish an announcement...
    client.publish("jlight", (char*)Jstate.c_str());    
      
    // ... and resubscribe
    client.subscribe("jlight/#");
  } 
  return client.connected();  
} 

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

  // skip this message if triggered too soon.
  long now = millis();
  
  if (String(topic) == "j-light/set") {
    Serial.print("Set command received: ");
    Serial.println(pl);
    // skip this message if triggered too soon.  .
    if ( (now-publish) < 3000 ) {
      Serial.print("skipping the process as its been only ");
      Serial.print(String(now-lastPublish));
      Serial.println(" msec.");
    } else {
      publish = now;
      
      if (pl == "off"){
        Jstate = "off"; 
      } else if (pl == "on") {
        Jstate = "on";
      }
      // force a publish
      lastPublish = -publishDelay;
    }
  }
}

  // =============================================================================== //
  //                                HTTP processing                                  //
  // =============================================================================== //

String handleJon() {
  Jstate = "on";
  String page;
  page += "<!DOCTYPE html><html><head><title>Johs's ESP8266 server</title>";
  page += "<meta http-equiv='refresh' content='2;url=/'/>";
  page += "</head><body>";
  page += "Turning on the J LED light.</br>";
  page += "</body></html>";
  return String(page);
}

String handleJoff() {
  Jstate = "off";
  String page;
  page += "<!DOCTYPE html><html><head><title>Johs's ESP8266 server</title>";
  page += "<meta http-equiv='refresh' content='2;url=/'/>";
  page += "</head><body>";
  page += "Turning off the J LED light.</br>";
  page += "</body></html>";
  return String(page);
}

String handleRoot(){
  String JonBC = "off";
  String JoffBC = "off";
  (Jstate == "on")?JonBC="style='background-color:#0066FF;'":JonBC="";
  (Jstate == "off")?JoffBC="style='background-color:#0066FF;'":JoffBC="";
  String page = "<!DOCTYPE html><html><head><title>Johs's ESP8266 server</title>"
    "<style>.button{background-color: #00b0f0; border: none; color: white; padding: 40px 64px; text-allign: center; text-decoration: none;display: inline-block; font-size:32px;}</style>"
    "</head><body>"
    "Hi! I am Josh's ESP8266.</p><hr>"
    "<a href='j-on' class='button' ";
  page += JonBC;
  page += ";'>J on</a>"
    "<a href='j-off' class='button' ";
  page += JoffBC;
  page += ";'>J off</a>"
    "<hr><p>Got updated OTA! ";
  page += updated;
  page += "</body></html>";
  return String(page);
}


void setup() {
  // =============================================================================== //
  //                                   setup WIFI                                    //
  // =============================================================================== //
  
  Serial.begin(115200);
  pinMode(LED,OUTPUT);
  WiFi.mode(WIFI_STA);
  WiFi.begin(MY_SSID, SSID_PSW);
  Serial.println("");

  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(MY_SSID);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  // =============================================================================== //
  //                                HTTP processing                                  //
  // =============================================================================== //

  server.on("/j-on", HTTP_GET, [](AsyncWebServerRequest *request){    
    request->send(200, "text/html", handleJon());
  });

  server.on("/j-off", HTTP_GET, [](AsyncWebServerRequest *request) {    
    request->send(200, "text/html", handleJoff());
  });

  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
    request->send(200, "text/html", handleRoot());
  });


  AsyncElegantOTA.begin(&server);    // Start ElegantOTA
  server.begin();
  Serial.println("HTTP server started");

  // =============================================================================== //
  //                               MQTT processing                                   //
  // =============================================================================== //
    
  //client.setServer(mqtt_server, 51883); //mqtt_port);
  client.setCallback(callback);

  //if (client.connect((char*) clientID.c_str())) {
  if (client.connect(clientId.c_str())) {
    Serial.println("Connected to MQTT broker");
    Serial.print("Topic is: ");
    Serial.println(topic);
    
    if (client.publish(topic.c_str(), Jstate.c_str())) {
      Serial.println("Publish ok");
    }
    else {
      Serial.println("Publish failed");
    }
  }
  else {
    Serial.println("MQTT connect failed");
    Serial.println("Will reset and try again...");
    abort();
  }
} 

void loop() {
  // put your main code here, to run repeatedly:

  // Check MQTT
  long now = millis();
  if (!client.connected()) {
    if (now - lastReconnectAttempt > 5000) {
      lastReconnectAttempt = now;
      // Attempt to reconnect
      if (reconnect()) {
        lastReconnectAttempt = 0;
      }
    }
  } else {
    // Client connected
    client.loop();
  } 

  // changed auto publish time to 1/2 hour infrequent
  if ((now - lastPublish) > publishDelay){
    boolean retained = true;
    if(client.publish("jlight", (char*)Jstate.c_str(),retained)) {
        Serial.println("Publish ok");
      }
      else {
        Serial.println("Publish failed");
      }
    lastPublish = now;
  } 

  // Update LED state
  if(Jstate == "off"){
    digitalWrite(LED,HIGH);
    Serial.print(".");
  }
  if(Jstate == "on"){
    digitalWrite(LED,LOW);
    Serial.print("o");
  }

  // Need to load new config?
  AsyncElegantOTA.loop();
}

to me.

Tested with the same libraries as you do, as I can see in

[env:esp12e]
platform = espressif8266
board = esp12e
framework = arduino
lib_deps = 
    ayushsharma82/AsyncElegantOTA @ ^2.2.5
    ottowinter/ESPAsyncTCP-esphome @ ^1.2.3
    ottowinter/ESPAsyncWebServer-esphome @ ^1.2.7
    knolleary/PubSubClient @ ^2.8
    bbx10/DNSServer @ ^1.1.0

which brings us to another problem:

ottowinter/ESPAsyncTCP-esphome @ ^1.2.3
ottowinter/ESPAsyncWebServer-esphome @ ^1.2.7

Why use the esphome fork libraries here? And not the original

me-no-dev/ESPAsyncTCP @ ^1.2.2
me-no-dev/ESP Async WebServer @ ^1.2.3

the ottowinter repos (GitHub - OttoWinter/ESPAsyncTCP: Async TCP Library for ESP8266) explicitly say

A fork of the AsyncTCP library by @me-no-dev for ESPHome.

So uhm if you’re not developing for that I’d suggest the normal libaries. Of course they might still work or have project-specific enhancements for it, but if anything doesn’t work, I’d recommend the normal ones.

As a TL;DR: Always read compiler messages fully and try to understand what they’re conveying to you. The error: no matching function for call to xy are saying “You’re attempting to call a function that doesn’t exist in this version of parameter types” to you already. You can follow the definitions of constructors in the library anytime in VSCode by Ctrl-Clicking on the class name or function name, these are not hiden from you. There you can look at what functions are available and what you’re trying to do.

2 Likes