WiFimanager configModeCallback - timing millis?

Hi!

Is it possible to time event in configModeCallback in the WifiManager from tzapu?
configModeCallback is what brings up the Web-portal where you can configure your WiFi and is run during "setup".
Well I can add "delay" so a human have the time to read the text on the LCD1602 i have attached.
But I also read almost everywhere that locks like the "delay()" causes should be avoided. But I cant really see how I can integrate millis() here... I use millis() in the loop to schedule things with great success but how is the correct way to do it here?

Probably not good way to do it:

void configModeCallback(WiFiManager *myWiFiManager) {
  Serial.println("##########  Entered config mode    ##################");
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Config mode...");  
  delay(5000);

  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("AccessPoint:");
  lcd.setCursor(0, 1);
  lcd.print(myWiFiManager->getConfigPortalSSID());
  delay(5000);

  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("User: username");
  lcd.setCursor(0, 1);
  lcd.print("Pass: password");
  delay(5000);

  Serial.println(WiFi.softAPIP());
  Serial.println(myWiFiManager->getConfigPortalSSID());
}

This depends of the overall logic structure of your code.
When you use millis() for non-blocking timing a part of the functionality is that
void loop() is looping.

Without seeing how you use = how you call the function

configModeCallback()

in your code it is hard to say how you should code it.

Your case is another case where it could be demontrated:

The really good help can only be given with posting the complete sketch

best regards Stefan

what clears the LCD? delay that with millis()

Sorry, the sketch was really big with a lot of Firebase-stuff in multiple tabs.
But here is a stripped down version covering the WiFi-part.
Maybe it's okay to use the delay()... But it would also be really nice to be able to toggle between messages on the display during "portal-mode". What access-point, IP-address, login credentials etc. And that (I guess?) is tricky if a delay() is used which I guess prevents the "Configuration portal" to launch. Or it's easy as a pie for someone else. I'm pretty new to programming...

// based on a stripped down version of: https://github.com/tzapu/WiFiManager/blob/master/examples/Advanced/Advanced.ino

#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);  // I2C address 0x27, 16 column and 2 rows connected to SCL --> D1, SDA -> D2
#include <WiFiManager.h>             // https://github.com/tzapu/WiFiManager
bool wm_nonblocking = false;  // change to true to use non blocking
WiFiManager wm;               // global wm instance

void setup() {
  Serial.begin(115200);
  Serial.setDebugOutput(true);
  lcd.init();  // initialize the lcd
  lcd.backlight();
  //###############################################################################
  //##################   Wifimanager   SETUP   ####################################
  //###############################################################################
  WiFi.mode(WIFI_STA);  // explicitly set mode, esp defaults to STA+AP
  delay(3000);
  Serial.println("\n Starting");
  if (wm_nonblocking) wm.setConfigPortalBlocking(false);
  std::vector<const char *> menu = { "wifi", "restart", "exit" };
  wm.setMenu(menu);
  // set dark theme
  wm.setClass("invert");
  wm.setConfigPortalTimeout(60);  // auto close configportal after n seconds //DEFAULT 30
  bool res;  // Something with WifiManager
  wm.setAPCallback(configModeCallback);  // Needed to execute other code during "Portal / Setup"
  res = wm.autoConnect("username", "password");  // password protected ap
  if (!res) {
    Serial.println("Failed to connect or hit timeout");
    // ESP.restart();
  } else {
    //if you get here you have connected to the WiFi
    Serial.println("connected...yeey :)");
  }
}  //  ############## END OF SETUP #############

void configModeCallback();   // To avoid arduino IDE bug when using TABs. List all functions here:

void loop() {
  //   if(wm_nonblocking) wm.process(); // avoid delays() in loop when non-blocking and other long running code
  //   checkButton();
  //   // put your main code here, to run repeatedly:
}

//############################################################
void configModeCallback(WiFiManager *myWiFiManager) {
  Serial.println("#########################        Entered config mode           ##################");
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Config mode...");  //Wrong order of devices in Firebase. "svi"-devicen shold be first
  delay(5000);

  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("AccessPoint:");
  lcd.setCursor(0, 1);
  lcd.print(myWiFiManager->getConfigPortalSSID());
  delay(5000);

  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("User: username");
  lcd.setCursor(0, 1);
  lcd.print("Pass: password");
  delay(5000);

  Serial.println(WiFi.softAPIP());
  Serial.println(myWiFiManager->getConfigPortalSSID());
}

as the function has a name configModeCallback

is it really a callback-function?

Your stripped-down code-version is so short that there is no single call of function
configModeCallback()

or in case it really is a callback-function there must be somewhere a registering of the callback-function.

If you do not understand what this means simply post the whole project as multiple code-sections
experienced users will know where to look at even if your code should have 2000 lines or more.

Another approach is that you describe in normal words what functionality you want to have

You have written about a LCD. Ususally WiFi-managers use a website. What do you think about the solution expecially for configuration your LCDis just showing a message
connect to WiFi named "myDevice" and type into browser 192.168.4.1 for config-menĂ¼
and then the configuration is done on the smartphone screen?

best regards Stefan

is found right about in the middle of the code.

And the instruction to use it was found here:

About 50% down on the page.

I just want to show messages on the simple display to tell the user to connect with phone/PC to the WiFimanager-portal to complete the network configuration. So the question is, is it possible somehow to run "non blocking" code? Toggle between messages etc, at the same time as the "Portal" is running.

the generalised answer to your generalised question is:

"Yes it is "somehow" possible.
Though this generalised question does not help at all.

What is so hard about posting your complete code ?
or presenting a reduced example-code

that is still able to show the process of

portal running means a website is shown and as soon as the user clicks on "SAVE" or "OK" or "REBOOT" or whatever the button on the website is named, store configuration and reboot connecting to the other network.

Do you understand ? the website-click initiates exectuting the callback-function.

So you have to add at least
what is the input-device that will initiate the toggling between different messages ?
or do you want the messages to change time after time?

best regards Stefan

In the above code everything is commented out
SO it is totally unclear what your real code is doing inside function loop()

as a very simple test
add a few lines of code to loop() that let an led blink
or print to serial monitor once per seconds

void loop() {
  blinkOnBoardLED(); 
  OncePerSecondPrintHello();
}

to see if loop is looping while you are in "portal mode"

best regards Stefan

I DID POST a complete and functional sketch describing the issue (post#4).
"would also be really nice to be able to toggle between messages on the display during "portal-mode"."
Sorry, do not know how to clarify that further.

"to see if loop is looping while you are in "portal mode""
No, it will not run since "portalMode" is executed during setup in "locking mode"

I now managed to get WiFiManager running in "non blocking mode" with the code shown below.
There is probably a better way to find out weather the portal is running or not then looking for IP 192.168.4.1.
Suggestions are appreciated!!!
Also noticed that if the wrong WiFi-password is entered inside the portal it looks like there is no way to recover(!).

And yes, this is also the complete sketch.

// WiFiManager in non blocking mode to toggle between messages on display.
// Entering the wrong WiFi-password in config portal will fuck it up. Not possible to change to correct password. My code? Do not know.

#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);  // I2C address 0x27, 16 column and 2 rows connected to SCL --> D1, SDA -> D2
#include <WiFiManager.h>             // https://github.com/tzapu/WiFiManager
WiFiManager wm;

void setup() {
  WiFi.mode(WIFI_STA);  // explicitly set mode, esp defaults to STA+AP
  // put your setup code here, to run once:
  Serial.begin(115200);
  lcd.init();  // initialize the lcd
  lcd.backlight();

  //reset settings - wipe credentials for testing
  //wm.resetSettings();

  wm.setConfigPortalBlocking(false);
  std::vector<const char *> menu = { "wifi", "restart", "exit" };  // Added by me...
  wm.setMenu(menu);
  wm.setConfigPortalTimeout(60);
  //automatically connect using saved credentials if they exist
  //If connection fails it starts an access point with the specified name
  if (wm.autoConnect("MyPortal", "password")) {
    Serial.println("connected...yeey)");
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Connected!!!");
    // } else {
    //   Serial.println("Configportal running");    
    //   runningConfigPortal = true;
  }
}

unsigned int currentMillis;
unsigned int startMillis;
unsigned int WiFiErrorCount;
bool portalMode;
bool startingUp = true;

void loop() {
  wm.process();
  // put your main code here, to run repeatedly:

  currentMillis = millis();
  if (currentMillis - startMillis > 2000) {  //test whether the period has elapsed
    String checkMode;
    checkMode = WiFi.softAPIP().toString();  // See if this returns 192.168.4.1 = Portal Mode. Did not manage to find any other way to get notice
    Serial.println(checkMode);               // of when exiting from "PortalMod".
    if (checkMode == "192.168.4.1") {
      Serial.println("###################################### IN PORTAL MODE ################### ");
      portalMode = true;
      startingUp = true;
    } else {
      portalMode = false;
    }
    Serial.print("Every second - WiFi.status is : ");
    Serial.println(WiFi.status());
    if (WiFi.status() == WL_CONNECTED) {  //
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Connected!!!");
      WiFiErrorCount = 0;
      startingUp = false;
    } else if ((WiFi.status() != WL_CONNECTED) && (portalMode == false)) {
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("NOT Connected!!!");
      lcd.setCursor(0, 1);
      lcd.print("Restarting.");
      lcd.print(WiFiErrorCount);
      WiFiErrorCount++;
      if ((WiFiErrorCount > 100) && (startingUp == false)) {  // Restart device after about 200 sec if no WiFi.
        ESP.restart();
      }
    }
    startMillis = currentMillis;
  }

  if ((WiFi.status() != WL_CONNECTED) && (portalMode == true)) {  // Show configuration messages on display if no WiFi and in PortalMode.
    portalDisplayMessages();
  }

  if (WiFi.status() == WL_CONNECTED) {
    // futureCrappyCode();      // Code dependent on an active WiFi connection.
  }
}


void portalDisplayMessages() {
  int currentMillis;
  static unsigned int startMillis;
  static unsigned int messageCount = 0;

  currentMillis = millis();
  if (currentMillis - startMillis > 10000) {  //test whether the period has elapsed
    Serial.println("Running portal,  10 seconds message switch");

    switch (messageCount) {
      case 0:
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("AccessPoint:");
        lcd.setCursor(0, 1);
        lcd.print("MyPortal");
        messageCount++;
        break;

      case 1:
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("Password:");
        lcd.setCursor(0, 1);
        lcd.print("gggggggg");
        messageCount = 0;
    }
    startMillis = currentMillis;
  }
}

By adding what is doing the toggling: it is time (despite of pressing a button)

what do you think is this line of code doing ?

in which part of your code is this line located?

it IS inside

void loop() {
  wm.process();
  // put your main code here, to run repeatedly:

  currentMillis = millis();
  if (currentMillis - startMillis > 2000) {  //test whether the period has elapsed
    String checkMode;
    ....      
    if ((WiFiErrorCount > 100) && (startingUp == false)) {  // Restart device after about 200 sec if no WiFi.
        ESP.restart();
      }
    }
    startMillis = currentMillis;
  }

  if ((WiFi.status() != WL_CONNECTED) && (portalMode == true)) {  // Show configuration messages on display if no WiFi and in PortalMode.
    portalDisplayMessages();
  }

  if (WiFi.status() == WL_CONNECTED) {
    // futureCrappyCode();      // Code dependent on an active WiFi connection.
  }
}

and this means
void loop() is looping

best regards Stefan

Stefan, What is toggling?
Pretty obvious it's some timing when spending 20 sec looking in the code.
And what you are commenting now is the new functional sketch where I solved the problem by using "non blocking portal mode" instead of "blocking portal mode".

Actually I must ask.. Why are you commenting in this thread at all?
Your long and confusing answers has not assisted in any way to come closer to a solution.
It's better if you comment on subjects where you have knowledge since it will benefit all. Shorter threads, easier to overview etc.

Well, after way to many hours I managed to sort it out my self, so problem solved.
Even if the solution is dodgy since I'm a rookie :wink:

trying to explain how the code really works internally

But you seem to be a person that is fixed on "there must be a "3-lines_of_code_solution"
and I will find it by trying this trying that, by trying this trying that by trying this trying that by trying this trying that.....

At last with this method you found a solution. Finding the solution took you

because you seem to do it without really understanding how it works.
Maybe after all these hours you do understand how it works.

It is very often the case that stepping back from the actual detail and learning how something works on the next higher level takes less time than
by trying this trying that, by trying this trying that by trying this trying that by trying this trying that.....

on the actual detail.

best regards Stefan

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.