Passing custom library method to ESP8266WebServer .on() method?

So I have ran into an issue while cleaning up my code and working it into its own library. The issue is related to the callback needed for the ESP8266WebServer .on method.

Here is the error

src\Html.cpp:47:13: warning: 'void _handleIndex()' defined but not used [-Wunused-function]
static void _handleIndex() {
^
In file included from C:/Users/webmaster/Documents/PlatformIO/Projects/ClockClock/src/ClockClock.ino:1:0:
src\Config.h:12:20: warning: 'stringDays' defined but not used [-Wunused-variable]
static const char *stringDays[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
^
Linking .pioenvs\d1_mini\firmware.elf
.pioenvs\d1_mini\src\Html.cpp.o:(.text._ZN4HtmlC2Ev+0x4): undefined reference to `Html::_handleIndex()'

Html.h

#ifndef Html_h
#define Html_h
#include <ESP8266WebServer.h>     //Local WebServer used to serve the configuration portal
#include "Arduino.h"
class Html{
    public:
        Html();
        void handleClient();
    private:
        ESP8266WebServer _server;
        char _header[];
        char _footer[];
        char _index[];
        byte _eepromByte;
        String _wrapHtml(String body);
        static void _handleIndex();
        void _redirectToIndex();
};
#endif

Html.cpp

#include <ESP8266WebServer.h>     //Local WebServer used to serve the configuration portal
#include <EEPROM.h>
#include "Config.h"
#include "Arduino.h"
#include "Html.h"
#include "PadDigit.h"

ESP8266WebServer _server;
byte _eepromByte = 0;

char _header[] PROGMEM = R"=====(
    <!DOCTYPE html>
    <html>
    <head>
    </head>
    <body>
    )=====";

char _footer[] PROGMEM = R"=====(
    </body>
    </html>
    )=====";

char _index[] PROGMEM = R"=====(
    <a href="/add">New Alarm</a>
    {alarms}
    )=====";

char _alarm[] PROGMEM = R"=====(
    <div>
    <a href="/toggle?alarm={index}">{invertedStatus}</a>
    <span class="day">{day}</span>
    <span class="hour">{hour}</span>:<span class="minute">{minute}</span>
    <a href="/delete?alarm={index}">Delete</a>
    </div>
    )=====";

String _wrapHtml(String body){
    return (String) _header + body + (String) _footer;
}

void _redirectToIndex() {
  _server.sendHeader("Location", String("/"), true);
  _server.send ( 302, "text/plain", "");
}

static void _handleIndex() {
  String html = _index;

  // Build the html for the saved alarms
  String alarmsHtml = "";
  for (unsigned int i = 0; i < ALARM_TOTAL; i++) {
    int alarmEnabledIndex = i * 4;
    _eepromByte = EEPROM.read(alarmEnabledIndex);

    if (_eepromByte != DELETED_STATE) {
      String alarmHtml = _alarm;

      alarmHtml.replace("{index}", (String) alarmEnabledIndex);
      String invertedState = "Disable";
      if (_eepromByte == 0) {
        invertedState = "Enable";
      }
      alarmHtml.replace("{invertedStatus}", invertedState);
      alarmHtml.replace("{day}", stringDays[EEPROM.read(alarmEnabledIndex + 1) - 1]); // The day is stored as 1-7 per the Time lib and our day names are of course base 0;
      alarmHtml.replace("{hour}", PadDigit::format(EEPROM.read(alarmEnabledIndex + 2)));
      alarmHtml.replace("{minute}", PadDigit::format(EEPROM.read(alarmEnabledIndex + 3)));

      alarmsHtml += alarmHtml;
    }
  }

  html.replace("{alarms}", alarmsHtml);
  _server.send(200, "text/html", _wrapHtml(html));
}

Html::Html(){
    ESP8266WebServer _server(80);

    _server.on("/", _handleIndex);
    //_server.on("/add", handleForm);
    //_server.on("/save", handleSave);
    //_server.on("/delete", handleDelete);
    //_server.on("/toggle", handleToggle);
    _server.begin();
}

void Html::handleClient(){
    _server.handleClient();
}
/*
void handleForm() {
  String html = htmlForm;
  server.send(200, "text/html", html);
}

void handleSave() {
  for (int i = 0; i < ALARM_TOTAL; i++) {
    int alarmEnabledIndex = i * 4;
    _eepromByte = EEPROM.read(alarmEnabledIndex); // I am keeping the enabled byte at the head of each "page". A page beeing four bytes consisting of enabled, day, hour, minute
    if (_eepromByte == DELETED_STATE) { // Find the first available slot
      // Do save
      EEPROM.write(alarmEnabledIndex, 1);
      EEPROM.write(alarmEnabledIndex + 1, server.arg("day").toInt());
      EEPROM.write(alarmEnabledIndex + 2, server.arg("hour").toInt());
      EEPROM.write(alarmEnabledIndex + 3, server.arg("minute").toInt());
      EEPROM.commit();

      _redirectToIndex();
      break;
    }
  }
  server.send(200, "text/html", htmlErrorLimit); // Send out the error page if we have hit the max alarms
}

void handleDelete() {
  if (server.hasArg("alarm")) {
    EEPROM.write(server.arg("alarm").toInt(), 2);
    EEPROM.commit();
  }
  _redirectToIndex();
}

void handleToggle() {
  if (server.hasArg("alarm")) {
    int i = server.arg("alarm").toInt();
    eepromByte = EEPROM.read(i);

    if (_eepromByte == 0) {
      EEPROM.write(i, 1);
    }
    else {
      EEPROM.write(i, 0);
    }
    EEPROM.commit();
  }
  _redirectToIndex();
}
*/

inside my loop I am calling

htmlLib.handleClient();

Code:


---




```
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <ESP8266WebServer.h>   // Include the WebServer library

class MyClass {
 public:
   MyClass(int i) : icolor=#000000[/color] {}
   ~MyClasscolor=#000000[/color] { /* This is where you would remove the handle from the server if it were possible */ }
   void handlecolor=#000000[/color] {
     if (server != nullptr)
       server->send(200, "text/plain", String("Hello world from MyClass!\r\ni = ") + i);   // Send HTTP status 200 (Ok) and send some text to the browser/client
   }
   void addToServer(ESP8266WebServer &server, const char *URI) {
     server.on(URI, std::bind(&MyClass::handle, this));
     this->server = &server;
   }
 private:
   int i;
   ESP8266WebServer *server = nullptr; // If you have access to the declaration of server, you can use the global instance instead of keeping a pointer to it.
};

MyClass myHandlercolor=#000000[/color];

ESP8266WebServer servercolor=#000000[/color];    // Create a webserver object that listens for HTTP request on port 80

void handleNotFoundcolor=#000000[/color];

void setupcolor=#000000[/color] {
 WiFi.begin("WiFi-SSID", "passphrase");
 while (WiFi.statuscolor=#000000[/color] != WL_CONNECTED)
   delaycolor=#000000[/color];

MDNS.begincolor=#000000[/color];

myHandler.addToServer(server, "/");
 server.onNotFoundcolor=#000000[/color];        // When a client requests an unknown URI (i.e. something other than "/"), call function "handleNotFound"
 server.begincolor=#000000[/color];                           // Actually start the server
}

void loopcolor=#000000[/color] {
 server.handleClientcolor=#000000[/color];                    // Listen for HTTP requests from clients
}

void handleNotFoundcolor=#000000[/color] {
 server.send(404, "text/plain", "404: Not found"); // Send HTTP status 404 (Not Found) when there's no handler for the URI in the request
}
```

|

std::bind

Pieter

This:

ESP8266WebServer _server;

in the cpp file does NOT relate to this:

    private:
        ESP8266WebServer _server;

in the header file. They are two completely different memory addresses.

void _redirectToIndex() {
  _server.sendHeader("Location", String("/"), true);
  _server.send ( 302, "text/plain", "");
}

Which _server does THAT refer to?

Ok that makes more sense. I will have to learn more about why/when one sets up variables inside the header file vs the cpp

hcker2000:
Ok that makes more sense. I will have to learn more about why/when one sets up variables inside the header file vs the cpp

You should also learn about how to properly value the variable(s) defined in the header file, in the source file. You CAN value the _server variable defined in the header file in the source file, instead of defining and valuing a new variable in the source file.

Html::Html(){
    ESP8266WebServer _server(80);

    _server.on("/", _handleIndex);

That defines ANOTHER variable named _server, and values it, but that one goes out of scope almost immediately.

That is the ONLY instance that actually does anything, but it goes out of scope.

Html::Html() : _server(80) // Create an instance of the ESP8266WebServer class
                                        // AND value the member field
{ // Down here, where it belongs
    _server.on("/", _handleIndex); // Assign callback actions to the member instance