I'm having a bit of trouble with the ESP8266WebServer. My WebServer{} class is wrapped around the ESP8266WebServer object and looks like this:
Header file:
#include <WiFiClient.h>
#ifndef WebServer_h
#define WebServer_h
#include "Arduino.h"
class WebServer {
public:
WebServer();
void begin();
void handleClient();
void finishedProcessingData(String clientReply);
String queryString;
private:
// page/url handlers
friend void handleSomeData();
};
#endif
Cpp file:
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include "Arduino.h"
#include "WebServer.h"
ESP8266WebServer server(80);
int aNumberHere = 0;
String queryString = "";
WebServer::WebServer(){
}
void handleSomeData(){
aNumberHere++;
queryString = "";
// this loop appends all the queries fro the query string back into a query string
// (not sure if there is an easier way to grab this directly from the server api)
int totalArgs = server.args();
for (int counter = 0; counter < totalArgs; counter++){
queryString += server.argName(counter) +"="+ server.arg(counter);
if(counter < (totalArgs - 1)){
queryString += "&";
}
}
Serial.println(queryString);
Serial.println(aNumberHere);
}
void WebServer::handleClient(){
server.handleClient();
}
void WebServer::begin(){
server.on("/data.html", handleSomeData);
server.begin();
}
void WebServer::finishedProcessingData(String clientReply){
// empty the string so it isn't cached (just in case)
Serial.print("Sending reply back to client: ");
Serial.println(clientReply);
queryString = "";
server.send(200, "text/plain", clientReply);
}
The idea is to grab a query string from an http request, do some processing, then return the response.
How it is called from outside is:
WebServer webServer;
String processingResult;
void setup(){
webServer.begin();
}
void loop(){
delay(10);
webServer.handleClient();
// check if the query string has stuff in it, if it doesn't then WebServer.handleSomeData() never fired, thus no request yet
if(webServer.queryString != ""){
// do stuff that results in a string being returned
processingResult = handWavyMagic();
// then respond back to client
webServer.finishedProcessingData(processingResult);
}
}
My issue is that from my outside loop (which is in my main sketch), "webServer.queryString" is always equal to an empty string. If I print out "queryString" from within handleSomeData(), I can see the printed result from within "handleSomeData()" (which is correct), but it somehow can't seem to set it 'outside' that method. I did check to see that it is able to access and modify a variable (which is why "aNumberHere" is printed) and there seem to be no issues; "aNumberHere" gets incremented as expected every time I go to the corresponding url.
My only suspect is that "queryString" is a String object which for some reason can't be set, while "aNumberHere" is a primitive int which is fine. Is this correct or is something else going on here?
I have also tried making "queryString" a static variable, but with no luck -either I did it wrong or it just doesn't work that way either.
I am new to friend functions (well, new to c/c++ in general actually -any advice is welcome), though I read that it should be able to access the classes private properties just fine, so I'm not sure how to fix this.
Any ideas?
I know, this is a bit late for the OP to help with his problem, but maybe other readers will find this useful.
To avoid splitting parts of the logic/data inside and outside the class it would be more elegant to have everything inside. Using callbacks to non-static methods of a class instance is a bit tricky (I learned it the hard way for my current project), but here is the alternative:
void WebServer::begin()
{
// instead of server.on("/data.html", handleSomeData);
server.on("/data.html", std::bind(&WebServer::handleSomeData, this));
server.begin();
}
void WebServer::handleSomeData()
{
// do whatever you need
}
This uses std:bind() to bind the instance method and its this
pointer to the callback. As a result, everything is contained inside the web server instance, which is a cleaner approach.
There is 2 different variables called queryString
:
WebServer.cpp
WebServer.h
In the callback handleSomeData
you set the global one, but in the loop
and finishedProcessingData
you access to the member of WebServer.
To make the code works, you could remove the member of WebServer and use the global one (as you did for aNumberHere) like this :
extern String queryString;
void loop(){
delay(10);
webServer.handleClient();
// check if the query string has stuff in it, if it doesn't then WebServer.handleSomeData() never fired, thus no request yet
if(queryString != ""){
// do stuff that results in a string being returned
processingResult = handWavyMagic();
// then respond back to client
webServer.finishedProcessingData(processingResult);
queryString = "";
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With