tzapu / WiFiManager

ESP8266 WiFi Connection manager with web captive portal
http://tzapu.com/esp8266-wifi-connection-manager-library-arduino-ide/
MIT License
6.53k stars 1.96k forks source link

WiFiManagerParameters without ID sometimes get a length of 0 #1116

Open Lithimlin opened 4 years ago

Lithimlin commented 4 years ago

Basic Infos

Hardware

WiFimanager Branch/Release:

Esp8266/Esp32:

Hardware: ESP-12e, esp01, esp25

ESP Core Version: 2.4.0, staging

Description

When creating WiFiManagerParameters without an ID, the length sometimes becomes 0, causing it and following parameters to not render. Is it necessary to check if the length is 0 and then skip all following parameters in getParamOut()? Maybe a continue instead of a break would be better in general.

I also don't know why this only occurs sometimes. I haven't found a place where the _length of a parameter is ever overwritten and it is never 0 when I assign it. It only occurs with parameters that have no ID, like the SeparatorParameter below.

If you need more code, I'll try to provide it, but I'm trying to keep it simple here and my code has gotten quite complex. I hope the provided code is enough to pin down where the problem occurs.

In the particular example below, the first three parameters are rendered (three checkboxes). The fourth has a length of 0 and thus the fifth (another checkbox with the ID "use_mqtt") and following parameters are not rendered.

EDIT:

To be clear: When I say sometimes, I mean that I can compile the code and it may work. If I compile the same code again, it doesn't anymore.

Sketch


#include <WiFiManager.h>

class SeparatorParameter : public WiFiManagerParameter {
public:
  SeparatorParameter(const char *label)
    : WiFiManagerParameter() {
    char *custom = new char[55];
    strcpy(custom, "<div class=\"separator\">");
    strcat(custom, label);
    strcat(custom, "</div>");
    init(NULL, NULL, NULL, 4, custom, WFM_LABEL_BEFORE);
  }
};

WiFiManager wm;

void setup() {
  Serial.begin(115200);

  wm.setHostname("ConfigAP");

  std::vector<const char *> menu = {"wifi","info","param","sep","restart","exit"};
  wm.setMenu(menu);
  const char customHead[] = "<style>"
  ".separator {display: flex;align-items: center;text-align: center;}"
  ".separator::before, .separator::after {content:''; flex: 1; border-bottom: 1px solid #000;}"
  ".separator::before {margin-right: .25em;}"
  ".separator::after {margin-left: .25em;}"
  "body.invert .separator::before {border-bottom: 1px solid #FFF;}"
  "body.invert .separator::after {border-bottom: 1px solid #FFF;}"
  "</style>";
  wm.setCustomHeadElement(customHead);
  [...]
}

void loop() {

}

In WiFiManager.cpp:

[...]
String WiFiManager::getParamOut(){
  String page;

  if(_paramsCount > 0){

    String HTTP_PARAM_temp = FPSTR(HTTP_FORM_LABEL);
    HTTP_PARAM_temp += FPSTR(HTTP_FORM_PARAM);
    bool tok_I = HTTP_PARAM_temp.indexOf(FPSTR(T_I)) > 0;
    bool tok_i = HTTP_PARAM_temp.indexOf(FPSTR(T_i)) > 0;
    bool tok_n = HTTP_PARAM_temp.indexOf(FPSTR(T_n)) > 0;
    bool tok_p = HTTP_PARAM_temp.indexOf(FPSTR(T_p)) > 0;
    bool tok_t = HTTP_PARAM_temp.indexOf(FPSTR(T_t)) > 0;
    bool tok_l = HTTP_PARAM_temp.indexOf(FPSTR(T_l)) > 0;
    bool tok_v = HTTP_PARAM_temp.indexOf(FPSTR(T_v)) > 0;
    bool tok_c = HTTP_PARAM_temp.indexOf(FPSTR(T_c)) > 0;

    char valLength[5];
    // add the extra parameters to the form
    for (int i = 0; i < _paramsCount; i++) {
      if (_params[i] == NULL || _params[i]->_length == 0) {
        DEBUG_WM(DEBUG_ERROR,"[ERROR] WiFiManagerParameter is out of scope");
        if(_params[i]->_length == 0) {
          Serial.println("Length is 0");
        }
        if(i+1 < _paramsCount) {
          Serial.print("Next element: ");
          if(_params[i+1] == NULL) {
            Serial.println("NULL");
          } else {
            Serial.println(_params[i+1]->getID());
          }
        }
        break;
      }
[...]

Debug Messages

[...]
*WM: [3] setupConfigPortal 
*WM: [1] Starting Web Portal 
*WM: [3] dns server started with ip:  192.168.4.1
*WM: [2] HTTP server started 
*WM: [2] WiFi Scan completed in 3105 ms
*WM: [2] Config Portal Running, blocking, waiting for clients... 
*WM: [3] -> connectivitycheck.platform.hicloud.com 
*WM: [2] <- Request redirected to captive portal 
*WM: [3] -> connectivitycheck.platform.hicloud.com 
*WM: [2] <- Request redirected to captive portal 
*WM: [3] -> connectivitycheck.platform.hicloud.com 
*WM: [2] <- Request redirected to captive portal 
*WM: [3] -> connectivitycheck.platform.hicloud.com 
*WM: [2] <- Request redirected to captive portal 
*WM: [3] -> connectivitycheck.platform.hicloud.com 
*WM: [2] <- Request redirected to captive portal 
*WM: [2] <- HTTP Root 
*WM: [3] -> 192.168.4.1 
*WM: [3] lastconxresulttmp: WL_IDLE_STATUS
*WM: [3] lastconxresult: WL_DISCONNECTED
*WM: [2] Scan is cached 10214 ms ago
*WM: [3] -> 192.168.4.1 
*WM: [3] -> connectivitycheck.platform.hicloud.com 
*WM: [2] <- Request redirected to captive portal 
*WM: [3] -> connectivitycheck.platform.hicloud.com 
*WM: [2] <- Request redirected to captive portal 
*WM: [3] -> connectivitycheck.platform.hicloud.com 
*WM: [2] <- Request redirected to captive portal 
*WM: [2] <- HTTP Param 
*WM: [0] [ERROR] WiFiManagerParameter is out of scope 
Length is 0
Next element: use_mqtt
*WM: [3] lastconxresulttmp: WL_IDLE_STATUS
*WM: [3] lastconxresult: WL_DISCONNECTED
*WM: [3] Sent param page 
[...]
Lithimlin commented 4 years ago

I just removed the length check and everything is working perfectly fine. Is that check even necessary?

tablatronix commented 4 years ago

I had a feeling this was the cause, what kind of parameter has a length of 0?

This is not necessary but it was keeping some code from blowing up if users were trying to use params out of scope.

Are you sure you are not losing scope of your params ? If you are using callbacks make sure they are icache, and make sure you are not in some other interrupt etc.

Lithimlin commented 4 years ago

As I said, no parameters of mine actually have a length of 0. It's always at least 1.

I'm pretty sure I'm not losing their scope since I can access the _length field just fine and correctly work with them. It's just that the _length is being set to 0 somewhere in the code. I tried to find all occurrences if the _length field but it's not set to anything anywhere except when it's deconstructed. But I'm never actively deconstructing any of my parameters.