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


//EDIT THESE LINES TO MATCH YOUR SETUP
#define MQTT_SERVER "YOUR.MQTT.SERVER.IP"
const char* ssid = "YOUR_SSID";
const char* password = "YOUR_PASSWORD";

//LED on ESP8266 GPIO2
const int lightPin = 2;

char* lightTopic = "/test/light1";


WiFiClient wifiClient;
PubSubClient client(MQTT_SERVER, 1883, callback, wifiClient);

void setup() {
    //initialize the light as an output and set to LOW (off)
    pinMode(lightPin, OUTPUT);
    digitalWrite(lightPin, LOW);

    //start the serial line for debugging
    Serial.begin(115200);
    delay(100);


    //start wifi subsystem
    WiFi.begin(ssid, password);
    //attempt to connect to the WIFI network and then connect to the MQTT server
    reconnect();

    //wait a bit before starting the main loop
        delay(2000);
}



void loop(){

    //reconnect if connection is lost
    if (!client.connected() && WiFi.status() == 3) {reconnect();}

    //maintain MQTT connection
    client.loop();

    //MUST delay to allow ESP8266 WIFI functions to run
    delay(10); 
}


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

    //convert topic to string to make it easier to work with
    String topicStr = topic; 

    //Print out some debugging info
    Serial.println("Callback update.");
    Serial.print("Topic: ");
    Serial.println(topicStr);

    //turn the light on if the payload is '1' and publish to the MQTT server a confirmation message
    if(payload[0] == '1'){
        digitalWrite(lightPin, HIGH);
        client.publish("/test/confirm", "Light On");

    }

    //turn the light off if the payload is '0' and publish to the MQTT server a confirmation message
    else if (payload[0] == '0'){
        digitalWrite(lightPin, LOW);
        client.publish("/test/confirm", "Light Off");
    }

}




void reconnect() {

    //attempt to connect to the wifi if connection is lost
    if(WiFi.status() != WL_CONNECTED){
        //debug printing
        Serial.print("Connecting to ");
        Serial.println(ssid);

        //loop while we wait for connection
        while (WiFi.status() != WL_CONNECTED) {
            delay(500);
            Serial.print(".");
        }

        //print out some more debug once connected
        Serial.println("");
        Serial.println("WiFi connected");  
        Serial.println("IP address: ");
        Serial.println(WiFi.localIP());
    }

    //make sure we are connected to WIFI before attemping to reconnect to MQTT
    if(WiFi.status() == WL_CONNECTED){
    // Loop until we're reconnected to the MQTT server
        while (!client.connected()) {
            Serial.print("Attempting MQTT connection...");

            // Generate client name based on MAC address and last 8 bits of microsecond counter
            String clientName;
            clientName += "esp8266-";
            uint8_t mac[6];
            WiFi.macAddress(mac);
            clientName += macToStr(mac);

            //if connected, subscribe to the topic(s) we want to be notified about
            if (client.connect((char*) clientName.c_str())) {
                Serial.print("\tMTQQ Connected");
                client.subscribe(lightTopic);
            }

            //otherwise print failed for debugging
            else{Serial.println("\tFailed."); abort();}
        }
    }
}

//generate unique name from MAC addr
String macToStr(const uint8_t* mac){

  String result;

  for (int i = 0; i < 6; ++i) {
    result += String(mac[i], 16);

    if (i < 5){
      result += ':';
    }
  }

  return result;
}

The error is 'callback' was not declared in this scope

  • it is a know bug in Arduino toolchain. copy the callback function before the first use. before client declaration. – Juraj Mar 22 '18 at 6:34
  • @Juraj I've changed it, but I found the same error – arn1m0nd Mar 23 '18 at 12:23
  • update the code in the question – Juraj Mar 23 '18 at 12:35
  • have you tried adding void callback(char* topic, byte* payload, unsigned int length); (exactly that one line with ; at the end) before PubSubClient client(MQTT_SERVER, 1883, callback, wifiClient); – Jaromanda X Mar 23 '18 at 23:02
  • @Juraj - that's not a bug, that's how C++ rolls - you can't "reference" a function in code before you "declare" it - also, moving callback will mean the callback function will try to "reference" client before it is declared, so, similar (but not exactly the same) error will occur - declaring the function callback before client will fix the issue – Jaromanda X Mar 23 '18 at 23:06
3

In C++, you can't use or reference a function before it is declared, that's not Arduino specific, it's how C++ "works"

Moving the callback function above the client declaration won't help, because the callback function references client

The only solution is to declare the callback function before it is referenced in client initialisation, but have the definition of callback after

i.e. add one line

WiFiClient wifiClient;
void callback(char* topic, byte* payload, unsigned int length); // add this in your code
PubSubClient client(MQTT_SERVER, 1883, callback, wifiClient);

Nothing else needs to be changed

Please excuse some terminology mistakes above - it's been a long time since I learned C/C++, while I know how to use it, I don't always know how to describe it :p

apprently there's some bug in the toolchain - see the comments in the question. However, this is still a valid solution, I guess it works around the bug

  • The difference is "declaration" vs "definition". Readers should take note of the differences, though they appear somewhat similar. Declaration must occur before (nearer to the start of a source file) use. – jose can u c Mar 24 '18 at 1:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.