espressif / arduino-esp32

Arduino core for the ESP32
GNU Lesser General Public License v2.1
13.26k stars 7.34k forks source link

WiFi Auto Reconnect Still Not Working - Is there a best practice to guarantee connection? #653

Closed vseven closed 5 years ago

vseven commented 6 years ago

Board: ModeMCU ESP32 Dev Module Core Installation/update date: 15/Sep/2017 IDE name: Arduino IDE

It seems there is no auto reconnect logic allowing the ESP32 to reconnect when the connection drops or if there is its not working properly. I have had completely random results with my ESP32 board, sometimes its up for as little as 30 minutes and at most 18 - 20 hours. WiFi is dropping and doesn't want to reconnect.

The library I am using for WiFi is watching the WiFi event and on a disconnect its trying to reconnect which helps but sometimes it fails the reconnect and then that's it...I have to reboot. There is no sleep/low power mode at all involved and the device is constantly powered by 3.3v in. There was a case opened regarding this, https://github.com/espressif/arduino-esp32/issues/353, but its closed without any real answer (says auto connect is kind of implemented...not sure what that means).

I guess the question comes down to is auto reconnect implemented in the code itself, reliably, and if not what is the best Arduino code way of making sure it is connected?

-Allan

everslick commented 6 years ago

definitly the SDK should try to reconnect automotically. That is the whole point of having WiFi.setAutoReconnect(true).

vseven commented 6 years ago

@everslick - I agree completely, it doesn't seem to work which is why I posted this originally 3+ months ago. The WiFi.setAutoReconnect(true) doesn't seem to make it reconnect which is ironic to say the least. The only thing that works is to reboot the controller and let it go back through its normal connect (which isn't going to work for me when controlling LEDs as they turn off) or doing the full disconnect and reconnect.

@zhangyanjiaoesp - So you are saying WiFi.setAutoReconnect(true) simply doesn't work? And to work around we have to call the disconnect and reconnect with the SSID and password again? If this is true will it be fixed or at least the documentation updated to say it doesn't work?

rrobinet commented 6 years ago

I have a similar issue, After reseting the by software using the following sequence: WiFi.disconnect(); //Ensure current ssid/password is erased delay (1000); ESP.restart(); The ESP reboots but never connects to the AP until an hardware reset. The function Wifi.disconnect () is also not working correctly. Robert

rrobinet commented 6 years ago

The hard way is to connect a GPIO pin to the EN one and force a System reset (GPIO Low) in case reboot/restart or wifi (re)connection is needed.

vseven commented 6 years ago

Don't do the disconnect. Just restart works for me. But again...shouldn't have to restart if WiFi.setAutoReconnect(true) worked properly.

rrobinet commented 6 years ago

It should be nice to have the Wifi.disconnect or autoreconnect working, but what's the point, if there is a Wifi connection issue, this is a major one in case of ESP32 (all subsequent applications probably relies on Wifi), so the ultimate solution is to try a hardware reset, if this one fails ... bye bye ESP32 usage.

vseven commented 6 years ago

Rebooting is NOT a solution. I'm using this for RGB LED control and rebooting resets the lights to off. If there is a function that tells the ESP that if it loses WiFi it should keep retrying to connect then that function should actually work as documented.

rrobinet commented 6 years ago

OK, I have tried to reset the ESP through a GPIO, but it looks that ESP doesn't like suicide, so it doesn't work without an external device. So I agreed the only solution that left is that the WiFi disconnect, the ESP restart or the Wifi auto reconnect are actually working. Another issue for which we have to wait for a functional ESP module (I note that as far I could test it, the I2C protocol is another one for which I am waiting for a solution). ESP32 is far to be reliable until now .... Robert

rrobinet commented 6 years ago

and I didn't mention the SPI interface ...

everslick commented 6 years ago

esp_restart_noos();

For when ESP.restart() doesn't work.

rrobinet commented 6 years ago

I am using Arduino IDE to configure a WeMos Lolin32. I use the function:

void unitReset ()
 {
#ifdef DEBUGGING
  Serial.println ("Coordinator will REBOOT NOW ....");
#endif    
  WiFi.disconnect();                          //Ensure current  ssid/password is erased
  delay (1000);
  ESP.restart();
 }

When WeMos connected in WiFi.mode(WIFI_STA), I call this function from MQTT. It actually restarts the system and the sketch starts, but Wifi (can't synchronise from that point, connection attempts goes in a endless loop). A manual reset solves it. However the same function called from with WiFi.mode(WIFI_STA) via telnet, works.

zhangyanjiaoesp commented 6 years ago

@vseven @everslick @rrobinet You misunderstand the meaning of the function WiFi.setAutoReconnect(true) . In our code, WiFi.setAutoReconnect(true) is not mean to reconnect wifi utomotically. It means if the ESP32 has connected to wifi before, then when the system restarts next time, it wiil connect the last connected wifi. So we will add some comments in the code. Sorry to have affected your work.

everslick commented 6 years ago

@zhangyanjiaoesp Sorry for stating it like that: That is just "wrong". That API was introduced for the ESP8266 and it did exactly that: reconnecting wifi automatically. What you describe is what the WiFi.setAutoConnect(); method is for. You cannot change the semantics of a well established API at will.

Besides, even when the API was meant to work like you said, the function naming would be incredible bad and misleading.

Anyway. We are talking IoT devices here. The default should be to stay connected to the network no matter what. If anything, there should be functions to disable automatic reconnects and not to require the API user to jump through hoops to make it behave that way.

zhangyanjiaoesp commented 6 years ago

@vseven @everslick @rrobinet Please look at here, it tells user this function works when powered on.

rrobinet commented 6 years ago

ESP.restart issue, correction. Well the script above was working with an ESP8266 and not with an ESP32, however after some tests, the issue is the usage of the WiFi.disconnect (true), before the ESP.restart(). This function for ESP32 should be place at the Wifi initialisation (see https://github.com/espressif/arduino-esp32/pull/466) Something like:

<snip>
  WiFi.disconnect(true);                                      // Clear Wifi Credentials
  WiFi.persistent(false);                                     // Avoid to store Wifi configuration in Flash
  WiFi.mode(WIFI_STA);                                        // Ensure WiFi mode is Station 
  Serial.println("Now Connecting to Access Point ...");  
  // Connect to the Access Point
  WiFi.begin(ssid,key);
<snip>

and the unit reset should be simply:

void unitReset ()
 {
#ifdef DEBUGGING
  Serial.println ("Coordinator will REBOOT NOW ....");
#endif    
  delay (1000);
  ESP.restart();
 }
Markusenz commented 6 years ago

Can you confirm the following, which I understand so far when reading this thread:

sidoh commented 6 years ago

@Markusenz, I can confirm that https://github.com/espressif/arduino-esp32/issues/653#issuecomment-355659659 seems to always work for me. It seems like the only reference to getAutoReconnect is the link I pasted in the comment, which wouldn't handle disconnects well, if it all.

@zhangyanjiaoesp, thanks for your help on this. :)

You misunderstand the meaning of the function WiFi.setAutoReconnect(true) . In our code, WiFi.setAutoReconnect(true) is not mean to reconnect wifi utomotically. It means if the ESP32 has connected to wifi before, then when the system restarts next time, it wiil connect the last connected wifi.

The method you linked to is setAutoConnect, not setAutoReconnect. I think these methods are different. setAutoReconnect is here. It just sets a flag, and I think the only place that flag is used is here.

Given the name of the method, and how that flag is getting used internally, it seems like this method is supposed to do what people are assuming it does -- enable/disable automatic attempts to reconnect to an AP after a disconnect.

My thought is that this feature is just not working as expected, and I think it's possibly because internally the SDK is using WiFi.begin(), which will clear the SSID if the saved AP doesn't exist, as I discovered above.

vseven commented 6 years ago

So this is how it seems to be happening. Can the SDK be updated to NOT clear out the AP if it doesn't see it instantly. Or to do a WiFi.Begin using the last known SSID and password if WiFi.setAutoReconnect(true) or am I missing something?

sidoh commented 6 years ago

If my thinking/digging is correct, I really doubt this behavior is intentional or expected. It seems likely that setAutoReconnect is meant to have the functionality that folks in this thread are expecting it to, and it just has some bugs.

My suggestion would be to work around it for now. In my own project I just attach an event handler that does

WiFi.disconnect(true);
WiFi.begin(ssid, passwd);

and it works for me.

It seems like reconnection is currently being handled by the Arduino SDK rather than the underlying stuff. With the ESP8266 Arduino SDK, reconnection is handled by the Non-OS SDK. So a fix to the ESP32 Arduino SDK will probably look a lot like this external workaround would anyway (again -- assuming my thinking is correct. I could certainly be wrong).

edit - here is the relevant section in my code that handles reconnection.

zhangyanjiaoesp commented 6 years ago

@Markusenz you are right. @vseven @sidoh I agree with @sidoh , you can work around it for now. We will implement the auto connect function, and we have known the importance of this issue, but we need time to provide you a perfect solution.

everslick commented 6 years ago

After some digging I found this to work pretty well:

static bool sta_was_connected = false;

static void poll_connection(void) {                                         
#ifdef ESP32
  // this is a crude workaround due to the inability of
  // the ESP32 to reconnect to an accesspoint automatically.
  //
  // https://github.com/espressif/arduino-esp32/issues/653

  static uint32_t ms = millis();

  if (!WiFi.isConnected() && (millis() - ms) > 1000 * 5) {
    ms = millis();

    if (sta_was_connected) WiFi.reconnect(); else WiFi.begin();
  }
#endif
}

loop() {
  poll_connection();
}

In the WiFi event handler for SYSTEM_EVENT_STA_GOT_IP you have to set sta_was_connected to true.

This will also work when the accesspoint was not available when the ESP32 booted.

The advantage is, that it does not clear the STA config. This is especially useful if you have set a static IP configuration (not using DHCP).

tablatronix commented 6 years ago

do you get a [D][WiFiGeneric.cpp:293] _eventCallback(): Event: 8 - STA_LOST_IP if you wait long enough ( there is a delay )

I am gonna try

    } else if(event->event_id == SYSTEM_EVENT_STA_LOST_IP) {
        if(WiFi.getAutoReconnect()){
            WiFi.begin();
        }
mickeypop commented 6 years ago

Here is a working solution that bypasses some issues with the WiFi library. Note the while loops after a WiFi.begin(). I have found the connection delay varies depending on the router and encryption settings, AES, WPA2 seem best, fastest and most reliable.

To that end waiting till you know a connection worked but making sure you don't lock up, pretty much does it.

I noted some are calling WiFi.disconnect(). Be careful to use WiFi.persistent(false); with it or every time you recover you are re-writing the NV FLASH and will brick it when the FLASH dies.

Partial CODE SAMPLE

setup()
{
  WiFi.begin( rssiSSID , password );

  int WLcount = 0;
  while (WiFi.status() != WL_CONNECTED && WLcount < 250 ) 
  {
    delay( 100 );
    #ifdef DEBUG
       Serial.print(".");
    #endif
    ++WLcount;
  }
}

void loop() 
{
  if (WiFi.status() ==  WL_CONNECTED) 
  {
    // PUT_YOUR_UP_TIME_CODE_HERE   

    #ifdef DEBUG
       Serial.print("C");
       if (UpCount >= 20)   // just keep terminal from scrolling sideways
       {
        UpCount = 0;
        Serial.println();
       }
       ++UpCount;
    #endif

      // END WiFi connected loop()
  } else
  {
    // PUT_YOUR_DOWN_TIME_CODE_HERE
    //  WiFi DOWN loop

    #ifdef DEBUG
        WFstatus = getWifiStatus( WFstatus );
    #endif

    WiFi.begin( rssiSSID , password );
    int WLcount = 0;
    // loop - depending on router, connect can be from 4 - 20 seconds
    // usually longer to reconnect than the connect at boot
    // lopping till reconnect seems to let it settle
    // usually around 80 count to breakout
    while (WiFi.status() != WL_CONNECTED && WLcount < 250 ) 
    {
        delay( 100 );
        #ifdef DEBUG  
            Serial.print(".");
            // just keep terminal from scrolling sideways in test
            if (UpCount >= 20)
            {
                UpCount = 0;
                Serial.println();
            }
            ++UpCount;
        #endif
        ++WLcount;
    }
    delay( 1000 );
  }  // END WiFi DOWN 
} // END loop()

int getWifiStatus( int WiFiStatus  )
{
  WiFiStatus = WiFi.status();
  Serial.print("\tStatus "); Serial.print( WiFiStatus );
  switch( WiFiStatus )
     {
        case WL_IDLE_STATUS :           // WL_IDLE_STATUS     = 0, 
                Serial.println(", WiFi IDLE "); 
                break;
        case WL_NO_SSID_AVAIL:          // WL_NO_SSID_AVAIL   = 1,
                Serial.println(", NO SSID AVAIL ");
                break;
        case WL_SCAN_COMPLETED:         // WL_SCAN_COMPLETED  = 2,
                Serial.println(", WiFi SCAN_COMPLETED "); 
                break;
        case WL_CONNECTED:      // WL_CONNECTED       = 3,
                Serial.println(", WiFi CONNECTED "); 
                WiFi.persistent(true);  
                break;
        case WL_CONNECT_FAILED:         // WL_CONNECT_FAILED  = 4,
                Serial.println(", WiFi WL_CONNECT FAILED"); 
                break;
        case WL_CONNECTION_LOST:        // WL_CONNECTION_LOST = 5,
                Serial.println(", WiFi CONNECTION LOST");
                WiFi.persistent(false); // don't keep writing FLASH
                break;   
        case WL_DISCONNECTED:            // WL_DISCONNECTED    = 6
                Serial.println(", WiFi DISCONNECTED ==");
                break;
  }
  return WiFiStatus;
}  // END getWifiStatus()

====== it takes on average 8-15 seconds to detect mode change note "."'s are connecting "C"'s are Connected

OUTPUT
CCCCCCCCC     Status 5, WiFi CONNECTION LOST    Unplugged Router here
.........
....................                            Trying
 More lines of dots...
....................
...........       Status 1, NO SSID AVAIL       Gave up, Changed Modes
.........                                       Replugged Router here
....................
................CCCC                            TaDa I'm Back...
CCCCCCCCCCCCCCCCCCCC
tablatronix commented 6 years ago

I am using this, seems to work for me

void WiFiEvent(WiFiEvent_t event){
    if(event == SYSTEM_EVENT_STA_DISCONNECTED){
      Serial.println("Event: SYSTEM_EVENT_STA_DISCONNECTED, reconnecting");
      WiFi.reconnect();
    }
}

if(WiFi.getAutoReconnect()) WiFi.onEvent(WiFiEvent);
thefatmoop commented 6 years ago

I guess my apartment with the 50 APs nearby is really a great place to test this issue. The solution from tablatronix causes my esp32 to dump and I don't see how mickeypop's solution would do any good, which it didn't help. I've found that restarting the wifi connection works fairly well but even that requires a hard power reset every once in a while. On the side i've got an esp8266 in the same environment that never requires any manual intervention. I've tried a few other suggestions here without luck.

I think it's amazing all the development that's done. Frankly I don't have the skills to come up with a solution. If anyone has something that they want to try in a harsh environment, feel free to send me tests. We really need the esp32 to have a solid connection and handle intermittent wifi gracefully.

Edit: after trying a lot of stuff: @tablatronix If I run this line too fast it crashes/gives backtrace. Calling every few seconds gave me no problems. Now to let it run for a few days to see what happens if(WiFi.getAutoReconnect()) WiFi.onEvent(WiFiEvent); Edit2: lasted 30 minutes before dropping off

stickbreaker commented 6 years ago

@thefatmoop I ran into a WiFi reconnect issue that ended up being a NVS corruption issue. #1147 I rewrote a sketch to dump the nvs data. Try it and capture the output. It may show something. Show NVS Keys

Chuck.

mickeypop commented 6 years ago

thefatmoop

Both solutions should work. As i noted; "Here is a working solution that bypasses some issues with the WiFi library."

While one bypasses some library issues the other uses the WiFi.onEvent() service, both simply detect when a connection is broken and re-initiate a new connection.

While some have noted after several hours they keep getting bumped, this is almost certainly a function of the lease time of DHCP server in the router.

If the lease time of the router is not the same sometimes devices "forget" to update causing a no IP address even though sometimes the WiFi connect is still there.

Rebooting may reconnect, but does not address the WHY of getting disconnected and often applications can get out of sync if you are simply rebooting.

So reconnecting without rebooting is often a necessity.

tablatronix commented 6 years ago

reconnect does not redo dhcp, I found this out when trying to change hostname and reconnect, was gonna file it as a bug.

1technophile commented 6 years ago

Solution from @tablatronix is working for me thanks! @thefatmoop you can check the implementation on OpenMQTTGateway.ino code.

The code is called after MQTT disconnection, if I put the code outside this condition the ESP dump indeed.

thrazu commented 6 years ago

If WiFi.reconnect() reconnects, but MQTT client not, you can make another setup_wifi(): with disconnect() delay() and begin(), after a few client reconnect attempts and it works great within the new connection. But what happens when the MQTT server is down?

tablatronix commented 6 years ago

Thats an application level problem..

beegee-tokyo commented 6 years ago

Added mickeypop code proposal to the Wiki

thrazu commented 6 years ago

Sorry. I'm a beginner in arduino/esp programming. I'm also confronting with the bugs/problems of wifi connect and reconnect. My part of code which manages both the WiFi & MQTT client (PubSubClient), and which actually works on an ESP32 from Adafruit/Huzzah32:

void setupWiFi() {
  WiFi.disconnect(true);
  WiFi.begin(WLAN_SSID, WLAN_PASS);
  WiFi.waitForConnectResult();
}

boolean clientReconnect() {
  if(client.connect("esp32_client")) {
    client.subscribe("/test");
  }
  return client.connected();
}

boolean wifi_connected_once = false;
unsigned long last_client_reconnect_attempt = 0;
int client_reconnect_attempts = 0;

void setup() {  
  client.setServer(MQTT_SERVER, 1883);
  client.setCallback(client_callback);
}

void loop() {
  unsigned long loop_start = millis();

  if(WiFi.isConnected()) {
    // WiFi connected
    if(client.connected()) {
      // client connected
      // publish data every 5 seconds
      if(loop_start - last_client_publish >= 5000) {
        client_publish_data();
        last_client_publish = loop_start;
      }
      client.loop();
    } else {
      // client not connected
      // try reconnect a few times every 5 seconds
      if(client_reconnect_attempts <= 5) {
        if(loop_start - last_client_reconnect_attempt > 5000) {
          client_reconnect_attempts++;
          if(clientReconnect()) {
            // client connected
            client_reconnect_attempts = 0;
          }
          last_client_reconnect_attempt = loop_start;
        }
      } else {
        // maybe MQTT server is down
        // try reconnect in 5 minutes
        if(loop_start - last_client_reconnect_attempt > 300000) {
          last_client_reconnect_attempt = loop_start;
          client_reconnect_attempts = 0;
        }
      }
    }
  } else {
    // WiFi not connected
    // try connect for the first time or 
    // try reconnect every 2 minutes
    if((loop_start - last_client_reconnect_attempt > 120000) || wifi_connected_once == false) {
      last_client_reconnect_attempt = loop_start;
      wifi_connected_once = true;
      client_reconnect_attempts = 0;
      setupWiFi();
    }
  }
}

Tested with some router reboots and the code seems working without the need of ESP reboot. Do you have any much better suggestion?

josmunpav commented 6 years ago

This issue is killing me. It's happening randomly sometimes in the first hour sometimes after six hours while running without issues. I've tried all sorts of configurations and none of them is reliable. Restarting the ESP by software or hardware is the last resort that actually works but that's not a viable solution for my product.

Last time I left it running and tried more than FOUR THOUSANDS attempts, none of them with success.

I have tried so far:

1) Enabling autoReconnect and calling reconnect 2) Disabling autoReconnect and manually disconnecting and reconnecting. In this configuration I've tried both methods of completely switching off the antenna or not. Does not work in any mode.

Here you have some logs (this is actually running right now with more than 600 attempts to reconnect on a perfectly working router (TP-LINK):

WARNING: WiFi lost connection. Trying reconnection attempt 632 on next iteration Triggering WiFi Reconnection attempt 632 I (14944038) wifi: mode : softAP (30:ae:a4:1a:ca:1d) Creating WiFi with SSID 'Nano BAB - Development' and password '#######' Connecting to WiFi 'TP-LINK_A8FB38' [D][WiFiGeneric.cpp:293] _eventCallback(): Event: 3 - STA_STOP [D][WiFiGeneric.cpp:293] _eventCallback(): Event: 2 - STA_START [WiFi-event] event: 2 [D][WiFiGeneric.cpp:293] _eventCallback(): Event: 5 - STA_DISCONNECTED [W][WiFiGeneric.cpp:298] _eventCallback(): Reason: 201 - AUTH_FAIL

As you can see is failing on authentication however the password is correct. On some previous attempt (number 578!!) from the same example is raising error 2:

WARNING: WiFi lost connection. Trying reconnection attempt 578 on next iteration Triggering WiFi Reconnection attempt 578 I (14134199) wifi: mode : softAP (30:ae:a4:1a:ca:1d) Creating WiFi with SSID 'Nano BAB - Development' and password '#########' [D][WiFiGeneric.cpp:293] _eventCallback(): Event: 3 - STA_STOP [WiFi-event] event: 3 Connecting to WiFi 'TP-LINK_A8FB38' [D][WiFiGeneric.cpp:293] _eventCallback(): Event: 13 - AP_START [WiFi-event] event: 13I (14134890) wifi: mode : sta (30:ae:a4:1a:ca:1c) + softAP (30:ae:a4:1a:ca:1d) [D][WiFiGeneric.cpp:293] _eventCallback(): Event: 2 - STA_START*

[WiFi-event] event: 2[D][WiFiGeneric.cpp:293] _eventCallback(): Event: 2 - STA_START [WiFi-event] event: 2I (14137748) wifi: ap channel adjust o:1,1 n:6,1 I (14137749) wifi: n:6 1, o:1 0, ap:6 1, sta:6 1, prof:1 I (14138422) wifi: state: init -> auth (b0) I (14139423) wifi: state: auth -> init (2) I (14139424) wifi: n:6 0, o:6 1, ap:6 1, sta:6 1, prof:6 [D][WiFiGeneric.cpp:293] _eventCallback(): Event: 5 - STA_DISCONNECTED [W][WiFiGeneric.cpp:298] _eventCallback(): Reason: 2 - AUTH_EXPIRE

It's always one of the two errors. In the end is simply that it does not reconnect.

Funny thing is I can disconnect manually the router by pulling the power cord for a few minutes, my code detects the disconnectiong and starts retrying and then my system reconnects OK when back in, however if the router is working normally this issue eventually happens and the ESP simply does not reconnect.

Btw, I am running with:

Running on SDK: 'v3.1-dev-239-g1c3dd23f-dirty' CPU Frequency: 240MHz WiFi both creating its own private WiFi and connecting to another one with access to the internet

tablatronix commented 6 years ago

When was the last time you pulled in from repo ?

1132

you only posted logs, no sketch or reconnect solution.

josmunpav commented 6 years ago

Last time was about a week or so. My SDK version is 3.1-dev-239. Sorry I did not add the code because I basically tested all the solutions within the post. At startup I call something similar to:

WiFi.disconnect(true);
WiFi.softAP(wifiName, wifiPassword);
WiFi.begin(connectoToWifiSSID, connectToWifiPassword);

Then I handle WiFi events and especially the event SYSTEM_EVENT_STA_DISCONNECTED. When this event happens, I have tried 3 different ways of reconnection:

1) When Wifi autoreconnect was enabled I left the system to handle itself the reconnection 2) I tried by disabling autoreconnect and on that event calling WiFi.reconnect() 3) Latest one I am trying is to disconnect by turning off the radio and connecting again if no other disconnection as triggered it. I've got something like:

reconnections++;
needsReconnection = true;
reconnectionDetection = millis();
Serial.printf("\r\nWARNING: WiFi lost connection. Trying reconnection attempt %d on next iteration\r\n", reconnections);

needsReconnection is a flag that is checked in the main loop and triggers again the connection by basically running the first 3 lines of code.

Hope it makes sense now ;-)

Not sure if there is another way of doing it.

I forgot to mention, I am running too a mongoose server to implement a Rest API, allowing a max of 3 concurrent connections. Not sure if that could be the cause of it.

tablatronix commented 6 years ago
  1. There is no autoreconnect, that is what this issue is for.
  2. WiFi.reconnect might not be the same as disconnect, begin() ( dhcp etc )
  3. This might be mode specific , without code nobody knows what you are doing, no idea how you are handling events, or "turning radio off"

I'd suggest pulling in changes and making a simple test case.

mickeypop commented 6 years ago

josmunpav

your issue may be WiFi mode's

your code

WiFi.softAP(wifiName, wifiPassword);
WiFi.begin(connectoToWifiSSID, connectToWifiPassword);

You are running mixed Modes. WiFi.softAP(); default is WIFI_MODE_AP mode

WiFi.begin(); default is WIFI_AP_STA mode

if you proceed with the WIFI_MODE_APSTA mode (mixed mode) they should not change and WiFi EVENT will not get mixed up with different modes.

WiFi.mode( WIFI_MODE_APSTA );
WiFi.softAP(wifiName, wifiPassword);
WiFi.begin(connectoToWifiSSID, connectToWifiPassword);

REF INFO in esp_wifi_types.h

typedef enum {
    WIFI_MODE_NULL = 0,  /**< null mode */
    WIFI_MODE_STA,       /**< WiFi station mode */
    WIFI_MODE_AP,        /**< WiFi soft-AP mode */
    WIFI_MODE_APSTA,     /**< WiFi station + soft-AP mode */
    WIFI_MODE_MAX
} wifi_mode_t;

in wifitypes.h

typedef enum {
    WL_NO_SHIELD        = 255,   // for compatibility with WiFi Shield library
    WL_IDLE_STATUS      = 0,
    WL_NO_SSID_AVAIL    = 1,
    WL_SCAN_COMPLETED   = 2,
    WL_CONNECTED        = 3,
    WL_CONNECT_FAILED   = 4,
    WL_CONNECTION_LOST  = 5,
    WL_DISCONNECTED     = 6
} wl_status_t;
josmunpav commented 6 years ago

Hi mickeypop ,

I am testing your solution of:


WiFi.mode( WIFI_MODE_APSTA );
WiFi.softAP(wifiName, wifiPassword);
WiFi.begin(connectoToWifiSSID, connectToWifiPassword);

I am calling WiFi.reconnect() when event SYSTEM_EVENT_STA_DISCONNECTED happens, which I tried by manually disconnecting the router and seems to be working (that bit worked before too).

So far it has been working overnight for 7 hours non stop on 2 different ESP32. I've been pinging them every 5 seconds and no issues so far. Could not imagine that mixed mode declaration could be the reason, I thought it was automatically enabled when calling WiFi.begin and WiFi.softAP() . Fingers crossed. I will start now with more heavy testing to confirm it is the solution to the problems I am facing.

By the way, THANK YOU so much!!

beegee-tokyo commented 6 years ago

@mickeypop @josmunpav thanks for sharing your findings. I added it to the Wiki

tablatronix commented 6 years ago

This makes no sense this indicates that there is a bug in enablesta or enablesoftap if setting mode beforehand changes the outcome. That is why I suggested this is mode specific, workarounds should not be needed. So reproduction code would be nice

vseven commented 6 years ago

A lot of this doesn't make sense as @everslick clearly pointed out above: https://github.com/espressif/arduino-esp32/issues/653#issuecomment-356515973. In fact I cant believe I posted this 6 months ago and were still talking about it when it should have never been a issue in the first place.

Why something is called "autoReconnect" that doesn't auto reconnect is beyond puzzling. Everyone seems to be making up there own code to get through this shortcoming/bug. I'm going to pull a fresh copy of the code and reflash per @tablatronix suggestion but the whole point of this is we shouldn't have to do any of this....it should work like the ESP8266 and reconnect on it's own!

I'm personally still having issue with the chip completely locking up on occasion when it gets into this disconnect loop. I have it counting to 10 and restarting but randomly (1 out of 15 or so reboots) it doesn't reboot and just hard locks which requires a cold reboot. I'd switch to the ESP8266 in a heartbeat if it had better/more analog inputs but it unfortunately doesn't. Not that the ESP32 is very good at that either (https://www.esp32.com/viewtopic.php?f=19&t=2881).

tablatronix commented 6 years ago

In esp8266 autoreconnect is implemented in SDK, in esp32 there is no implementation, so it was added to the library to bring some form of compatibility, although it is only implemented for WIFI_REASON_AUTH_EXPIRE.

It can be implemented but it needs to be worked out, and this library is still alpha so there really should be no expectation, the sdk is subject to change, the entire event system is subject to change. So implementing core features like this takes time.

Not to mention, if espressif implements this in SDK , then we just wasted all our time.

tablatronix commented 6 years ago

When I say it needs to be worked out, I mean there are several outstanding issues that need to be resolved. That is why I ask for test sketches for people the above event solution is failing for.

** reconnect does not enablesta, it just returns false, you should always be checking for return values!

If using my workaround above, I suggest disabling autoreconnect to avoid 2 of those bugs.

josmunpav commented 6 years ago

Hi guys I am back with a sample that reproduce the issues I am facing. The sample is full of comments but basically consists into:

  1. Two tasks: main one and web/wifi (implemented by mongoose 6.11 library)
  2. Some shared objects to do dummy tasks like setting PWM on a pin, reading average ADC value and a shared int counter
  3. A test page at http://your_esp32_ip/ that you can leave it running and will let you know when it disconnects. It also shows the values of the dummy tasks being performed
  4. A semaphore to avoid data corruption between tasks. Main task does changes on pwm pin, reads from ADC and increase the counter. Web task presents that data at the home page.
  5. Typical WiFi methods for connecting, disconnecting and handling WiFi events.
  6. It runs on APSTA mode so you need to configure your own WiFi (your WiFi needs internet connection as the home web page uses jQuery from a CDN to make API calls implemented by the ESP32 in the sample)

What I have found so far is that if you disable the dummy tasks (there is a flag for it) then both tasks run fine endlessly. If you enable them, then eventually (sometimes can take hours but normally happens within the first hour) the ESP32 disconnects from the WiFi and cannot reconnect, running the connection attempt every 10 seconds without success all the time.

I think there is some interference between ADC or PWM library (implemented by esp32-hal-ledc.h), because I could not reproduce the issue when the main task does nothing but doing a dummy waiting.

Something else I noticed is when the disconnection happens the WiFi signal for the AP decreases a lot. I checked this on my smartphone.

This is the typical WiFi log messages you can find when it fails:

[WiFi-event] event: 5
Disconnected from WiFi. Trying connection again in 10000ms
Web/Main Task is up and running. Shared counter is 11309, Average ADC Value = 1305.000000, PWM Value = 0
Connecting to WiFi 'TP-LINK_A8FB38' with password: 'C1A8FB38' on connection attempt = 108
Oops, there was a problem when connecting. It returned error: 1[D][WiFiGeneric.cpp:293] _eventCallback(): Event: 5 - STA_DISCONNECTED
[W][WiFiGeneric.cpp:298] _eventCallback(): Reason: 2 - AUTH_EXPIRE

Please find the attached source code and sample pages:

working not_working

ESP32_APSTA_Mode_Disconnection_Test.zip

PS: My real app is doing kind of the same. Starting APSTA mode with two tasks one for updating sensors, devices and GPIOS and the second for handling WiFi and the webserver implemented by mongoose and facing the very same issue.

AIWIndustries commented 6 years ago

I built this sketch to test the connection, get time every 10 seconds 10 times, disconnect wifi, reconnect wifi. Seems to work pretty good so I'm implementing in my other code to run for a few days because I was having re-connection issues.

#include <WiFi.h>
#include "time.h"

const char* ssid       = "ssid1";
const char* password   = "password1";

const char* ntpServer = "pool.ntp.org";
const long  gmtOffset_sec = 3600;
const int   daylightOffset_sec = 3600;

byte wfConnectTry = 0;
byte loopCnt = 0;

void printLocalTime()
{
  struct tm timeinfo;
  if (!getLocalTime(&timeinfo)) {
    Serial.println("Failed to obtain time");
    return;
  }
  Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S");
}

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

  //connect to WiFi
  Serial.printf("Connecting to %s ", ssid);
  //WiFi.begin(ssid, password);
  wifiStart();
  //init and get the time
  configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
  if (WiFi.status() == WL_CONNECTED) {
    printLocalTime();
  }

}

void loop()
{
  delay(10000);
  printLocalTime();
  while (WiFi.status() != WL_CONNECTED || wfConnectTry >=5) {
    wfConnectTry++;
    wifiReconnect();

  }
  if (loopCnt >= 10){
    wifiReconnect();
  }
  loopCnt++;
}

void wifiReconnect()
{
  Serial.println(F("Disconnecting"));
  WiFi.disconnect(true);
  delay(500);
  Serial.println(F("Starting WiFi!"));
  wifiStart();
  loopCnt = 0;
}

void wifiStart()
{
  unsigned long timer1 = millis();
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED && millis() - timer1 < 5000UL) {
    delay(500);
    Serial.print(".");
  }
  if (WiFi.status() == WL_CONNECTED) {
    Serial.println(F(" CONNECTED"));
    wfConnectTry = 0;
  }
  else {
    Serial.println(F("Could not connect!"));
  }
}

....thanks for the code tip @tablatronix

tablatronix commented 6 years ago

Use code fences three ticks newline before amd after

gdombiak commented 6 years ago

Here is an interesting piece of information. I tried every trick mentioned in this thread and nothing worked. However, every time I install and run SimpleWiFiServer things get reset and then I can reinstall my app and things work again.

My app connects just fine to WiFi and at some point (days or weeks) it loses the connection and nothing can make it connect. I tried all the tricks on this thread and nada. As I said above, the only way I can make my ESP32 connect again to Wifi is by installing this other app to reset things. I wonder what it does that it makes my ESP32 work again with WiFi.

AIWIndustries commented 6 years ago

@gdombiak, do you have any debug information to show what the ESP32 is doing when it locks up? I had a recent issue where one of my sketches worked like a champ except when new day rolled over and there were two lines that put it into a continuous loop and the ESP finally just shit itself down till I reset or reloaded. Another issue I had was that I had another ESP that was up as a AP_STA and it kept trying to connect to it rather than the normal WiFI. Had to reload the other ESP and stipulate WiFi.mode(WIFI_STA) to fix that.

mickeypop commented 6 years ago

@AIWIndustries

Check out a post I put up at: https://github.com/espressif/arduino-esp32/issues/1100
Search for "SmartConfig / WiFi skeleton"

I wrote a complete skeleton that; saves, set with SmartConfig, deals with WiFi UP and DOWN, auto reconnects if Down.

It's a full structure and has always re-connected when WiFi went down or just disconnected for unknown reasons.

Take note in loop() for "// WiFi DOWN". I use a simple if()/else to track the WiFi status. Because of the espressif libraries, it takes about 30-40 seconds to report when the WiFi is down then starts looking to reconnect.

If the AP is power cycled it takes about 30 seconds for the AP to boot and another 15 seconds to reconnect but always reconnects.