WiFiManager: Char* conversion for default_value errornous when adding WiFiManagerParameter();

Basic Infos

Hardware

WiFimanager Branch/Release:

  • Master
  • Development (OTA)

Esp8266/Esp32:

  • ESP8266
  • ESP32

Hardware: ESP-12e, esp01, esp25

  • ESP01
  • ESP12 E/F/S (nodemcu, wemos, feather)
  • Other

ESP Core Version: 2.4.0, staging

  • 2.3.0
  • 2.4.0
  • 2.6.3
  • staging (master/dev)

Description

Hi,

When we add a custom WiFiManagerParameter with a normal char* to initialize the default value it has a strange conversion error. Following code:

char mqtt_broker[12] = "192.168.1.108";
custom_mqtt_broker = WiFiManagerParameter("mqttbroker", "MQTT Broker", mqtt_broker, sizeof(mqtt_broker));
Serial.println(custom_mqtt_broker.getValue());
Serial.println(mqtt_broker);`

puts out on the Serial:

⸮⸮⸮?168.1.10
192.168.1.108

Settings in IDE

Module: NodeMcu, Wemos D1

Additional libraries:

Sketch


#include <FS.h>                   //this needs to be first, or it all crashes and burns...
#include <ArduinoJson.h>          //https://github.com/bblanchon/ArduinoJson
#include <WiFiManager.h> //https://github.com/tzapu/WiFiManager WiFi Configuration Magic
#include <PubSubClient.h>
#include <ESP8266WiFi.h>

#define USEOTA
// enable OTA
#ifdef USEOTA
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#endif

#define TRIGGER_PIN 0 //Pin used to start AccessPoint to configure device - Just ground GPIO for 2 seconds

WiFiManager wm;
ESP8266WebServer server(80);




WiFiClient espClient;
PubSubClient client(espClient);

long lastReconnectAttempt = 0;

boolean reconnect() {
  Serial.println("attempting connecting to mqtt");
  if (client.connect("arduinoClient")) {

    Serial.println("MQTT CONNECTED");
    // Once connected, publish an announcement...
    client.publish("outTopic", "hello world");
    // ... and resubscribe
    client.subscribe("inTopic");
  }
  return client.connected();
}

//############################################# CUSTOM PARAMETERS FOR THE WIFI MANAGER ##########################################
//char mqtt_server[40] = "0.0.0.0";
//char mqtt_topicIN[80] ="IOT_Device/IN";
//char mqtt_topicOUT[80] ="IOT_Device/OUT";
//char mqtt_port[6] = "1883";

char output[2] = "2";
char wifi_enc[40];
char entity_version[40];
char mqtt_port[40] = "1883";
char mqtt_broker[12] = "           ";
char mqtt_pwd[40];
char session_key[40];
char entity_name[40];
char entity_type[40];
char entity_id[40];
char mqtt_retain[40];
char mqtt_qos[40];





//flag for saving data
bool shouldSaveConfig = false;

//WiFiManagerParameter custom_mqtt_server("server", "Server IP", mqtt_server, 40);
//WiFiManagerParameter custom_mqtt_port("port", "Port", mqtt_port, 6);
//WiFiManagerParameter custom_mqtt_topicIN("topicIn", "Input Topic", mqtt_topicIN, 80);
//WiFiManagerParameter custom_mqtt_topicOUT("topicOut", "Output Topic", mqtt_topicOUT, 80);
//WiFiManagerParameter custom_mqtt_messages("messages", "Messages Topic", mqtt_topicOUT, 80);
WiFiManagerParameter custom_output("output", "output", output, 2);
WiFiManagerParameter custom_mqtt_broker("mqttbroker", "MQTT Broker", mqtt_broker, 12);
WiFiManagerParameter custom_mqtt_pwd("mqttpwd", "MQTT password", mqtt_pwd, 40);
WiFiManagerParameter custom_session_key("sessionkey", "Session Key", session_key, 40);
WiFiManagerParameter custom_entity_name("entityname", "Entity Name", entity_name, 40);
WiFiManagerParameter custom_entity_type("entitytype", "Entitiy Type", entity_type, 40);
WiFiManagerParameter custom_wifi_enc("wifienc", "Wifi Enc", wifi_enc, 40);
WiFiManagerParameter custom_entity_version("entityversion", "Entity Version", entity_version, 40);
WiFiManagerParameter custom_mqtt_port("mqttport", "MQTT Port", mqtt_port, 40);
WiFiManagerParameter custom_entity_id("entityid", "Entitiy ID", entity_id, 40);
WiFiManagerParameter custom_mqtt_retain("mqttretain", "MQTT Retain", mqtt_retain, 40);
WiFiManagerParameter custom_mqtt_qos("mqttqos", "MQTT QoS", mqtt_qos, 40);


//###############################################################################################################################

//################################################### GENERAL VARIABLES #########################################################
bool blockWM = true; // Change this to false if you want your code to continue to run on the loop void even if you are not conected to any wifi.
//###############################################################################################################################


void saveConfigCallback() {

}


void saveParamCallback() {
  Serial.println("****************Should save params");
  shouldSaveConfig = true;

  if (shouldSaveConfig) {
    Serial.println("saving config");
    //mqtt_broker = custom_mqtt_broker.getValue();
    strcpy(mqtt_broker, custom_mqtt_broker.getValue());
    DynamicJsonDocument json(1024);
    //mqtt_broker = (char*) custom_mqtt_broker.getValue();
    json["output"] = output;
    json["mqtt_broker"] = mqtt_broker;
    json["mqtt_pwd"] = mqtt_pwd;
    json["session_key"] = session_key;
    json["entity_name"] = entity_name;
    json["entity_type"] = entity_type;
    json["wifi_enc"] = wifi_enc;
    json["entity_version"] = entity_version;
    json["mqtt_port"] = mqtt_port;
    json["entity_id"] = entity_id;
    json["mqtt_retain"] = mqtt_retain;
    json["mqtt_qos"] = mqtt_qos;
    // json["ip"]          = WiFi.localIP().toString();
    // json["gateway"]     = WiFi.gatewayIP().toString();
    // json["subnet"]      = WiFi.subnetMask().toString();

    File configFile = SPIFFS.open("/config.json", "w");
    if (!configFile) {
      Serial.println("failed to open config file for writing");
    }

    serializeJson(json, Serial);
    serializeJson(json, configFile);

    //json.printTo(Serial);
    //json.printTo(configFile);
    configFile.close();
    //end save
    shouldSaveConfig = false;
  }

}

void handleNotFound()
{
  String message = "File Not Found\n\n";
  message += "URI: ";
  message += server.uri();
  message += "\nMethod: ";
  message += (server.method() == HTTP_GET) ? "GET" : "POST";
  message += "\nArguments: ";
  message += server.args();
  message += "\n";
  for (uint8_t i = 0; i < server.args(); i++)
  {
    message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
  }
  server.send(404, "text/plain", message);
}

/*

  This void sets the device with the WiFiManager from tzapu with custom parameters.
  Needs to be called only in the setup void.
*/
void setupDeviceWM()
{
  //Serial.println("pppppppppppppppppp");
  //Serial.println(mqtt_broker);

  // callbacks
  wm.setConfigPortalBlocking(blockWM);
  String ssid = "IOT_ESP_" + String(ESP.getChipId());

  if (wm.autoConnect(ssid.c_str()))
  {
    //if you get here you have connected to the WiFi
    Serial.println("Connected to wifi network!");
    Serial.println(ssid);
    //Serial.println(mqtt_broker);
    //Serial.println(custom_mqtt_broker.getValue());
    -Serial.println(WiFi.localIP());
    WiFi.mode(WIFI_STA);
    wm.startWebPortal();
  }
  else
  {
    Serial.println("Could not connect with WiFi!");
  }

  // call the code down to activate wifi so users can configure the device, event if it's connected to the local network
  //wm.startConfigPortal("IOT_Device");
  //
  server.onNotFound(handleNotFound);
  server.begin(); // declare this at the beggining of the code => ESP8266WebServer server(80);
}


void bindServerCallback() {
  wm.server->on("/custom", handleRoute);
  // wm.server->on("/info",handleRoute); // can override wm!
  wm.server->on("/LED", HTTP_POST, handleLED);  // Call the 'handleLED' function when a POST request is made to URI "/LED"
}

void handleRoute() {
  Serial.println("[HTTP] handle route");
  wm.server->send(200, "text/html", "<iframe name=\"dummyframe\" id=\"dummyframe\" style=\"display: none;\"></iframe><form action=\"/LED\" target=\"dummyframe\" method=\"POST\"><input type=\"submit\" value=\"Toggle LED\"></form>");

}

void handleLED() {                          // If a POST request is made to URI /LED
  digitalWrite(atoi(output), !digitalRead(atoi(output)));     // Change the state of the LED
  server.sendHeader("Location", "/");       // Add a header to respond with a new location for the browser to go to the home page again
  server.send(303);                         // Send it back to the browser with an HTTP status 303 (See Other) to redirect
}


/*

  This void needs to be called in the loop void so it can handle the WM and the webportal.
*/
void loopDeviceWM()
{
  wm.process();
  server.handleClient();
}




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


int setupSpiffs() {
  //read configuration from FS json
  Serial.println("mounting FS...");

  if (SPIFFS.begin()) {
    Serial.println("mounted file system");
    if (SPIFFS.exists("/config.json")) {
      //file exists, reading and loading
      Serial.println("reading config file");
      File configFile = SPIFFS.open("/config.json", "r");
      if (configFile) {
        Serial.println("opened config file");
        size_t size = configFile.size();
        // Allocate a buffer to store contents of the file.
        std::unique_ptr<char[]> buf(new char[size]);

        configFile.readBytes(buf.get(), size);
        DynamicJsonDocument jsonBuffer(1024);
        //DynamicJsonBuffer jsonBuffer;
        deserializeJson(jsonBuffer, buf.get());
        //JsonObject& json = jsonBuffer.parseObject(buf.get());
        serializeJson(jsonBuffer, Serial);
        //json.printTo(Serial);

        if (!jsonBuffer.isNull()) {
          Serial.println("\nparsed json");
          //Serial.println(custom_mqtt_broker.getValue());
          strcpy(wifi_enc, jsonBuffer["wifi_enc"]);
          strcpy(entity_version, jsonBuffer["entity_version"]);
          strcpy(mqtt_port, jsonBuffer["mqtt_port"]);
          strcpy(output, jsonBuffer["output"]);
          strcpy(mqtt_broker, jsonBuffer["mqtt_broker"]);
          strcpy(mqtt_pwd, jsonBuffer["mqtt_pwd"]);
          strcpy(session_key, jsonBuffer["session_key"]);
          strcpy(entity_name, jsonBuffer["entity_name"]);
          strcpy(entity_type, jsonBuffer["entity_type"]);
          strcpy(entity_id, jsonBuffer["entity_id"]);
          strcpy(mqtt_retain, jsonBuffer["mqtt_retain"]);
          strcpy(mqtt_qos, jsonBuffer["mqtt_qos"]);

          //Serial.println("ooooooooooooooo");
          Serial.println("loaded Json");
          Serial.println("now mqtt broker is: ");
          Serial.println(mqtt_broker);
          
          return 0;
        } else {
          Serial.println("failed to load json config");
          return 1;
        }
        configFile.close();
      }
    }
    else
    {
      Serial.println("config json doesnt exist");
      return 1;
    }
   
  } else {
    Serial.println("failed to mount FS");
    return 1;
  }
  //end read

}

void setup()
{

  pinMode(atoi(output), OUTPUT);
  Serial.begin(115200);
  delay(3000);

  //diese funktion gibt 0 zurück wenn eine config json da ist. 
  if(setupSpiffs() == 0){
    Serial.println("SO, NOW:");
    Serial.println(mqtt_broker);
    custom_mqtt_broker = WiFiManagerParameter("mqttbroker", "MQTT Broker", mqtt_broker, sizeof(mqtt_broker));
  }
  else
  {
    
  }
  //an diesem punkt sind die parameter entweder leer weil keine config existiert, oder voll weil config da war. 
  
  wm.setWebServerCallback(bindServerCallback);
  wm.setSaveParamsCallback(saveParamCallback);

  //wm.addParameter(&custom_output);
  wm.addParameter(&custom_mqtt_broker);
  //wm.addParameter(&custom_mqtt_pwd);
  //wm.addParameter(&custom_session_key);
  //wm.addParameter(&custom_entity_name);
  //wm.addParameter(&custom_entity_type);
  //wm.addParameter(&custom_wifi_enc);
  //wm.addParameter(&custom_entity_version);
  //wm.addParameter(&custom_mqtt_port);
  //wm.addParameter(&custom_entity_id);
  //wm.addParameter(&custom_mqtt_retain);
  //wm.addParameter(&custom_mqtt_qos);

  // Set cutom menu via menu[] or vector
  // const char* menu[] = {"wifi","wifinoscan","info","param","close","sep","erase","restart","exit"};
  // wm.setMenu(menu,9); // custom menu array must provide length

  std::vector<const char *> menu = {"wifi", "info", "param", "update", "close", "sep", "erase", "restart", "exit"};
  wm.setMenu(menu); // custom menu, pass vector

  // set country
  wm.setCountry("US"); // setting wifi country seems to improve OSX soft ap connectivity, may help others as well

  Serial.println("Setup mode...");
  //wifiManager.resetSettings();

  setupDeviceWM();

  pinMode(TRIGGER_PIN, INPUT);

#ifdef USEOTA
  ArduinoOTA.begin();
#endif

  wm.setClass("invert");
  Serial.println("-------------");

  Serial.println(custom_mqtt_broker.getValue());
  Serial.println(String(mqtt_broker));
  Serial.println(mqtt_broker);
  Serial.println(session_key);
  client.setServer(mqtt_broker, atoi(mqtt_port));
  client.setCallback(callback);
  lastReconnectAttempt = 0;

}

void loop()
{
#ifdef USEOTA
  ArduinoOTA.handle();
#endif
  loopDeviceWM();


  if ( digitalRead(TRIGGER_PIN) == LOW ) {
    delay(2000);
    if ( digitalRead(TRIGGER_PIN) == LOW ) {
      Serial.println("BUTTON PRESSED");
      //wm.setConfigPortalTimeout(140);

      // disable captive portal redirection
      // wm.setCaptivePortalEnable(false);

      if (!wm.startConfigPortal("OnDemandAP", "12345678")) {
        Serial.println("failed to connect and hit timeout");
        delay(3000);
      }
    }
  }



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

    client.loop();
  }

}```

### Debug Messages

mounted file system reading config file opened config file {“output”:“2”,“mqtt_broker”:“192.168.1.108”,“mqtt_pwd”:“”,“session_key”:“”,“entity_name”:“”,“entity_type”:“”,“wifi_enc”:“”,“entity_version”:“”,“mqtt_port”:“1883”,“entity_id”:“”,“mqtt_retain”:“”,“mqtt_qos”:“”} parsed json loaded Json now mqtt broker is: 192.168.1.108 SO, NOW: 192.168.1.108 *WM: [3] allocating params bytes: 20 *WM: [2] Added Parameter: mqttbroker *WM: [1] <form action='/wifi' method='get'><button>Configure WiFi</button></form>

<form action='/info' method='get'><button>Info</button></form>
<form action='/param' method='get'><button>Setup</button></form>
<form action='/update' method='get'><button>Update</button></form>
<form action='/close' method='get'><button>Close</button></form>


<form action='/erase' method='get'><button class='D'>Erase</button></form>
<form action='/restart' method='get'><button>Restart</button></form>
<form action='/exit' method='get'><button>Exit</button></form>

Setup mode… *WM: [1] AutoConnect *WM: [2] esp_wifi_set_country: US *WM: [1] AutoConnect: ESP Already Connected *WM: [3] STA static IP: *WM: [2] setSTAConfig static ip not set, skipping *WM: [1] AutoConnect: SUCCESS *WM: [1] STA IP Address: 192.168.1.109 Connected to wifi network! IOT_ESP_6184038 192.168.1.109 *WM: [1] Starting Web Portal *WM: [3] dns server started with ip: *WM: [2] HTTP server started *WM: [2] WiFi Scan completed in 2182 ms

⸮⸮⸮?168.1.10 192.168.1.108 192.168.1.108

attempting connecting to mqtt


About this issue

  • Original URL
  • State: open
  • Created 4 years ago
  • Reactions: 1
  • Comments: 53 (3 by maintainers)

Commits related to this issue

Most upvoted comments

WiFiManagerParameter is missing a copy assignment operator. https://en.cppreference.com/w/cpp/language/copy_assignment

Doing this: WiFiManagerParameter custom_mqtt_broker("mqttbroker", "MQTT Broker", mqtt_broker, 20);

is different from doing this: custom_mqtt_broker = WiFiManagerParameter("mqttbroker", "MQTT Broker", mqtt_broker, 20);

what happens in that single line is this:

    • Create a new object WiFiManagerParameter(…) will call setValue(…) etc…
    • Assign the newly created object to custom_mqtt_broker, c++ generates a assignment operator where each value is copied copied, but remember… char pointers is a address, only the address get’s copied, not the string!
    • After assignment the created object in 1 get’s deleted. so the pointer _value is not valid anymore, also not in the copied version because they point to the same deleted address.

Hope that clarifies…

Is there any reason you want re-assign custom_mqtt_broker? Some comments are in German and although I got taught German at school 25 years ago it’s not that good anymore…

Made copy assignment private, so compiler will error out if you try this again.

Not sure what compiler you are using but with c++11 you can do this: WiFiManagerParameter& operator=(const WiFiManagerParameter&) = delete;

so you don’t have to set it private if you just want to prevent all users (including the class self) prevent using the copy assignment.

@dontsovcmc yes you are absolutely right, setValue does not release memory of previously allocated memory… I guess that´s why we love immutables 😃

ok this is pretty much the example, so where exactly is the problem, where in the code can we see the issue ? can you add a line in there or serial print ?

ok - above sketch never saved changed parameters to spiff… could not work anyway… but please try this one. there is an obvious serial print saying what i expect and this is not matching up with what i get at the end of the setup - so as you can see “mqtt_broker” is alright - i can use this to connect … but custom_mqtt_broker.getValue() is not. and that also shows on the portal making it unusable.


#include <FS.h>                   //this needs to be first, or it all crashes and burns...
#include <ArduinoJson.h>          //https://github.com/bblanchon/ArduinoJson
#include <WiFiManager.h> //https://github.com/tzapu/WiFiManager WiFi Configuration Magic



WiFiManager wm;

//############################################# CUSTOM PARAMETERS FOR THE WIFI MANAGER ##########################################

char mqtt_broker[16] = "192.168.100.108";


WiFiManagerParameter custom_mqtt_broker("mqttbroker", "MQTT Broker", mqtt_broker, 16);



//################################################### GENERAL VARIABLES #########################################################
bool blockWM = true; // Change this to false if you want your code to continue to run on the loop void even if you are not conected to any wifi.
//###############################################################################################################################



void saveParamCallback() {
  Serial.println("****************Should save params");
  Serial.println(mqtt_broker);
  Serial.println(custom_mqtt_broker.getValue());

  strcpy(mqtt_broker, custom_mqtt_broker.getValue());
  
  Serial.println(mqtt_broker);
  Serial.println(custom_mqtt_broker.getValue());
  
  DynamicJsonDocument json(1024);
 
  json["mqtt_broker"] = mqtt_broker;
 
    
  File configFile2 = SPIFFS.open("/config.json", "w");
    if (!configFile2) {
      Serial.println("failed to open config file for writing");
    }
    
  serializeJson(json, Serial);
  serializeJson(json, configFile2);

  configFile2.close();
  //end save
  }



/*
  This void sets the device with the WiFiManager from tzapu with custom parameters.
  Needs to be called only in the setup void.
*/

void setupDeviceWM()
{
  //Serial.println("setupDeviceWM() is running");


  // callbacks
  wm.setConfigPortalBlocking(blockWM);
  
  String ssid = "IOT_ESP_" + String(ESP.getChipId());

  if (wm.autoConnect(ssid.c_str()))
  {
    //if you get here you have connected to the WiFi
    Serial.println("Connected to wifi network!");
    Serial.println(ssid);
    Serial.println(WiFi.localIP());
    
    WiFi.mode(WIFI_STA);
    wm.startWebPortal();
  }
  else
  {
    Serial.println("Could not connect with WiFi!");
  }

  // call the code down to activate wifi so users can configure the device, event if it's connected to the local network
  //wm.startConfigPortal("IOT_Device");
  //
  }



/*
  This void needs to be called in the loop void so it can handle the WM and the webportal.
*/


void loopDeviceWM()
{
  wm.process();
  
}


int setupSpiffs() {
  //read configuration from FS json
  Serial.println("mounting FS...");

  if (SPIFFS.begin()) {
    Serial.println("mounted file system");
    if (SPIFFS.exists("/config.json")) {
      //file exists, reading and loading
      Serial.println("reading config file");
      File configFile = SPIFFS.open("/config.json", "r");
      if (configFile) {
        Serial.println("opened config file");
        size_t size = configFile.size();
        // Allocate a buffer to store contents of the file.
        std::unique_ptr<char[]> buf(new char[size]);

        configFile.readBytes(buf.get(), size);
        DynamicJsonDocument jsonBuffer(1024);
        deserializeJson(jsonBuffer, buf.get());
        serializeJson(jsonBuffer, Serial);
      
        if (!jsonBuffer.isNull()) {
          Serial.println("\nparsed json");

          strcpy(mqtt_broker, jsonBuffer["mqtt_broker"]);

          Serial.println("loaded Json");
          Serial.println("now mqtt broker is: ");
          Serial.println(mqtt_broker);
          
          return 0;
          
        } else {
          Serial.println("failed to load json config");
          return 1;
        }
        configFile.close();
      }
    }
    else
    {
      Serial.println("config json doesnt exist");
      return 1;
    }
   
  } else {
    Serial.println("failed to mount FS");
    return 1;
  }
  //end read

}

void setup()
{

  Serial.begin(115200);
  delay(3000);

  //diese funktion gibt 0 zurück wenn eine config json da ist. 
  if(setupSpiffs() == 0){
    Serial.println("SO, NOW:");
    Serial.println(mqtt_broker);
    //custom_mqtt_broker = WiFiManagerParameter("mqttbroker", "MQTT Broker", mqtt_broker, 16);
  }
  else
  {
    
  }
  // at this point the parameters are either empty because there is no config or full because there is a config
  

  wm.setSaveParamsCallback(saveParamCallback);

 
  wm.addParameter(&custom_mqtt_broker);


  std::vector<const char *> menu = {"wifi", "info", "param", "close", "sep", "erase", "restart", "exit"};
  wm.setMenu(menu); // custom menu, pass vector

  // set country
  wm.setCountry("US"); // setting wifi country seems to improve OSX soft ap connectivity, may help others as well

  Serial.println("Setup mode...");
  //wifiManager.resetSettings();
  
  setupDeviceWM();




  wm.setClass("invert");
  Serial.println("**** Issue here **** - the next four lines should be the mqtt broker adress after changing in portal and restarting but apparently custom_mqtt_broker.getValue() never gets it value of the config.json");
  Serial.println(String(custom_mqtt_broker.getValue()));
  Serial.println(custom_mqtt_broker.getValue());
  Serial.println(String(mqtt_broker));
  Serial.println(mqtt_broker);


}

void loop()
{
  
  loopDeviceWM();

}

I have no idea, your sketch still contains other stuff not needed to reproduce, hell you have 2 webservers running…

You need to let c++ decide for the size: So use ‘char mqtt_broker[] = “192.168.1.108”;’ And male sure that the length parameter for WiFiManagerParameter is large enough for a An IP address: 16 chars